Add support for the CancelKeyPress event on Windows
authorAlex Fort <imphasing@gmail.com>
Tue, 9 Nov 2010 20:22:49 +0000 (15:22 -0500)
committerGonzalo Paniagua Javier <gonzalo.mono@gmail.com>
Wed, 10 Nov 2010 03:24:29 +0000 (22:24 -0500)
Adds a call to the Win32 function SetConsoleCtrlHandler for Windows,
which adds the DoWindowsConsoleCancelEvent wrapper for
DoConsoleCancelEvent to the Ctrl-C handler when an event handler is
added, and removes the handler once all event handlers are removed.

mcs/class/corlib/System/Console.cs

index 9457016a431d0cace111e888dcc766b4a38a1da2..8b68f4f505f373c581a8e8ddf4c69336f78a4b4c 100644 (file)
@@ -44,11 +44,26 @@ namespace System
 #if !NET_2_1
                private class WindowsConsole
                {
+                       public static bool ctrlHandlerAdded = false;
+                       private delegate bool WindowsCancelHandler (int keyCode);
+                       private static WindowsCancelHandler cancelHandler = new WindowsCancelHandler (DoWindowsConsoleCancelEvent);
+
                        [DllImport ("kernel32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
                        private static extern int GetConsoleCP ();
                        [DllImport ("kernel32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
                        private static extern int GetConsoleOutputCP ();
 
+                       [DllImport ("kernel32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
+                       private static extern bool SetConsoleCtrlHandler (WindowsCancelHandler handler, bool addHandler);
+
+                       // Only call the event handler if Control-C was pressed (code == 0), nothing else
+                       private static bool DoWindowsConsoleCancelEvent (int keyCode)
+                       {
+                               if (keyCode == 0)
+                                       DoConsoleCancelEvent ();
+                               return keyCode == 0;
+                       }
+
                        [MethodImpl (MethodImplOptions.NoInlining)]
                        public static int GetInputCodePage ()
                        {
@@ -60,6 +75,18 @@ namespace System
                        {
                                return GetConsoleOutputCP ();
                        }
+
+                       public static void AddCtrlHandler ()
+                       {
+                               SetConsoleCtrlHandler (cancelHandler, true);
+                               ctrlHandlerAdded = true;
+                       }
+                       
+                       public static void RemoveCtrlHandler ()
+                       {
+                               SetConsoleCtrlHandler (cancelHandler, false);
+                               ctrlHandlerAdded = false;
+                       }
                }
 #endif
                internal static TextWriter stdout;
@@ -682,12 +709,22 @@ namespace System
                                        ConsoleDriver.Init ();
 
                                cancel_event += value;
+
+                               if (Environment.IsRunningOnWindows && !WindowsConsole.ctrlHandlerAdded)
+                                       WindowsConsole.AddCtrlHandler();
                        }
                        remove {
                                if (ConsoleDriver.Initialized == false)
                                        ConsoleDriver.Init ();
 
                                cancel_event -= value;
+
+                               if (cancel_event == null && Environment.IsRunningOnWindows)
+                               {
+                                       // Need to remove our hook if there's nothing left in the event
+                                       if (WindowsConsole.ctrlHandlerAdded)
+                                               WindowsConsole.RemoveCtrlHandler();
+                               }
                        }
                }