Merge pull request #631 from kebby/master
[mono.git] / mcs / class / corlib / System / Console.cs
1 //
2 // System.Console.cs
3 //
4 // Author:
5 //      Dietmar Maurer (dietmar@ximian.com)
6 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 //
8 // (C) Ximian, Inc.  http://www.ximian.com
9 // (C) 2004,2005 Novell, Inc. (http://www.novell.com)
10 // Copyright 2013 Xamarin Inc. (http://www.xamarin.com)
11
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System.Diagnostics;
33 using System.IO;
34 using System.Runtime.CompilerServices;
35 using System.Runtime.InteropServices;
36 using System.Security;
37 using System.Security.Permissions;
38 using System.Text;
39
40 namespace System
41 {
42         public static partial class Console
43         {
44 #if !NET_2_1
45                 private class WindowsConsole
46                 {
47                         public static bool ctrlHandlerAdded = false;
48                         private delegate bool WindowsCancelHandler (int keyCode);
49                         private static WindowsCancelHandler cancelHandler = new WindowsCancelHandler (DoWindowsConsoleCancelEvent);
50
51                         [DllImport ("kernel32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
52                         private static extern int GetConsoleCP ();
53                         [DllImport ("kernel32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
54                         private static extern int GetConsoleOutputCP ();
55
56                         [DllImport ("kernel32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
57                         private static extern bool SetConsoleCtrlHandler (WindowsCancelHandler handler, bool addHandler);
58
59                         // Only call the event handler if Control-C was pressed (code == 0), nothing else
60                         private static bool DoWindowsConsoleCancelEvent (int keyCode)
61                         {
62                                 if (keyCode == 0)
63                                         DoConsoleCancelEvent ();
64                                 return keyCode == 0;
65                         }
66
67                         [MethodImpl (MethodImplOptions.NoInlining)]
68                         public static int GetInputCodePage ()
69                         {
70                                 return GetConsoleCP ();
71                         }
72
73                         [MethodImpl (MethodImplOptions.NoInlining)]
74                         public static int GetOutputCodePage ()
75                         {
76                                 return GetConsoleOutputCP ();
77                         }
78
79                         public static void AddCtrlHandler ()
80                         {
81                                 SetConsoleCtrlHandler (cancelHandler, true);
82                                 ctrlHandlerAdded = true;
83                         }
84                         
85                         public static void RemoveCtrlHandler ()
86                         {
87                                 SetConsoleCtrlHandler (cancelHandler, false);
88                                 ctrlHandlerAdded = false;
89                         }
90                 }
91 #endif
92
93                 internal static TextWriter stdout;
94                 private static TextWriter stderr;
95                 private static TextReader stdin;
96
97 #if NET_4_5 && !MOBILE
98                 static TextWriter console_stdout;
99                 static TextWriter console_stderr;
100                 static TextReader console_stdin;
101 #endif
102
103                 static Console ()
104                 {
105 #if NET_2_1
106                         Encoding inputEncoding;
107                         Encoding outputEncoding;
108 #endif
109
110                         if (Environment.IsRunningOnWindows) {
111                                 //
112                                 // On Windows, follow the Windows tradition
113                                 //
114 #if NET_2_1
115                                 // should never happen since Moonlight does not run on windows
116                                 inputEncoding = outputEncoding = Encoding.Default;
117 #else                   
118                                 try {
119                                         inputEncoding = Encoding.GetEncoding (WindowsConsole.GetInputCodePage ());
120                                         outputEncoding = Encoding.GetEncoding (WindowsConsole.GetOutputCodePage ());
121                                         // ArgumentException and NotSupportedException can be thrown as well
122                                 } catch {
123                                         // FIXME: I18N assemblies are not available when compiling mcs
124                                         // Use Latin 1 as it is fast and UTF-8 is never used as console code page
125                                         inputEncoding = outputEncoding = Encoding.Default;
126                                 }
127 #endif
128                         } else {
129                                 //
130                                 // On Unix systems (128), do not output the
131                                 // UTF-8 ZWNBSP (zero-width non-breaking space).
132                                 //
133                                 int code_page = 0;
134                                 Encoding.InternalCodePage (ref code_page);
135
136                                 if (code_page != -1 && ((code_page & 0x0fffffff) == 3 // UTF8Encoding.UTF8_CODE_PAGE
137                                         || ((code_page & 0x10000000) != 0)))
138                                         inputEncoding = outputEncoding = Encoding.UTF8Unmarked;
139                                 else
140                                         inputEncoding = outputEncoding = Encoding.Default;
141                         }
142
143                         SetupStreams (inputEncoding, outputEncoding);
144                 }
145
146                 static void SetupStreams (Encoding inputEncoding, Encoding outputEncoding)
147                 {
148 #if !NET_2_1
149                         if (!Environment.IsRunningOnWindows && ConsoleDriver.IsConsole) {
150                                 StreamWriter w = new CStreamWriter (OpenStandardOutput (0), outputEncoding);
151                                 w.AutoFlush = true;
152                                 stdout = TextWriter.Synchronized (w, true);
153
154                                 w = new CStreamWriter (OpenStandardOutput (0), outputEncoding);
155                                 w.AutoFlush = true;
156                                 stderr = TextWriter.Synchronized (w, true);
157                                 
158                                 stdin = new CStreamReader (OpenStandardInput (0), inputEncoding);
159                         } else {
160 #endif
161 // FULL_AOT_RUNTIME is used (instead of MONOTOUCH) since we only want this code when running on 
162 // iOS (simulator or devices) and *not* when running tools (e.g. btouch #12179) that needs to use 
163 // the mscorlib.dll shipped with Xamarin.iOS
164 #if FULL_AOT_RUNTIME
165                                 stdout = new NSLogWriter ();
166 #else
167                                 stdout = new UnexceptionalStreamWriter (OpenStandardOutput (0), outputEncoding);
168                                 ((StreamWriter)stdout).AutoFlush = true;
169 #endif
170                                 stdout = TextWriter.Synchronized (stdout, true);
171
172 #if FULL_AOT_RUNTIME
173                                 stderr = new NSLogWriter ();
174 #else
175                                 stderr = new UnexceptionalStreamWriter (OpenStandardError (0), outputEncoding); 
176                                 ((StreamWriter)stderr).AutoFlush = true;
177 #endif
178                                 stderr = TextWriter.Synchronized (stderr, true);
179
180                                 stdin = new UnexceptionalStreamReader (OpenStandardInput (0), inputEncoding);
181                                 stdin = TextReader.Synchronized (stdin);
182 #if !NET_2_1
183                         }
184 #endif
185
186 #if NET_4_5 && !MOBILE
187                         console_stderr = stderr;
188                         console_stdout = stdout;
189                         console_stdin = stdin;
190 #endif
191
192 #if MONODROID
193                         if (LogcatTextWriter.IsRunningOnAndroid ()) {
194                                 stdout = TextWriter.Synchronized (new LogcatTextWriter ("mono-stdout", stdout));
195                                 stderr = TextWriter.Synchronized (new LogcatTextWriter ("mono-stderr", stderr));
196                         }
197 #endif  // MONODROID
198
199                         GC.SuppressFinalize (stdout);
200                         GC.SuppressFinalize (stderr);
201                         GC.SuppressFinalize (stdin);
202                 }
203
204                 public static TextWriter Error {
205                         get {
206                                 return stderr;
207                         }
208                 }
209
210                 public static TextWriter Out {
211                         get {
212                                 return stdout;
213                         }
214                 }
215
216                 public static TextReader In {
217                         get {
218                                 return stdin;
219                         }
220                 }
221
222                 private static Stream Open (IntPtr handle, FileAccess access, int bufferSize)
223                 {
224                         try {
225                                 return new FileStream (handle, access, false, bufferSize, false, bufferSize == 0);
226                         } catch (IOException) {
227                                 return new NullStream ();
228                         }
229                 }
230
231                 public static Stream OpenStandardError ()
232                 {
233                         return OpenStandardError (0);
234                 }
235
236                 // calling any FileStream constructor with a handle normally
237                 // requires permissions UnmanagedCode permissions. In this 
238                 // case we assert this permission so the console can be used
239                 // in partial trust (i.e. without having UnmanagedCode).
240                 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
241                 public static Stream OpenStandardError (int bufferSize)
242                 {
243                         return Open (MonoIO.ConsoleError, FileAccess.Write, bufferSize);
244                 }
245
246                 public static Stream OpenStandardInput ()
247                 {
248                         return OpenStandardInput (0);
249                 }
250
251                 // calling any FileStream constructor with a handle normally
252                 // requires permissions UnmanagedCode permissions. In this 
253                 // case we assert this permission so the console can be used
254                 // in partial trust (i.e. without having UnmanagedCode).
255                 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
256                 public static Stream OpenStandardInput (int bufferSize)
257                 {
258                         return Open (MonoIO.ConsoleInput, FileAccess.Read, bufferSize);
259                 }
260
261                 public static Stream OpenStandardOutput ()
262                 {
263                         return OpenStandardOutput (0);
264                 }
265
266                 // calling any FileStream constructor with a handle normally
267                 // requires permissions UnmanagedCode permissions. In this 
268                 // case we assert this permission so the console can be used
269                 // in partial trust (i.e. without having UnmanagedCode).
270                 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
271                 public static Stream OpenStandardOutput (int bufferSize)
272                 {
273                         return Open (MonoIO.ConsoleOutput, FileAccess.Write, bufferSize);
274                 }
275
276                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
277                 public static void SetError (TextWriter newError)
278                 {
279                         if (newError == null)
280                                 throw new ArgumentNullException ("newError");
281
282                         stderr = newError;
283                 }
284
285                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
286                 public static void SetIn (TextReader newIn)
287                 {
288                         if (newIn == null)
289                                 throw new ArgumentNullException ("newIn");
290
291                         stdin = newIn;
292                 }
293
294                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
295                 public static void SetOut (TextWriter newOut)
296                 {
297                         if (newOut == null)
298                                 throw new ArgumentNullException ("newOut");
299
300                         stdout = newOut;
301                 }
302
303                 public static void Write (bool value)
304                 {
305                         stdout.Write (value);
306                 }
307
308                 public static void Write (char value)
309                 {
310                         stdout.Write (value);
311                 }
312
313                 public static void Write (char[] buffer)
314                 {
315                         stdout.Write (buffer);
316                 }
317
318                 public static void Write (decimal value)
319                 {
320                         stdout.Write (value);
321                 }
322                 
323                 public static void Write (double value)
324                 {
325                         stdout.Write (value);
326                 }
327
328                 public static void Write (int value)
329                 {
330                         stdout.Write (value);
331                 }
332
333                 public static void Write (long value)
334                 {
335                         stdout.Write (value);
336                 }
337
338                 public static void Write (object value)
339                 {
340                         stdout.Write (value);
341                 }
342
343                 public static void Write (float value)
344                 {
345                         stdout.Write (value);
346                 }
347
348                 public static void Write (string value)
349                 {
350                         stdout.Write (value);
351                 }
352
353                 [CLSCompliant (false)]
354                 public static void Write (uint value)
355                 {
356                         stdout.Write (value);
357                 }
358
359                 [CLSCompliant (false)]
360                 public static void Write (ulong value)
361                 {
362                         stdout.Write (value);
363                 }
364
365                 public static void Write (string format, object arg0)
366                 {
367                         stdout.Write (format, arg0);
368                 }
369
370                 public static void Write (string format, params object[] arg)
371                 {
372                         if (arg == null)
373                                 stdout.Write (format);
374                         else
375                                 stdout.Write (format, arg);
376                 }
377
378                 public static void Write (char[] buffer, int index, int count)
379                 {
380                         stdout.Write (buffer, index, count);
381                 }
382
383                 public static void Write (string format, object arg0, object arg1)
384                 {
385                         stdout.Write (format, arg0, arg1);
386                 }
387
388                 public static void Write (string format, object arg0, object arg1, object arg2 )
389                 {
390                         stdout.Write (format, arg0, arg1, arg2);
391                 }
392
393                 [CLSCompliant (false)]
394                 public static void Write (string format, object arg0, object arg1, object arg2, object arg3, __arglist)
395                 {
396                         ArgIterator iter = new ArgIterator (__arglist);
397                         int argCount = iter.GetRemainingCount();
398
399                         object[] args = new object [argCount + 4];
400                         args [0] = arg0;
401                         args [1] = arg1;
402                         args [2] = arg2;
403                         args [3] = arg3;
404                         for (int i = 0; i < argCount; i++) {
405                                 TypedReference typedRef = iter.GetNextArg ();
406                                 args [i + 4] = TypedReference.ToObject (typedRef);
407                         }
408
409                         stdout.Write (String.Format (format, args));
410                 }
411
412                 public static void WriteLine ()
413                 {
414                         stdout.WriteLine ();
415                 }
416
417                 public static void WriteLine (bool value)
418                 {
419                         stdout.WriteLine (value);
420                 }
421
422                 public static void WriteLine (char value)
423                 {
424                         stdout.WriteLine (value);
425                 }
426
427                 public static void WriteLine (char[] buffer)
428                 {
429                         stdout.WriteLine (buffer);
430                 }
431
432                 public static void WriteLine (decimal value)
433                 {
434                         stdout.WriteLine (value);
435                 }
436
437                 public static void WriteLine (double value)
438                 {
439                         stdout.WriteLine (value);
440                 }
441
442                 public static void WriteLine (int value)
443                 {
444                         stdout.WriteLine (value);
445                 }
446
447                 public static void WriteLine (long value)
448                 {
449                         stdout.WriteLine (value);
450                 }
451
452                 public static void WriteLine (object value)
453                 {
454                         stdout.WriteLine (value);
455                 }
456
457                 public static void WriteLine (float value)
458                 {
459                         stdout.WriteLine (value);
460                 }
461
462                 public static void WriteLine (string value)
463                 {
464                         stdout.WriteLine (value);
465                 }
466
467                 [CLSCompliant (false)]
468                 public static void WriteLine (uint value)
469                 {
470                         stdout.WriteLine (value);
471                 }
472
473                 [CLSCompliant (false)]
474                 public static void WriteLine (ulong value)
475                 {
476                         stdout.WriteLine (value);
477                 }
478
479                 public static void WriteLine (string format, object arg0)
480                 {
481                         stdout.WriteLine (format, arg0);
482                 }
483
484                 public static void WriteLine (string format, params object[] arg)
485                 {
486                         if (arg == null)
487                                 stdout.WriteLine (format);
488                         else
489                                 stdout.WriteLine (format, arg);
490                 }
491
492                 public static void WriteLine (char[] buffer, int index, int count)
493                 {
494                         stdout.WriteLine (buffer, index, count);
495                 }
496
497                 public static void WriteLine (string format, object arg0, object arg1)
498                 {
499                         stdout.WriteLine (format, arg0, arg1);
500                 }
501
502                 public static void WriteLine (string format, object arg0, object arg1, object arg2)
503                 {
504                         stdout.WriteLine (format, arg0, arg1, arg2);
505                 }
506
507                 [CLSCompliant (false)]
508                 public static void WriteLine (string format, object arg0, object arg1, object arg2, object arg3, __arglist)
509                 {
510                         ArgIterator iter = new ArgIterator (__arglist);
511                         int argCount = iter.GetRemainingCount();
512
513                         object[] args = new object [argCount + 4];
514                         args [0] = arg0;
515                         args [1] = arg1;
516                         args [2] = arg2;
517                         args [3] = arg3;
518                         for (int i = 0; i < argCount; i++) {
519                                 TypedReference typedRef = iter.GetNextArg ();
520                                 args [i + 4] = TypedReference.ToObject (typedRef);
521                         }
522
523                         stdout.WriteLine (String.Format (format, args));
524                 }
525
526 #if !NET_2_1
527                 public static int Read ()
528                 {
529                         if ((stdin is CStreamReader) && ConsoleDriver.IsConsole) {
530                                 return ConsoleDriver.Read ();
531                         } else {
532                                 return stdin.Read ();
533                         }
534                 }
535
536                 public static string ReadLine ()
537                 {
538                         if ((stdin is CStreamReader) && ConsoleDriver.IsConsole) {
539                                 return ConsoleDriver.ReadLine ();
540                         } else {
541                                 return stdin.ReadLine ();
542                         }
543                 }
544 #else
545                 public static int Read ()
546                 {
547                         return stdin.Read ();
548                 }
549
550                 public static string ReadLine ()
551                 {
552                         return stdin.ReadLine ();
553                 }
554
555 #endif
556
557 #if !NET_2_1
558                 // FIXME: Console should use these encodings when changed
559                 static Encoding inputEncoding;
560                 static Encoding outputEncoding;
561
562                 public static Encoding InputEncoding {
563                         get { return inputEncoding; }
564                         set {
565                                 inputEncoding = value;
566                                 SetupStreams (inputEncoding, outputEncoding);
567                         }
568                 }
569
570                 public static Encoding OutputEncoding {
571                         get { return outputEncoding; }
572                         set {
573                                 outputEncoding = value;
574                                 SetupStreams (inputEncoding, outputEncoding);
575                         }
576                 }
577
578                 public static ConsoleColor BackgroundColor {
579                         get { return ConsoleDriver.BackgroundColor; }
580                         set { ConsoleDriver.BackgroundColor = value; }
581                 }
582
583                 public static int BufferHeight {
584                         get { return ConsoleDriver.BufferHeight; }
585                         [MonoLimitation ("Implemented only on Windows")]
586                         set { ConsoleDriver.BufferHeight = value; }
587                 }
588
589                 public static int BufferWidth {
590                         get { return ConsoleDriver.BufferWidth; }
591                         [MonoLimitation ("Implemented only on Windows")]
592                         set { ConsoleDriver.BufferWidth = value; }
593                 }
594
595                 [MonoLimitation ("Implemented only on Windows")]
596                 public static bool CapsLock {
597                         get { return ConsoleDriver.CapsLock; }
598                 }
599
600                 public static int CursorLeft {
601                         get { return ConsoleDriver.CursorLeft; }
602                         set { ConsoleDriver.CursorLeft = value; }
603                 }
604
605                 public static int CursorTop {
606                         get { return ConsoleDriver.CursorTop; }
607                         set { ConsoleDriver.CursorTop = value; }
608                 }
609
610                 public static int CursorSize {
611                         get { return ConsoleDriver.CursorSize; }
612                         set { ConsoleDriver.CursorSize = value; }
613                 }
614
615                 public static bool CursorVisible {
616                         get { return ConsoleDriver.CursorVisible; }
617                         set { ConsoleDriver.CursorVisible = value; }
618                 }
619
620                 public static ConsoleColor ForegroundColor {
621                         get { return ConsoleDriver.ForegroundColor; }
622                         set { ConsoleDriver.ForegroundColor = value; }
623                 }
624
625                 public static bool KeyAvailable {
626                         get { return ConsoleDriver.KeyAvailable; }
627                 }
628
629                 public static int LargestWindowHeight {
630                         get { return ConsoleDriver.LargestWindowHeight; }
631                 }
632
633                 public static int LargestWindowWidth {
634                         get { return ConsoleDriver.LargestWindowWidth; }
635                 }
636
637                 [MonoLimitation ("Only works on windows")]
638                 public static bool NumberLock {
639                         get { return ConsoleDriver.NumberLock; }
640                 }
641
642                 public static string Title {
643                         get { return ConsoleDriver.Title; }
644                         set { ConsoleDriver.Title = value; }
645                 }
646
647                 public static bool TreatControlCAsInput {
648                         get { return ConsoleDriver.TreatControlCAsInput; }
649                         set { ConsoleDriver.TreatControlCAsInput = value; }
650                 }
651
652                 [MonoLimitation ("Only works on windows")]
653                 public static int WindowHeight {
654                         get { return ConsoleDriver.WindowHeight; }
655                         set { ConsoleDriver.WindowHeight = value; }
656                 }
657
658                 [MonoLimitation ("Only works on windows")]
659                 public static int WindowLeft {
660                         get { return ConsoleDriver.WindowLeft; }
661                         set { ConsoleDriver.WindowLeft = value; }
662                 }
663
664                 [MonoLimitation ("Only works on windows")]
665                 public static int WindowTop {
666                         get { return ConsoleDriver.WindowTop; }
667                         set { ConsoleDriver.WindowTop = value; }
668                 }
669
670                 [MonoLimitation ("Only works on windows")]
671                 public static int WindowWidth {
672                         get { return ConsoleDriver.WindowWidth; }
673                         set { ConsoleDriver.WindowWidth = value; }
674                 }
675
676 #if NET_4_5
677                 public static bool IsErrorRedirected {
678                         get {
679                                 return stderr != console_stderr || ConsoleDriver.IsErrorRedirected;
680                         }
681                 }
682
683                 public static bool IsOutputRedirected {
684                         get {
685                                 return stdout != console_stdout || ConsoleDriver.IsOutputRedirected;
686                         }
687                 }
688
689                 public static bool IsInputRedirected {
690                         get {
691                                 return stdin != console_stdin || ConsoleDriver.IsInputRedirected;
692                         }
693                 }
694 #endif
695
696                 public static void Beep ()
697                 {
698                         Beep (1000, 500);
699                 }
700
701                 public static void Beep (int frequency, int duration)
702                 {
703                         if (frequency < 37 || frequency > 32767)
704                                 throw new ArgumentOutOfRangeException ("frequency");
705
706                         if (duration <= 0)
707                                 throw new ArgumentOutOfRangeException ("duration");
708
709                         ConsoleDriver.Beep (frequency, duration);
710                 }
711
712                 public static void Clear ()
713                 {
714                         ConsoleDriver.Clear ();
715                 }
716
717                 [MonoLimitation ("Implemented only on Windows")]
718                 public static void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight,
719                                                 int targetLeft, int targetTop)
720                 {
721                         ConsoleDriver.MoveBufferArea (sourceLeft, sourceTop, sourceWidth, sourceHeight, targetLeft, targetTop);
722                 }
723
724                 [MonoLimitation ("Implemented only on Windows")]
725                 public static void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight,
726                                                 int targetLeft, int targetTop, Char sourceChar,
727                                                 ConsoleColor sourceForeColor, ConsoleColor sourceBackColor)
728                 {
729                         ConsoleDriver.MoveBufferArea (sourceLeft, sourceTop, sourceWidth, sourceHeight, targetLeft, targetTop,
730                                                         sourceChar, sourceForeColor, sourceBackColor);
731                 }
732
733                 public static ConsoleKeyInfo ReadKey ()
734                 {
735                         return ReadKey (false);
736                 }
737
738                 public static ConsoleKeyInfo ReadKey (bool intercept)
739                 {
740                         return ConsoleDriver.ReadKey (intercept);
741                 }
742
743                 public static void ResetColor ()
744                 {
745                         ConsoleDriver.ResetColor ();
746                 }
747
748                 [MonoLimitation ("Only works on windows")]
749                 public static void SetBufferSize (int width, int height)
750                 {
751                         ConsoleDriver.SetBufferSize (width, height);
752                 }
753
754                 public static void SetCursorPosition (int left, int top)
755                 {
756                         ConsoleDriver.SetCursorPosition (left, top);
757                 }
758
759                 public static void SetWindowPosition (int left, int top)
760                 {
761                         ConsoleDriver.SetWindowPosition (left, top);
762                 }
763
764                 public static void SetWindowSize (int width, int height)
765                 {
766                         ConsoleDriver.SetWindowSize (width, height);
767                 }
768
769                 static ConsoleCancelEventHandler cancel_event;
770                 public static event ConsoleCancelEventHandler CancelKeyPress {
771                         add {
772                                 if (ConsoleDriver.Initialized == false)
773                                         ConsoleDriver.Init ();
774
775                                 cancel_event += value;
776
777                                 if (Environment.IsRunningOnWindows && !WindowsConsole.ctrlHandlerAdded)
778                                         WindowsConsole.AddCtrlHandler();
779                         }
780                         remove {
781                                 if (ConsoleDriver.Initialized == false)
782                                         ConsoleDriver.Init ();
783
784                                 cancel_event -= value;
785
786                                 if (cancel_event == null && Environment.IsRunningOnWindows)
787                                 {
788                                         // Need to remove our hook if there's nothing left in the event
789                                         if (WindowsConsole.ctrlHandlerAdded)
790                                                 WindowsConsole.RemoveCtrlHandler();
791                                 }
792                         }
793                 }
794
795                 delegate void InternalCancelHandler ();
796                 
797 #pragma warning disable 414
798                 //
799                 // Used by console-io.c
800                 //
801                 static readonly InternalCancelHandler cancel_handler = new InternalCancelHandler (DoConsoleCancelEvent);
802 #pragma warning restore 414             
803
804                 internal static void DoConsoleCancelEvent ()
805                 {
806                         bool exit = true;
807                         if (cancel_event != null) {
808                                 ConsoleCancelEventArgs args = new ConsoleCancelEventArgs (ConsoleSpecialKey.ControlC);
809                                 Delegate [] delegates = cancel_event.GetInvocationList ();
810                                 foreach (ConsoleCancelEventHandler d in delegates){
811                                         try {
812                                                 // Sender is always null here.
813                                                 d (null, args);
814                                         } catch {} // Ignore any exception.
815                                 }
816                                 exit = !args.Cancel;
817                         }
818
819                         if (exit)
820                                 Environment.Exit (58);
821                 }
822 #endif
823         }
824 }
825