首页 > 代码库 > c#键盘鼠标钩子

c#键盘鼠标钩子

  1 using System;  2 using System.Collections.Generic;  3 using System.Linq;  4 using System.Text;  5 using System.Windows.Forms;  6 using System.Runtime.InteropServices;  7 using System.ComponentModel;  8 using System.Reflection;  9  10 namespace Alif.CommonAPI.WindowsAPI 11 { 12     /// <summary> 13     /// 用户键盘鼠标钩子 14     /// </summary> 15     public class UserActivityHook 16     { 17         #region Windows structure definitions 18  19         /// <summary> 20         /// The POINT structure defines the x- and y- coordinates of a point.  21         /// </summary> 22         /// <remarks> 23         /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/rectangl_0tiq.asp 24         /// </remarks> 25         [StructLayout(LayoutKind.Sequential)] 26         private class POINT 27         { 28             /// <summary> 29             /// Specifies the x-coordinate of the point.  30             /// </summary> 31             public int x; 32             /// <summary> 33             /// Specifies the y-coordinate of the point.  34             /// </summary> 35             public int y; 36         } 37  38         /// <summary> 39         /// The MOUSEHOOKSTRUCT structure contains information about a mouse event passed to a WH_MOUSE hook procedure, MouseProc.  40         /// </summary> 41         /// <remarks> 42         /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/hooks/hookreference/hookstructures/cwpstruct.asp 43         /// </remarks> 44         [StructLayout(LayoutKind.Sequential)] 45         private class MouseHookStruct 46         { 47             /// <summary> 48             /// Specifies a POINT structure that contains the x- and y-coordinates of the cursor, in screen coordinates.  49             /// </summary> 50             public POINT pt; 51             /// <summary> 52             /// Handle to the window that will receive the mouse message corresponding to the mouse event.  53             /// </summary> 54             public int hwnd; 55             /// <summary> 56             /// Specifies the hit-test value. For a list of hit-test values, see the description of the WM_NCHITTEST message.  57             /// </summary> 58             public int wHitTestCode; 59             /// <summary> 60             /// Specifies extra information associated with the message.  61             /// </summary> 62             public int dwExtraInfo; 63         } 64  65         /// <summary> 66         /// The MSLLHOOKSTRUCT structure contains information about a low-level keyboard input event.  67         /// </summary> 68         [StructLayout(LayoutKind.Sequential)] 69         private class MouseLLHookStruct 70         { 71             /// <summary> 72             /// Specifies a POINT structure that contains the x- and y-coordinates of the cursor, in screen coordinates.  73             /// </summary> 74             public POINT pt; 75             /// <summary> 76             /// If the message is WM_MOUSEWHEEL, the high-order word of this member is the wheel delta.  77             /// The low-order word is reserved. A positive value indicates that the wheel was rotated forward,  78             /// away from the user; a negative value indicates that the wheel was rotated backward, toward the user.  79             /// One wheel click is defined as WHEEL_DELTA, which is 120.  80             ///If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP, 81             /// or WM_NCXBUTTONDBLCLK, the high-order word specifies which X button was pressed or released,  82             /// and the low-order word is reserved. This value can be one or more of the following values. Otherwise, mouseData is not used.  83             ///XBUTTON1 84             ///The first X button was pressed or released. 85             ///XBUTTON2 86             ///The second X button was pressed or released. 87             /// </summary> 88             public int mouseData; 89             /// <summary> 90             /// Specifies the event-injected flag. An application can use the following value to test the mouse flags. Value Purpose  91             ///LLMHF_INJECTED Test the event-injected flag.   92             ///0 93             ///Specifies whether the event was injected. The value is 1 if the event was injected; otherwise, it is 0. 94             ///1-15 95             ///Reserved. 96             /// </summary> 97             public int flags; 98             /// <summary> 99             /// Specifies the time stamp for this message.100             /// </summary>101             public int time;102             /// <summary>103             /// Specifies extra information associated with the message. 104             /// </summary>105             public int dwExtraInfo;106         }107 108 109         /// <summary>110         /// The KBDLLHOOKSTRUCT structure contains information about a low-level keyboard input event. 111         /// </summary>112         /// <remarks>113         /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/hooks/hookreference/hookstructures/cwpstruct.asp114         /// </remarks>115         [StructLayout(LayoutKind.Sequential)]116         private class KeyboardHookStruct117         {118             /// <summary>119             /// Specifies a virtual-key code. The code must be a value in the range 1 to 254. 120             /// </summary>121             public int vkCode;122             /// <summary>123             /// Specifies a hardware scan code for the key. 124             /// </summary>125             public int scanCode;126             /// <summary>127             /// Specifies the extended-key flag, event-injected flag, context code, and transition-state flag.128             /// </summary>129             public int flags;130             /// <summary>131             /// Specifies the time stamp for this message.132             /// </summary>133             public int time;134             /// <summary>135             /// Specifies extra information associated with the message. 136             /// </summary>137             public int dwExtraInfo;138         }139         #endregion140 141         #region Windows function imports142         /// <summary>143         /// The SetWindowsHookEx function installs an application-defined hook procedure into a hook chain. 144         /// You would install a hook procedure to monitor the system for certain types of events. These events 145         /// are associated either with a specific thread or with all threads in the same desktop as the calling thread. 146         /// </summary>147         /// <param name="idHook">148         /// [in] Specifies the type of hook procedure to be installed. This parameter can be one of the following values.149         /// </param>150         /// <param name="lpfn">151         /// [in] Pointer to the hook procedure. If the dwThreadId parameter is zero or specifies the identifier of a 152         /// thread created by a different process, the lpfn parameter must point to a hook procedure in a dynamic-link 153         /// library (DLL). Otherwise, lpfn can point to a hook procedure in the code associated with the current process.154         /// </param>155         /// <param name="hMod">156         /// [in] Handle to the DLL containing the hook procedure pointed to by the lpfn parameter. 157         /// The hMod parameter must be set to NULL if the dwThreadId parameter specifies a thread created by 158         /// the current process and if the hook procedure is within the code associated with the current process. 159         /// </param>160         /// <param name="dwThreadId">161         /// [in] Specifies the identifier of the thread with which the hook procedure is to be associated. 162         /// If this parameter is zero, the hook procedure is associated with all existing threads running in the 163         /// same desktop as the calling thread. 164         /// </param>165         /// <returns>166         /// If the function succeeds, the return value is the handle to the hook procedure.167         /// If the function fails, the return value is NULL. To get extended error information, call GetLastError.168         /// </returns>169         /// <remarks>170         /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/hooks/hookreference/hookfunctions/setwindowshookex.asp171         /// </remarks>172         [DllImport("user32.dll", CharSet = CharSet.Auto,173            CallingConvention = CallingConvention.StdCall, SetLastError = true)]174         private static extern int SetWindowsHookEx(175             int idHook,176             HookProc lpfn,177             IntPtr hMod,178             int dwThreadId);179 180         /// <summary>181         /// The UnhookWindowsHookEx function removes a hook procedure installed in a hook chain by the SetWindowsHookEx function. 182         /// </summary>183         /// <param name="idHook">184         /// [in] Handle to the hook to be removed. This parameter is a hook handle obtained by a previous call to SetWindowsHookEx. 185         /// </param>186         /// <returns>187         /// If the function succeeds, the return value is nonzero.188         /// If the function fails, the return value is zero. To get extended error information, call GetLastError.189         /// </returns>190         /// <remarks>191         /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/hooks/hookreference/hookfunctions/setwindowshookex.asp192         /// </remarks>193         [DllImport("user32.dll", CharSet = CharSet.Auto,194             CallingConvention = CallingConvention.StdCall, SetLastError = true)]195         private static extern int UnhookWindowsHookEx(int idHook);196 197         /// <summary>198         /// The CallNextHookEx function passes the hook information to the next hook procedure in the current hook chain. 199         /// A hook procedure can call this function either before or after processing the hook information. 200         /// </summary>201         /// <param name="idHook">Ignored.</param>202         /// <param name="nCode">203         /// [in] Specifies the hook code passed to the current hook procedure. 204         /// The next hook procedure uses this code to determine how to process the hook information.205         /// </param>206         /// <param name="wParam">207         /// [in] Specifies the wParam value passed to the current hook procedure. 208         /// The meaning of this parameter depends on the type of hook associated with the current hook chain. 209         /// </param>210         /// <param name="lParam">211         /// [in] Specifies the lParam value passed to the current hook procedure. 212         /// The meaning of this parameter depends on the type of hook associated with the current hook chain. 213         /// </param>214         /// <returns>215         /// This value is returned by the next hook procedure in the chain. 216         /// The current hook procedure must also return this value. The meaning of the return value depends on the hook type. 217         /// For more information, see the descriptions of the individual hook procedures.218         /// </returns>219         /// <remarks>220         /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/hooks/hookreference/hookfunctions/setwindowshookex.asp221         /// </remarks>222         [DllImport("user32.dll", CharSet = CharSet.Auto,223              CallingConvention = CallingConvention.StdCall)]224         private static extern int CallNextHookEx(225             int idHook,226             int nCode,227             int wParam,228             IntPtr lParam);229 230         /// <summary>231         /// The CallWndProc hook procedure is an application-defined or library-defined callback 232         /// function used with the SetWindowsHookEx function. The HOOKPROC type defines a pointer 233         /// to this callback function. CallWndProc is a placeholder for the application-defined 234         /// or library-defined function name.235         /// </summary>236         /// <param name="nCode">237         /// [in] Specifies whether the hook procedure must process the message. 238         /// If nCode is HC_ACTION, the hook procedure must process the message. 239         /// If nCode is less than zero, the hook procedure must pass the message to the 240         /// CallNextHookEx function without further processing and must return the 241         /// value returned by CallNextHookEx.242         /// </param>243         /// <param name="wParam">244         /// [in] Specifies whether the message was sent by the current thread. 245         /// If the message was sent by the current thread, it is nonzero; otherwise, it is zero. 246         /// </param>247         /// <param name="lParam">248         /// [in] Pointer to a CWPSTRUCT structure that contains details about the message. 249         /// </param>250         /// <returns>251         /// If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx. 252         /// If nCode is greater than or equal to zero, it is highly recommended that you call CallNextHookEx 253         /// and return the value it returns; otherwise, other applications that have installed WH_CALLWNDPROC 254         /// hooks will not receive hook notifications and may behave incorrectly as a result. If the hook 255         /// procedure does not call CallNextHookEx, the return value should be zero. 256         /// </returns>257         /// <remarks>258         /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/hooks/hookreference/hookfunctions/callwndproc.asp259         /// </remarks>260         private delegate int HookProc(int nCode, int wParam, IntPtr lParam);261 262         /// <summary>263         /// The ToAscii function translates the specified virtual-key code and keyboard 264         /// state to the corresponding character or characters. The function translates the code 265         /// using the input language and physical keyboard layout identified by the keyboard layout handle.266         /// </summary>267         /// <param name="uVirtKey">268         /// [in] Specifies the virtual-key code to be translated. 269         /// </param>270         /// <param name="uScanCode">271         /// [in] Specifies the hardware scan code of the key to be translated. 272         /// The high-order bit of this value is set if the key is up (not pressed). 273         /// </param>274         /// <param name="lpbKeyState">275         /// [in] Pointer to a 256-byte array that contains the current keyboard state. 276         /// Each element (byte) in the array contains the state of one key. 277         /// If the high-order bit of a byte is set, the key is down (pressed). 278         /// The low bit, if set, indicates that the key is toggled on. In this function, 279         /// only the toggle bit of the CAPS LOCK key is relevant. The toggle state 280         /// of the NUM LOCK and SCROLL LOCK keys is ignored.281         /// </param>282         /// <param name="lpwTransKey">283         /// [out] Pointer to the buffer that receives the translated character or characters. 284         /// </param>285         /// <param name="fuState">286         /// [in] Specifies whether a menu is active. This parameter must be 1 if a menu is active, or 0 otherwise. 287         /// </param>288         /// <returns>289         /// If the specified key is a dead key, the return value is negative. Otherwise, it is one of the following values. 290         /// Value Meaning 291         /// 0 The specified virtual key has no translation for the current state of the keyboard. 292         /// 1 One character was copied to the buffer. 293         /// 2 Two characters were copied to the buffer. This usually happens when a dead-key character 294         /// (accent or diacritic) stored in the keyboard layout cannot be composed with the specified 295         /// virtual key to form a single character. 296         /// </returns>297         /// <remarks>298         /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/keyboardinput/keyboardinputreference/keyboardinputfunctions/toascii.asp299         /// </remarks>300         [DllImport("user32")]301         private static extern int ToAscii(302             int uVirtKey,303             int uScanCode,304             byte[] lpbKeyState,305             byte[] lpwTransKey,306             int fuState);307 308         /// <summary>309         /// The GetKeyboardState function copies the status of the 256 virtual keys to the 310         /// specified buffer. 311         /// </summary>312         /// <param name="pbKeyState">313         /// [in] Pointer to a 256-byte array that contains keyboard key states. 314         /// </param>315         /// <returns>316         /// If the function succeeds, the return value is nonzero.317         /// If the function fails, the return value is zero. To get extended error information, call GetLastError. 318         /// </returns>319         /// <remarks>320         /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/keyboardinput/keyboardinputreference/keyboardinputfunctions/toascii.asp321         /// </remarks>322         [DllImport("user32")]323         private static extern int GetKeyboardState(byte[] pbKeyState);324 325         [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]326         private static extern short GetKeyState(int vKey);327 328         #endregion329 330         #region Windows constants331 332         //values from Winuser.h in Microsoft SDK.333         /// <summary>334         /// Windows NT/2000/XP: Installs a hook procedure that monitors low-level mouse input events.335         /// </summary>336         private const int WH_MOUSE_LL = 14;337         /// <summary>338         /// Windows NT/2000/XP: Installs a hook procedure that monitors low-level keyboard  input events.339         /// </summary>340         private const int WH_KEYBOARD_LL = 13;341 342         /// <summary>343         /// Installs a hook procedure that monitors mouse messages. For more information, see the MouseProc hook procedure. 344         /// </summary>345         private const int WH_MOUSE = 7;346         /// <summary>347         /// Installs a hook procedure that monitors keystroke messages. For more information, see the KeyboardProc hook procedure. 348         /// </summary>349         private const int WH_KEYBOARD = 2;350 351         /// <summary>352         /// The WM_MOUSEMOVE message is posted to a window when the cursor moves. 353         /// </summary>354         private const int WM_MOUSEMOVE = 0x200;355         /// <summary>356         /// The WM_LBUTTONDOWN message is posted when the user presses the left mouse button 357         /// </summary>358         private const int WM_LBUTTONDOWN = 0x201;359         /// <summary>360         /// The WM_RBUTTONDOWN message is posted when the user presses the right mouse button361         /// </summary>362         private const int WM_RBUTTONDOWN = 0x204;363         /// <summary>364         /// The WM_MBUTTONDOWN message is posted when the user presses the middle mouse button 365         /// </summary>366         private const int WM_MBUTTONDOWN = 0x207;367         /// <summary>368         /// The WM_LBUTTONUP message is posted when the user releases the left mouse button 369         /// </summary>370         private const int WM_LBUTTONUP = 0x202;371         /// <summary>372         /// The WM_RBUTTONUP message is posted when the user releases the right mouse button 373         /// </summary>374         private const int WM_RBUTTONUP = 0x205;375         /// <summary>376         /// The WM_MBUTTONUP message is posted when the user releases the middle mouse button 377         /// </summary>378         private const int WM_MBUTTONUP = 0x208;379         /// <summary>380         /// The WM_LBUTTONDBLCLK message is posted when the user double-clicks the left mouse button 381         /// </summary>382         private const int WM_LBUTTONDBLCLK = 0x203;383         /// <summary>384         /// The WM_RBUTTONDBLCLK message is posted when the user double-clicks the right mouse button 385         /// </summary>386         private const int WM_RBUTTONDBLCLK = 0x206;387         /// <summary>388         /// The WM_RBUTTONDOWN message is posted when the user presses the right mouse button 389         /// </summary>390         private const int WM_MBUTTONDBLCLK = 0x209;391         /// <summary>392         /// The WM_MOUSEWHEEL message is posted when the user presses the mouse wheel. 393         /// </summary>394         private const int WM_MOUSEWHEEL = 0x020A;395 396         /// <summary>397         /// The WM_KEYDOWN message is posted to the window with the keyboard focus when a nonsystem 398         /// key is pressed. A nonsystem key is a key that is pressed when the ALT key is not pressed.399         /// </summary>400         private const int WM_KEYDOWN = 0x100;401         /// <summary>402         /// The WM_KEYUP message is posted to the window with the keyboard focus when a nonsystem 403         /// key is released. A nonsystem key is a key that is pressed when the ALT key is not pressed, 404         /// or a keyboard key that is pressed when a window has the keyboard focus.405         /// </summary>406         private const int WM_KEYUP = 0x101;407         /// <summary>408         /// The WM_SYSKEYDOWN message is posted to the window with the keyboard focus when the user 409         /// presses the F10 key (which activates the menu bar) or holds down the ALT key and then 410         /// presses another key. It also occurs when no window currently has the keyboard focus; 411         /// in this case, the WM_SYSKEYDOWN message is sent to the active window. The window that 412         /// receives the message can distinguish between these two contexts by checking the context 413         /// code in the lParam parameter. 414         /// </summary>415         private const int WM_SYSKEYDOWN = 0x104;416         /// <summary>417         /// The WM_SYSKEYUP message is posted to the window with the keyboard focus when the user 418         /// releases a key that was pressed while the ALT key was held down. It also occurs when no 419         /// window currently has the keyboard focus; in this case, the WM_SYSKEYUP message is sent 420         /// to the active window. The window that receives the message can distinguish between 421         /// these two contexts by checking the context code in the lParam parameter. 422         /// </summary>423         private const int WM_SYSKEYUP = 0x105;424 425         private const byte VK_SHIFT = 0x10;426         private const byte VK_CAPITAL = 0x14;427         private const byte VK_NUMLOCK = 0x90;428 429         #endregion430 431         /// <summary>432         /// Creates an instance of UserActivityHook object and sets mouse and keyboard hooks.433         /// </summary>434         /// <exception cref="Win32Exception">Any windows problem.</exception>435         public UserActivityHook()436         {437             Start();438         }439 440         /// <summary>441         /// Creates an instance of UserActivityHook object and installs both or one of mouse and/or keyboard hooks and starts rasing events442         /// </summary>443         /// <param name="InstallMouseHook"><b>true</b> if mouse events must be monitored</param>444         /// <param name="InstallKeyboardHook"><b>true</b> if keyboard events must be monitored</param>445         /// <exception cref="Win32Exception">Any windows problem.</exception>446         /// <remarks>447         /// To create an instance without installing hooks call new UserActivityHook(false, false)448         /// </remarks>449         public UserActivityHook(bool InstallMouseHook, bool InstallKeyboardHook)450         {451             Start(InstallMouseHook, InstallKeyboardHook);452         }453 454         /// <summary>455         /// Destruction.456         /// </summary>457         ~UserActivityHook()458         {459             //uninstall hooks and do not throw exceptions460             Stop(true, true, false);461         }462 463         /// <summary>464         /// Occurs when the user moves the mouse, presses any mouse button or scrolls the wheel465         /// </summary>466         public event MouseEventHandler onm ouseActivity;467         /// <summary>468         /// Occurs when the user presses a key469         /// </summary>470         public event KeyEventHandler KeyDown;471         /// <summary>472         /// Occurs when the user presses and releases 473         /// </summary>474         public event KeyPressEventHandler KeyPress;475         /// <summary>476         /// Occurs when the user releases a key477         /// </summary>478         public event KeyEventHandler KeyUp;479 480 481         /// <summary>482         /// Stores the handle to the mouse hook procedure.483         /// </summary>484         private int hMouseHook = 0;485         /// <summary>486         /// Stores the handle to the keyboard hook procedure.487         /// </summary>488         private int hKeyboardHook = 0;489 490 491         /// <summary>492         /// Declare MouseHookProcedure as HookProc type.493         /// </summary>494         private static HookProc MouseHookProcedure;495         /// <summary>496         /// Declare KeyboardHookProcedure as HookProc type.497         /// </summary>498         private static HookProc KeyboardHookProcedure;499 500 501         /// <summary>502         /// Installs both mouse and keyboard hooks and starts raising events503         /// </summary>504         /// <exception cref="Win32Exception">Any windows problem.</exception>505         public void Start()506         {507             this.Start(true, true);508         }509 510         /// <summary>511         /// Installs both or one of mouse and/or keyboard hooks and starts raising events512         /// </summary>513         /// <param name="InstallMouseHook"><b>true</b> if mouse events must be monitored</param>514         /// <param name="InstallKeyboardHook"><b>true</b> if keyboard events must be monitored</param>515         /// <exception cref="Win32Exception">Any windows problem.</exception>516         public void Start(bool InstallMouseHook, bool InstallKeyboardHook)517         {518             // install Mouse hook only if it is not installed and must be installed519             if (hMouseHook == 0 && InstallMouseHook)520             {521                 // Create an instance of HookProc.522                 MouseHookProcedure = new HookProc(MouseHookProc);523                 //install hook524                 hMouseHook = SetWindowsHookEx(525                     WH_MOUSE_LL,526                     MouseHookProcedure,527                     Marshal.GetHINSTANCE(528                     Assembly.GetExecutingAssembly().GetModules()[0]),529                     0);530                 //If SetWindowsHookEx fails.531                 if (hMouseHook == 0)532                 {533                     //Returns the error code returned by the last unmanaged function called using platform invoke that has the DllImportAttribute.SetLastError flag set. 534                     int errorCode = Marshal.GetLastWin32Error();535                     //do cleanup536                     Stop(true, false, false);537                     //Initializes and throws a new instance of the Win32Exception class with the specified error. 538                     throw new Win32Exception(errorCode);539                 }540             }541 542             // install Keyboard hook only if it is not installed and must be installed543             if (hKeyboardHook == 0 && InstallKeyboardHook)544             {545                 // Create an instance of HookProc.546                 KeyboardHookProcedure = new HookProc(KeyboardHookProc);547                 //install hook548                 hKeyboardHook = SetWindowsHookEx(549                     WH_KEYBOARD_LL,550                     KeyboardHookProcedure,551                     Marshal.GetHINSTANCE(552                     Assembly.GetExecutingAssembly().GetModules()[0]),553                     0);554                 //If SetWindowsHookEx fails.555                 if (hKeyboardHook == 0)556                 {557                     //Returns the error code returned by the last unmanaged function called using platform invoke that has the DllImportAttribute.SetLastError flag set. 558                     int errorCode = Marshal.GetLastWin32Error();559                     //do cleanup560                     Stop(false, true, false);561                     //Initializes and throws a new instance of the Win32Exception class with the specified error. 562                     throw new Win32Exception(errorCode);563                 }564             }565         }566 567         /// <summary>568         /// Stops monitoring both mouse and keyboard events and rasing events.569         /// </summary>570         /// <exception cref="Win32Exception">Any windows problem.</exception>571         public void Stop()572         {573             this.Stop(true, true, true);574         }575 576         /// <summary>577         /// Stops monitoring both or one of mouse and/or keyboard events and rasing events.578         /// </summary>579         /// <param name="UninstallMouseHook"><b>true</b> if mouse hook must be uninstalled</param>580         /// <param name="UninstallKeyboardHook"><b>true</b> if keyboard hook must be uninstalled</param>581         /// <param name="ThrowExceptions"><b>true</b> if exceptions which occured during uninstalling must be thrown</param>582         /// <exception cref="Win32Exception">Any windows problem.</exception>583         public void Stop(bool UninstallMouseHook, bool UninstallKeyboardHook, bool ThrowExceptions)584         {585             //if mouse hook set and must be uninstalled586             if (hMouseHook != 0 && UninstallMouseHook)587             {588                 //uninstall hook589                 int retMouse = UnhookWindowsHookEx(hMouseHook);590                 //reset invalid handle591                 hMouseHook = 0;592                 //if failed and exception must be thrown593                 if (retMouse == 0 && ThrowExceptions)594                 {595                     //Returns the error code returned by the last unmanaged function called using platform invoke that has the DllImportAttribute.SetLastError flag set. 596                     int errorCode = Marshal.GetLastWin32Error();597                     //Initializes and throws a new instance of the Win32Exception class with the specified error. 598                     throw new Win32Exception(errorCode);599                 }600             }601 602             //if keyboard hook set and must be uninstalled603             if (hKeyboardHook != 0 && UninstallKeyboardHook)604             {605                 //uninstall hook606                 int retKeyboard = UnhookWindowsHookEx(hKeyboardHook);607                 //reset invalid handle608                 hKeyboardHook = 0;609                 //if failed and exception must be thrown610                 if (retKeyboard == 0 && ThrowExceptions)611                 {612                     //Returns the error code returned by the last unmanaged function called using platform invoke that has the DllImportAttribute.SetLastError flag set. 613                     int errorCode = Marshal.GetLastWin32Error();614                     //Initializes and throws a new instance of the Win32Exception class with the specified error. 615                     throw new Win32Exception(errorCode);616                 }617             }618         }619 620 621         /// <summary>622         /// A callback function which will be called every time a mouse activity detected.623         /// </summary>624         /// <param name="nCode">625         /// [in] Specifies whether the hook procedure must process the message. 626         /// If nCode is HC_ACTION, the hook procedure must process the message. 627         /// If nCode is less than zero, the hook procedure must pass the message to the 628         /// CallNextHookEx function without further processing and must return the 629         /// value returned by CallNextHookEx.630         /// </param>631         /// <param name="wParam">632         /// [in] Specifies whether the message was sent by the current thread. 633         /// If the message was sent by the current thread, it is nonzero; otherwise, it is zero. 634         /// </param>635         /// <param name="lParam">636         /// [in] Pointer to a CWPSTRUCT structure that contains details about the message. 637         /// </param>638         /// <returns>639         /// If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx. 640         /// If nCode is greater than or equal to zero, it is highly recommended that you call CallNextHookEx 641         /// and return the value it returns; otherwise, other applications that have installed WH_CALLWNDPROC 642         /// hooks will not receive hook notifications and may behave incorrectly as a result. If the hook 643         /// procedure does not call CallNextHookEx, the return value should be zero. 644         /// </returns>645         private int MouseHookProc(int nCode, int wParam, IntPtr lParam)646         {647             // if ok and someone listens to our events648             if ((nCode >= 0) && (OnMouseActivity != null))649             {650                 //Marshall the data from callback.651                 MouseLLHookStruct mouseHookStruct = (MouseLLHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseLLHookStruct));652 653                 //detect button clicked654                 MouseButtons button = MouseButtons.None;655                 short mouseDelta = 0;656                 switch (wParam)657                 {658                     case WM_LBUTTONDOWN:659                         //case WM_LBUTTONUP: 660                         //case WM_LBUTTONDBLCLK: 661                         button = MouseButtons.Left;662                         break;663                     case WM_RBUTTONDOWN:664                         //case WM_RBUTTONUP: 665                         //case WM_RBUTTONDBLCLK: 666                         button = MouseButtons.Right;667                         break;668                     case WM_MOUSEWHEEL:669                         //If the message is WM_MOUSEWHEEL, the high-order word of mouseData member is the wheel delta. 670                         //One wheel click is defined as WHEEL_DELTA, which is 120. 671                         //(value >> 16) & 0xffff; retrieves the high-order word from the given 32-bit value672                         mouseDelta = (short)((mouseHookStruct.mouseData >> 16) & 0xffff);673                         //TODO: X BUTTONS (I havent them so was unable to test)674                         //If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP, 675                         //or WM_NCXBUTTONDBLCLK, the high-order word specifies which X button was pressed or released, 676                         //and the low-order word is reserved. This value can be one or more of the following values. 677                         //Otherwise, mouseData is not used. 678                         break;679                 }680 681                 //double clicks682                 int clickCount = 0;683                 if (button != MouseButtons.None)684                     if (wParam == WM_LBUTTONDBLCLK || wParam == WM_RBUTTONDBLCLK) clickCount = 2;685                     else clickCount = 1;686 687                 //generate event 688                 MouseEventArgs e = new MouseEventArgs(689                                    button,690                                    clickCount,691                                    mouseHookStruct.pt.x,692                                    mouseHookStruct.pt.y,693                                    mouseDelta);694                 //raise it695                 onm ouseActivity(this, e);696             }697             //call next hook698             return CallNextHookEx(hMouseHook, nCode, wParam, lParam);699         }700 701         /// <summary>702         /// A callback function which will be called every time a keyboard activity detected.703         /// </summary>704         /// <param name="nCode">705         /// [in] Specifies whether the hook procedure must process the message. 706         /// If nCode is HC_ACTION, the hook procedure must process the message. 707         /// If nCode is less than zero, the hook procedure must pass the message to the 708         /// CallNextHookEx function without further processing and must return the 709         /// value returned by CallNextHookEx.710         /// </param>711         /// <param name="wParam">712         /// [in] Specifies whether the message was sent by the current thread. 713         /// If the message was sent by the current thread, it is nonzero; otherwise, it is zero. 714         /// </param>715         /// <param name="lParam">716         /// [in] Pointer to a CWPSTRUCT structure that contains details about the message. 717         /// </param>718         /// <returns>719         /// If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx. 720         /// If nCode is greater than or equal to zero, it is highly recommended that you call CallNextHookEx 721         /// and return the value it returns; otherwise, other applications that have installed WH_CALLWNDPROC 722         /// hooks will not receive hook notifications and may behave incorrectly as a result. If the hook 723         /// procedure does not call CallNextHookEx, the return value should be zero. 724         /// </returns>725         private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)726         {727             //indicates if any of underlaing events set e.Handled flag728             bool handled = false;729             //it was ok and someone listens to events730             if ((nCode >= 0) && (KeyDown != null || KeyUp != null || KeyPress != null))731             {732                 //read structure KeyboardHookStruct at lParam733                 KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));734                 //raise KeyDown735                 if (KeyDown != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))736                 {737                     Keys keyData =http://www.mamicode.com/ (Keys)MyKeyboardHookStruct.vkCode;738                     KeyEventArgs e = new KeyEventArgs(keyData);739                     KeyDown(this, e);740                     handled = handled || e.Handled;741                 }742 743                 // raise KeyPress744                 if (KeyPress != null && wParam == WM_KEYDOWN)745                 {746                     bool isDownShift = ((GetKeyState(VK_SHIFT) & 0x80) == 0x80 ? true : false);747                     bool isDownCapslock = (GetKeyState(VK_CAPITAL) != 0 ? true : false);748 749                     byte[] keyState = new byte[256];750                     GetKeyboardState(keyState);751                     byte[] inBuffer = new byte[2];752                     if (ToAscii(MyKeyboardHookStruct.vkCode,753                           MyKeyboardHookStruct.scanCode,754                           keyState,755                           inBuffer,756                           MyKeyboardHookStruct.flags) == 1)757                     {758                         char key = (char)inBuffer[0];759                         if ((isDownCapslock ^ isDownShift) && Char.IsLetter(key)) key = Char.ToUpper(key);760                         KeyPressEventArgs e = new KeyPressEventArgs(key);761                         KeyPress(this, e);762                         handled = handled || e.Handled;763                     }764                 }765 766                 // raise KeyUp767                 if (KeyUp != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))768                 {769                     Keys keyData =http://www.mamicode.com/ (Keys)MyKeyboardHookStruct.vkCode;770                     KeyEventArgs e = new KeyEventArgs(keyData);771                     KeyUp(this, e);772                     handled = handled || e.Handled;773                 }774 775             }776 777             //if event handled in application do not handoff to other listeners778             if (handled)779                 return 1;780             else781                 return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);782         }783     }784 }

 

c#键盘鼠标钩子