Merge pull request #704 from jgagnon/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                 static Console ()
98                 {
99 #if NET_2_1
100                         Encoding inputEncoding;
101                         Encoding outputEncoding;
102 #endif
103
104                         if (Environment.IsRunningOnWindows) {
105                                 //
106                                 // On Windows, follow the Windows tradition
107                                 //
108 #if NET_2_1
109                                 // should never happen since Moonlight does not run on windows
110                                 inputEncoding = outputEncoding = Encoding.Default;
111 #else                   
112                                 try {
113                                         inputEncoding = Encoding.GetEncoding (WindowsConsole.GetInputCodePage ());
114                                         outputEncoding = Encoding.GetEncoding (WindowsConsole.GetOutputCodePage ());
115                                         // ArgumentException and NotSupportedException can be thrown as well
116                                 } catch {
117                                         // FIXME: I18N assemblies are not available when compiling mcs
118                                         // Use Latin 1 as it is fast and UTF-8 is never used as console code page
119                                         inputEncoding = outputEncoding = Encoding.Default;
120                                 }
121 #endif
122                         } else {
123                                 //
124                                 // On Unix systems (128), do not output the
125                                 // UTF-8 ZWNBSP (zero-width non-breaking space).
126                                 //
127                                 int code_page = 0;
128                                 EncodingHelper.InternalCodePage (ref code_page);
129
130                                 if (code_page != -1 && ((code_page & 0x0fffffff) == 3 // UTF8Encoding.UTF8_CODE_PAGE
131                                         || ((code_page & 0x10000000) != 0)))
132                                         inputEncoding = outputEncoding = EncodingHelper.UTF8Unmarked;
133                                 else
134                                         inputEncoding = outputEncoding = Encoding.Default;
135                         }
136
137                         SetupStreams (inputEncoding, outputEncoding);
138                 }
139
140                 static void SetupStreams (Encoding inputEncoding, Encoding outputEncoding)
141                 {
142 #if !NET_2_1
143                         if (!Environment.IsRunningOnWindows && ConsoleDriver.IsConsole) {
144                                 StreamWriter w = new CStreamWriter (OpenStandardOutput (0), outputEncoding, true);
145                                 w.AutoFlush = true;
146                                 stdout = TextWriter.Synchronized (w);
147
148                                 w = new CStreamWriter (OpenStandardOutput (0), outputEncoding, true);
149                                 w.AutoFlush = true;
150                                 stderr = TextWriter.Synchronized (w);
151                                 
152                                 stdin = new CStreamReader (OpenStandardInput (0), inputEncoding);
153                         } else {
154 #endif
155 // FULL_AOT_RUNTIME is used (instead of MONOTOUCH) since we only want this code when running on 
156 // iOS (simulator or devices) and *not* when running tools (e.g. btouch #12179) that needs to use 
157 // the mscorlib.dll shipped with Xamarin.iOS
158 #if MONOTOUCH && FULL_AOT_RUNTIME
159                                 stdout = new NSLogWriter ();
160 #else
161                                 stdout = new UnexceptionalStreamWriter (OpenStandardOutput (0), outputEncoding);
162                                 ((StreamWriter)stdout).AutoFlush = true;
163 #endif
164                                 stdout = TextWriter.Synchronized (stdout);
165
166 #if MONOTOUCH && FULL_AOT_RUNTIME
167                                 stderr = new NSLogWriter ();
168 #else
169                                 stderr = new UnexceptionalStreamWriter (OpenStandardError (0), outputEncoding); 
170                                 ((StreamWriter)stderr).AutoFlush = true;
171 #endif
172                                 stderr = TextWriter.Synchronized (stderr);
173
174                                 stdin = new UnexceptionalStreamReader (OpenStandardInput (0), inputEncoding);
175                                 stdin = TextReader.Synchronized (stdin);
176 #if !NET_2_1
177                         }
178 #endif
179
180 #if MONODROID
181                         if (LogcatTextWriter.IsRunningOnAndroid ()) {
182                                 stdout = TextWriter.Synchronized (new LogcatTextWriter ("mono-stdout", stdout));
183                                 stderr = TextWriter.Synchronized (new LogcatTextWriter ("mono-stderr", stderr));
184                         }
185 #endif  // MONODROID
186
187                         GC.SuppressFinalize (stdout);
188                         GC.SuppressFinalize (stderr);
189                         GC.SuppressFinalize (stdin);
190                 }
191
192                 public static TextWriter Error {
193                         get {
194                                 return stderr;
195                         }
196                 }
197
198                 public static TextWriter Out {
199                         get {
200                                 return stdout;
201                         }
202                 }
203
204                 public static TextReader In {
205                         get {
206                                 return stdin;
207                         }
208                 }
209
210                 private static Stream Open (IntPtr handle, FileAccess access, int bufferSize)
211                 {
212                         try {
213                                 // TODO: Should use __ConsoleStream from reference sources
214                                 return new FileStream (handle, access, false, bufferSize, false, true);
215                         } catch (IOException) {
216                                 return Stream.Null;
217                         }
218                 }
219
220                 public static Stream OpenStandardError ()
221                 {
222                         return OpenStandardError (0);
223                 }
224
225                 // calling any FileStream constructor with a handle normally
226                 // requires permissions UnmanagedCode permissions. In this 
227                 // case we assert this permission so the console can be used
228                 // in partial trust (i.e. without having UnmanagedCode).
229                 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
230                 public static Stream OpenStandardError (int bufferSize)
231                 {
232                         return Open (MonoIO.ConsoleError, FileAccess.Write, bufferSize);
233                 }
234
235                 public static Stream OpenStandardInput ()
236                 {
237                         return OpenStandardInput (0);
238                 }
239
240                 // calling any FileStream constructor with a handle normally
241                 // requires permissions UnmanagedCode permissions. In this 
242                 // case we assert this permission so the console can be used
243                 // in partial trust (i.e. without having UnmanagedCode).
244                 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
245                 public static Stream OpenStandardInput (int bufferSize)
246                 {
247                         return Open (MonoIO.ConsoleInput, FileAccess.Read, bufferSize);
248                 }
249
250                 public static Stream OpenStandardOutput ()
251                 {
252                         return OpenStandardOutput (0);
253                 }
254
255                 // calling any FileStream constructor with a handle normally
256                 // requires permissions UnmanagedCode permissions. In this 
257                 // case we assert this permission so the console can be used
258                 // in partial trust (i.e. without having UnmanagedCode).
259                 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
260                 public static Stream OpenStandardOutput (int bufferSize)
261                 {
262                         return Open (MonoIO.ConsoleOutput, FileAccess.Write, bufferSize);
263                 }
264
265                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
266                 public static void SetError (TextWriter newError)
267                 {
268                         if (newError == null)
269                                 throw new ArgumentNullException ("newError");
270
271                         stderr = newError;
272                 }
273
274                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
275                 public static void SetIn (TextReader newIn)
276                 {
277                         if (newIn == null)
278                                 throw new ArgumentNullException ("newIn");
279
280                         stdin = newIn;
281                 }
282
283                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
284                 public static void SetOut (TextWriter newOut)
285                 {
286                         if (newOut == null)
287                                 throw new ArgumentNullException ("newOut");
288
289                         stdout = newOut;
290                 }
291
292                 public static void Write (bool value)
293                 {
294                         stdout.Write (value);
295                 }
296
297                 public static void Write (char value)
298                 {
299                         stdout.Write (value);
300                 }
301
302                 public static void Write (char[] buffer)
303                 {
304                         stdout.Write (buffer);
305                 }
306
307                 public static void Write (decimal value)
308                 {
309                         stdout.Write (value);
310                 }
311                 
312                 public static void Write (double value)
313                 {
314                         stdout.Write (value);
315                 }
316
317                 public static void Write (int value)
318                 {
319                         stdout.Write (value);
320                 }
321
322                 public static void Write (long value)
323                 {
324                         stdout.Write (value);
325                 }
326
327                 public static void Write (object value)
328                 {
329                         stdout.Write (value);
330                 }
331
332                 public static void Write (float value)
333                 {
334                         stdout.Write (value);
335                 }
336
337                 public static void Write (string value)
338                 {
339                         stdout.Write (value);
340                 }
341
342                 [CLSCompliant (false)]
343                 public static void Write (uint value)
344                 {
345                         stdout.Write (value);
346                 }
347
348                 [CLSCompliant (false)]
349                 public static void Write (ulong value)
350                 {
351                         stdout.Write (value);
352                 }
353
354                 public static void Write (string format, object arg0)
355                 {
356                         stdout.Write (format, arg0);
357                 }
358
359                 public static void Write (string format, params object[] arg)
360                 {
361                         if (arg == null)
362                                 stdout.Write (format);
363                         else
364                                 stdout.Write (format, arg);
365                 }
366
367                 public static void Write (char[] buffer, int index, int count)
368                 {
369                         stdout.Write (buffer, index, count);
370                 }
371
372                 public static void Write (string format, object arg0, object arg1)
373                 {
374                         stdout.Write (format, arg0, arg1);
375                 }
376
377                 public static void Write (string format, object arg0, object arg1, object arg2 )
378                 {
379                         stdout.Write (format, arg0, arg1, arg2);
380                 }
381
382                 [CLSCompliant (false)]
383                 public static void Write (string format, object arg0, object arg1, object arg2, object arg3, __arglist)
384                 {
385                         ArgIterator iter = new ArgIterator (__arglist);
386                         int argCount = iter.GetRemainingCount();
387
388                         object[] args = new object [argCount + 4];
389                         args [0] = arg0;
390                         args [1] = arg1;
391                         args [2] = arg2;
392                         args [3] = arg3;
393                         for (int i = 0; i < argCount; i++) {
394                                 TypedReference typedRef = iter.GetNextArg ();
395                                 args [i + 4] = TypedReference.ToObject (typedRef);
396                         }
397
398                         stdout.Write (String.Format (format, args));
399                 }
400
401                 public static void WriteLine ()
402                 {
403                         stdout.WriteLine ();
404                 }
405
406                 public static void WriteLine (bool value)
407                 {
408                         stdout.WriteLine (value);
409                 }
410
411                 public static void WriteLine (char value)
412                 {
413                         stdout.WriteLine (value);
414                 }
415
416                 public static void WriteLine (char[] buffer)
417                 {
418                         stdout.WriteLine (buffer);
419                 }
420
421                 public static void WriteLine (decimal value)
422                 {
423                         stdout.WriteLine (value);
424                 }
425
426                 public static void WriteLine (double value)
427                 {
428                         stdout.WriteLine (value);
429                 }
430
431                 public static void WriteLine (int value)
432                 {
433                         stdout.WriteLine (value);
434                 }
435
436                 public static void WriteLine (long value)
437                 {
438                         stdout.WriteLine (value);
439                 }
440
441                 public static void WriteLine (object value)
442                 {
443                         stdout.WriteLine (value);
444                 }
445
446                 public static void WriteLine (float value)
447                 {
448                         stdout.WriteLine (value);
449                 }
450
451                 public static void WriteLine (string value)
452                 {
453                         stdout.WriteLine (value);
454                 }
455
456                 [CLSCompliant (false)]
457                 public static void WriteLine (uint value)
458                 {
459                         stdout.WriteLine (value);
460                 }
461
462                 [CLSCompliant (false)]
463                 public static void WriteLine (ulong value)
464                 {
465                         stdout.WriteLine (value);
466                 }
467
468                 public static void WriteLine (string format, object arg0)
469                 {
470                         stdout.WriteLine (format, arg0);
471                 }
472
473                 public static void WriteLine (string format, params object[] arg)
474                 {
475                         if (arg == null)
476                                 stdout.WriteLine (format);
477                         else
478                                 stdout.WriteLine (format, arg);
479                 }
480
481                 public static void WriteLine (char[] buffer, int index, int count)
482                 {
483                         stdout.WriteLine (buffer, index, count);
484                 }
485
486                 public static void WriteLine (string format, object arg0, object arg1)
487                 {
488                         stdout.WriteLine (format, arg0, arg1);
489                 }
490
491                 public static void WriteLine (string format, object arg0, object arg1, object arg2)
492                 {
493                         stdout.WriteLine (format, arg0, arg1, arg2);
494                 }
495
496                 [CLSCompliant (false)]
497                 public static void WriteLine (string format, object arg0, object arg1, object arg2, object arg3, __arglist)
498                 {
499                         ArgIterator iter = new ArgIterator (__arglist);
500                         int argCount = iter.GetRemainingCount();
501
502                         object[] args = new object [argCount + 4];
503                         args [0] = arg0;
504                         args [1] = arg1;
505                         args [2] = arg2;
506                         args [3] = arg3;
507                         for (int i = 0; i < argCount; i++) {
508                                 TypedReference typedRef = iter.GetNextArg ();
509                                 args [i + 4] = TypedReference.ToObject (typedRef);
510                         }
511
512                         stdout.WriteLine (String.Format (format, args));
513                 }
514
515 #if !NET_2_1
516                 public static int Read ()
517                 {
518                         if ((stdin is CStreamReader) && ConsoleDriver.IsConsole) {
519                                 return ConsoleDriver.Read ();
520                         } else {
521                                 return stdin.Read ();
522                         }
523                 }
524
525                 public static string ReadLine ()
526                 {
527                         if ((stdin is CStreamReader) && ConsoleDriver.IsConsole) {
528                                 return ConsoleDriver.ReadLine ();
529                         } else {
530                                 return stdin.ReadLine ();
531                         }
532                 }
533 #else
534                 public static int Read ()
535                 {
536                         return stdin.Read ();
537                 }
538
539                 public static string ReadLine ()
540                 {
541                         return stdin.ReadLine ();
542                 }
543
544 #endif
545
546 #if !NET_2_1
547                 // FIXME: Console should use these encodings when changed
548                 static Encoding inputEncoding;
549                 static Encoding outputEncoding;
550
551                 public static Encoding InputEncoding {
552                         get { return inputEncoding; }
553                         set {
554                                 inputEncoding = value;
555                                 SetupStreams (inputEncoding, outputEncoding);
556                         }
557                 }
558
559                 public static Encoding OutputEncoding {
560                         get { return outputEncoding; }
561                         set {
562                                 outputEncoding = value;
563                                 SetupStreams (inputEncoding, outputEncoding);
564                         }
565                 }
566
567                 public static ConsoleColor BackgroundColor {
568                         get { return ConsoleDriver.BackgroundColor; }
569                         set { ConsoleDriver.BackgroundColor = value; }
570                 }
571
572                 public static int BufferHeight {
573                         get { return ConsoleDriver.BufferHeight; }
574                         [MonoLimitation ("Implemented only on Windows")]
575                         set { ConsoleDriver.BufferHeight = value; }
576                 }
577
578                 public static int BufferWidth {
579                         get { return ConsoleDriver.BufferWidth; }
580                         [MonoLimitation ("Implemented only on Windows")]
581                         set { ConsoleDriver.BufferWidth = value; }
582                 }
583
584                 [MonoLimitation ("Implemented only on Windows")]
585                 public static bool CapsLock {
586                         get { return ConsoleDriver.CapsLock; }
587                 }
588
589                 public static int CursorLeft {
590                         get { return ConsoleDriver.CursorLeft; }
591                         set { ConsoleDriver.CursorLeft = value; }
592                 }
593
594                 public static int CursorTop {
595                         get { return ConsoleDriver.CursorTop; }
596                         set { ConsoleDriver.CursorTop = value; }
597                 }
598
599                 public static int CursorSize {
600                         get { return ConsoleDriver.CursorSize; }
601                         set { ConsoleDriver.CursorSize = value; }
602                 }
603
604                 public static bool CursorVisible {
605                         get { return ConsoleDriver.CursorVisible; }
606                         set { ConsoleDriver.CursorVisible = value; }
607                 }
608
609                 public static ConsoleColor ForegroundColor {
610                         get { return ConsoleDriver.ForegroundColor; }
611                         set { ConsoleDriver.ForegroundColor = value; }
612                 }
613
614                 public static bool KeyAvailable {
615                         get { return ConsoleDriver.KeyAvailable; }
616                 }
617
618                 public static int LargestWindowHeight {
619                         get { return ConsoleDriver.LargestWindowHeight; }
620                 }
621
622                 public static int LargestWindowWidth {
623                         get { return ConsoleDriver.LargestWindowWidth; }
624                 }
625
626                 [MonoLimitation ("Only works on windows")]
627                 public static bool NumberLock {
628                         get { return ConsoleDriver.NumberLock; }
629                 }
630
631                 public static string Title {
632                         get { return ConsoleDriver.Title; }
633                         set { ConsoleDriver.Title = value; }
634                 }
635
636                 public static bool TreatControlCAsInput {
637                         get { return ConsoleDriver.TreatControlCAsInput; }
638                         set { ConsoleDriver.TreatControlCAsInput = value; }
639                 }
640
641                 [MonoLimitation ("Only works on windows")]
642                 public static int WindowHeight {
643                         get { return ConsoleDriver.WindowHeight; }
644                         set { ConsoleDriver.WindowHeight = value; }
645                 }
646
647                 [MonoLimitation ("Only works on windows")]
648                 public static int WindowLeft {
649                         get { return ConsoleDriver.WindowLeft; }
650                         set { ConsoleDriver.WindowLeft = value; }
651                 }
652
653                 [MonoLimitation ("Only works on windows")]
654                 public static int WindowTop {
655                         get { return ConsoleDriver.WindowTop; }
656                         set { ConsoleDriver.WindowTop = value; }
657                 }
658
659                 [MonoLimitation ("Only works on windows")]
660                 public static int WindowWidth {
661                         get { return ConsoleDriver.WindowWidth; }
662                         set { ConsoleDriver.WindowWidth = value; }
663                 }
664
665                 public static bool IsErrorRedirected {
666                         get {
667                                 return ConsoleDriver.IsErrorRedirected;
668                         }
669                 }
670
671                 public static bool IsOutputRedirected {
672                         get {
673                                 return ConsoleDriver.IsOutputRedirected;
674                         }
675                 }
676
677                 public static bool IsInputRedirected {
678                         get {
679                                 return ConsoleDriver.IsInputRedirected;
680                         }
681                 }
682
683                 public static void Beep ()
684                 {
685                         Beep (1000, 500);
686                 }
687
688                 public static void Beep (int frequency, int duration)
689                 {
690                         if (frequency < 37 || frequency > 32767)
691                                 throw new ArgumentOutOfRangeException ("frequency");
692
693                         if (duration <= 0)
694                                 throw new ArgumentOutOfRangeException ("duration");
695
696                         ConsoleDriver.Beep (frequency, duration);
697                 }
698
699                 public static void Clear ()
700                 {
701                         ConsoleDriver.Clear ();
702                 }
703
704                 [MonoLimitation ("Implemented only on Windows")]
705                 public static void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight,
706                                                 int targetLeft, int targetTop)
707                 {
708                         ConsoleDriver.MoveBufferArea (sourceLeft, sourceTop, sourceWidth, sourceHeight, targetLeft, targetTop);
709                 }
710
711                 [MonoLimitation ("Implemented only on Windows")]
712                 public static void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight,
713                                                 int targetLeft, int targetTop, Char sourceChar,
714                                                 ConsoleColor sourceForeColor, ConsoleColor sourceBackColor)
715                 {
716                         ConsoleDriver.MoveBufferArea (sourceLeft, sourceTop, sourceWidth, sourceHeight, targetLeft, targetTop,
717                                                         sourceChar, sourceForeColor, sourceBackColor);
718                 }
719
720                 public static ConsoleKeyInfo ReadKey ()
721                 {
722                         return ReadKey (false);
723                 }
724
725                 public static ConsoleKeyInfo ReadKey (bool intercept)
726                 {
727                         return ConsoleDriver.ReadKey (intercept);
728                 }
729
730                 public static void ResetColor ()
731                 {
732                         ConsoleDriver.ResetColor ();
733                 }
734
735                 [MonoLimitation ("Only works on windows")]
736                 public static void SetBufferSize (int width, int height)
737                 {
738                         ConsoleDriver.SetBufferSize (width, height);
739                 }
740
741                 public static void SetCursorPosition (int left, int top)
742                 {
743                         ConsoleDriver.SetCursorPosition (left, top);
744                 }
745
746                 public static void SetWindowPosition (int left, int top)
747                 {
748                         ConsoleDriver.SetWindowPosition (left, top);
749                 }
750
751                 public static void SetWindowSize (int width, int height)
752                 {
753                         ConsoleDriver.SetWindowSize (width, height);
754                 }
755
756                 static ConsoleCancelEventHandler cancel_event;
757                 public static event ConsoleCancelEventHandler CancelKeyPress {
758                         add {
759                                 if (ConsoleDriver.Initialized == false)
760                                         ConsoleDriver.Init ();
761
762                                 cancel_event += value;
763
764                                 if (Environment.IsRunningOnWindows && !WindowsConsole.ctrlHandlerAdded)
765                                         WindowsConsole.AddCtrlHandler();
766                         }
767                         remove {
768                                 if (ConsoleDriver.Initialized == false)
769                                         ConsoleDriver.Init ();
770
771                                 cancel_event -= value;
772
773                                 if (cancel_event == null && Environment.IsRunningOnWindows)
774                                 {
775                                         // Need to remove our hook if there's nothing left in the event
776                                         if (WindowsConsole.ctrlHandlerAdded)
777                                                 WindowsConsole.RemoveCtrlHandler();
778                                 }
779                         }
780                 }
781
782                 delegate void InternalCancelHandler ();
783                 
784 #pragma warning disable 414
785                 //
786                 // Used by console-io.c
787                 //
788                 static readonly InternalCancelHandler cancel_handler = new InternalCancelHandler (DoConsoleCancelEvent);
789 #pragma warning restore 414             
790
791                 internal static void DoConsoleCancelEvent ()
792                 {
793                         bool exit = true;
794                         if (cancel_event != null) {
795                                 ConsoleCancelEventArgs args = new ConsoleCancelEventArgs (ConsoleSpecialKey.ControlC);
796                                 Delegate [] delegates = cancel_event.GetInvocationList ();
797                                 foreach (ConsoleCancelEventHandler d in delegates){
798                                         try {
799                                                 // Sender is always null here.
800                                                 d (null, args);
801                                         } catch {} // Ignore any exception.
802                                 }
803                                 exit = !args.Cancel;
804                         }
805
806                         if (exit)
807                                 Environment.Exit (58);
808                 }
809 #endif
810         }
811 }
812