zoukankan      html  css  js  c++  java
  • 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.asp
    114         /// </remarks>
    115         [StructLayout(LayoutKind.Sequential)]
    116         private class KeyboardHookStruct
    117         {
    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         #endregion
    140 
    141         #region Windows function imports
    142         /// <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.asp
    171         /// </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.asp
    192         /// </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.asp
    221         /// </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.asp
    259         /// </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.asp
    299         /// </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.asp
    321         /// </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         #endregion
    329 
    330         #region Windows constants
    331 
    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 button
    361         /// </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         #endregion
    430 
    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 events
    442         /// </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 exceptions
    460             Stop(true, true, false);
    461         }
    462 
    463         /// <summary>
    464         /// Occurs when the user moves the mouse, presses any mouse button or scrolls the wheel
    465         /// </summary>
    466         public event MouseEventHandler OnMouseActivity;
    467         /// <summary>
    468         /// Occurs when the user presses a key
    469         /// </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 key
    477         /// </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 events
    503         /// </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 events
    512         /// </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 installed
    519             if (hMouseHook == 0 && InstallMouseHook)
    520             {
    521                 // Create an instance of HookProc.
    522                 MouseHookProcedure = new HookProc(MouseHookProc);
    523                 //install hook
    524                 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 cleanup
    536                     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 installed
    543             if (hKeyboardHook == 0 && InstallKeyboardHook)
    544             {
    545                 // Create an instance of HookProc.
    546                 KeyboardHookProcedure = new HookProc(KeyboardHookProc);
    547                 //install hook
    548                 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 cleanup
    560                     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 uninstalled
    586             if (hMouseHook != 0 && UninstallMouseHook)
    587             {
    588                 //uninstall hook
    589                 int retMouse = UnhookWindowsHookEx(hMouseHook);
    590                 //reset invalid handle
    591                 hMouseHook = 0;
    592                 //if failed and exception must be thrown
    593                 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 uninstalled
    603             if (hKeyboardHook != 0 && UninstallKeyboardHook)
    604             {
    605                 //uninstall hook
    606                 int retKeyboard = UnhookWindowsHookEx(hKeyboardHook);
    607                 //reset invalid handle
    608                 hKeyboardHook = 0;
    609                 //if failed and exception must be thrown
    610                 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 events
    648             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 clicked
    654                 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 value
    672                         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 clicks
    682                 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 it
    695                 OnMouseActivity(this, e);
    696             }
    697             //call next hook
    698             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 flag
    728             bool handled = false;
    729             //it was ok and someone listens to events
    730             if ((nCode >= 0) && (KeyDown != null || KeyUp != null || KeyPress != null))
    731             {
    732                 //read structure KeyboardHookStruct at lParam
    733                 KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
    734                 //raise KeyDown
    735                 if (KeyDown != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
    736                 {
    737                     Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
    738                     KeyEventArgs e = new KeyEventArgs(keyData);
    739                     KeyDown(this, e);
    740                     handled = handled || e.Handled;
    741                 }
    742 
    743                 // raise KeyPress
    744                 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 KeyUp
    767                 if (KeyUp != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))
    768                 {
    769                     Keys keyData = (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 listeners
    778             if (handled)
    779                 return 1;
    780             else
    781                 return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
    782         }
    783     }
    784 }
    人生,总是有一些空城旧事,年华未央;总是有些季节,一季花凉,满地忧伤。许多事,看开了,便会峰回路转;许多梦,看淡了,便会云开日出。学会思索,学会珍藏,微笑领悟,默默坚强。
  • 相关阅读:
    GDB调试汇编堆栈过程分析
    20145322 《信息安全系统设计基础》第十二周学习总结
    # 20145322《信息安全系统设计基础》第十一周学习总结
    20145322 《信息安全系统设计基础》第十周学习总结
    20145322学号 《信息安全系统设计基础》第9周学习总结(二)
    20145322学号 《信息安全系统设计基础》第9周学习总结(一)
    20145322 《信息安全系统设计基础》期中总结
    20145322 20145310 20145318信息安全系统设计基础实验报告
    20145322 《信息安全系统设计基础》第8周学习总结
    《信息安全系统设计基础》实验一报告
  • 原文地址:https://www.cnblogs.com/yuzhou133/p/4111064.html
Copyright © 2011-2022 走看看