zoukankan      html  css  js  c++  java
  • 如何在C#中使用全局鼠标、键盘Hook

    今天,有个同事问我,怎样在C#中使用全局钩子?以前写的全局钩子都是用unmanaged C或C++写个DLL来实现,可大家都知道,C#是基于.Net Framework的,是managed,怎么实现全局钩子呢?于是开始到网上搜索,好不容易找到一篇,318804 - HOW TO: Set a Windows Hook in Visual C# .NET,里面详细的说明了如何使用鼠标钩子捕获鼠标的移动等,可是,它只能在Application里起作用,出了Application就没用了,就是说它还是没有实现全局钩子,而且文章结尾处说:“Global Hooks are not supported in the .NET Framework...”,这可怎么办呢? 

      别担心,办法总是有的,经过一番摸索以后,发现WH_KEYBORAD_LL和WH_MOUSE_LL这两个low-level的hook可以被安装成全局的,这就好办了,我们不妨用这两个low-level的hook替换掉WH_KEYBORAD和WH_MOUSE,于是开始测试。结果成功了,在C#里实现了全局钩子。 

      我们来看一下主要代码段。 

      首先倒入所需要的windows函数,主要有三个,SetWindowsHookEX用来安装钩子,UnhookWindowsHookEX用来卸载钩子以及CallNextHookEX用来将hook信息传递到链表中下一个hook处理过程。 

    C#代码  收藏代码
      1. [DllImport("user32.dll", CharSet = CharSet.Auto,  
      2.            CallingConvention = CallingConvention.StdCall, SetLastError = true)]  
      3.         private static extern int SetWindowsHookEx(  
      4.             int idHook,  
      5.             HookProc lpfn,  
      6.             IntPtr hMod,  
      7.             int dwThreadId);  
      8.   
      9. [DllImport("user32.dll", CharSet = CharSet.Auto,  
      10.             CallingConvention = CallingConvention.StdCall, SetLastError = true)]  
      11.         private static extern int UnhookWindowsHookEx(int idHook);  
      12.   
      13. [DllImport("user32.dll", CharSet = CharSet.Auto,  
      14.              CallingConvention = CallingConvention.StdCall)]  
      15.         private static extern int CallNextHookEx(  
      16.             int idHook,  
      17.             int nCode,  
      18.             int wParam,  
      19.             IntPtr lParam);  
      20.   
      21.   下面是有关这两个low-level hook在Winuser.h中的定义:  
      22.   
      23.   
      24. /// <summary>  
      25.         /// Windows NT/2000/XP: Installs a hook procedure that monitors low-level mouse input events.  
      26.         /// </summary>  
      27.         private const int WH_MOUSE_LL       = 14;  
      28.         /// <summary>  
      29.         /// Windows NT/2000/XP: Installs a hook procedure that monitors low-level keyboard input events.  
      30.         /// </summary>  
      31.         private const int WH_KEYBOARD_LL    = 13;  
      32.   
      33.   在安装全局钩子的时候,我们就要做替换了,将WH_MOUSE和WH_KEYBORAD分别换成WH_MOUSE_LL和WH_KEYBORAD_LL:  
      34.   
      35.   
      36. //install hook  
      37.                 hMouseHook = SetWindowsHookEx(  
      38.                     WH_MOUSE_LL, //原来是WH_MOUSE  
      39.                     MouseHookProcedure,  
      40.                     Marshal.GetHINSTANCE(  
      41.                         Assembly.GetExecutingAssembly().GetModules()[0]),  
      42.                     0);  
      43.   
      44. //install hook  
      45.                 hKeyboardHook = SetWindowsHookEx(  
      46.                     WH_KEYBOARD_LL, //原来是WH_KEYBORAD  
      47.                     KeyboardHookProcedure,  
      48.                     Marshal.GetHINSTANCE(  
      49.                     Assembly.GetExecutingAssembly().GetModules()[0]),  
      50.                     0);  
      51.   
      52.   这样替换了之后,我们就可以实现全局钩子了,而且,不需要写DLL。看一下程序运行情况:  
      53.   
      54.   
      55.   
      56.   下面是关于鼠标和键盘的两个Callback函数:  
      57.   
      58.   
      59. private int MouseHookProc(int nCode, int wParam, IntPtr lParam)  
      60.   
      61.         {  
      62.   
      63.             // if ok and someone listens to our events  
      64.   
      65.             if ((nCode >= 0) && (OnMouseActivity != null))  
      66.   
      67.             {  
      68.   
      69.                 //Marshall the data from callback.  
      70.   
      71.                 MouseLLHookStruct mouseHookStruct = (MouseLLHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseLLHookStruct));  
      72.   
      73.   
      74.                 //detect button clicked  
      75.   
      76.                 MouseButtons button = MouseButtons.None;  
      77.   
      78.                 short mouseDelta = 0;  
      79.   
      80.                 switch (wParam)  
      81.   
      82.                 {  
      83.   
      84.                     case WM_LBUTTONDOWN:  
      85.   
      86.                         //case WM_LBUTTONUP:  
      87.   
      88.                         //case WM_LBUTTONDBLCLK:  
      89.   
      90.                         button = MouseButtons.Left;  
      91.   
      92.                         break;  
      93.   
      94.                     case WM_RBUTTONDOWN:  
      95.   
      96.                         //case WM_RBUTTONUP:  
      97.   
      98.                         //case WM_RBUTTONDBLCLK:  
      99.   
      100.                         button = MouseButtons.Right;  
      101.   
      102.                         break;  
      103.   
      104.                     case WM_MOUSEWHEEL:  
      105.   
      106.                         //If the message is WM_MOUSEWHEEL, the high-order word of mouseData member is the wheel delta.  
      107.   
      108.                         //One wheel click is defined as WHEEL_DELTA, which is 120.  
      109.   
      110.                         //(value >> 16) & 0xffff; retrieves the high-order word from the given 32-bit value  
      111.   
      112.                         mouseDelta = (short)((mouseHookStruct.mouseData >> 16) & 0xffff);  
      113.   
      114.                         //TODO: X BUTTONS (I havent them so was unable to test)  
      115.   
      116.                         //If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP,  
      117.   
      118.                         //or WM_NCXBUTTONDBLCLK, the high-order word specifies which X button was pressed or released,  
      119.   
      120.                         //and the low-order word is reserved. This value can be one or more of the following values.  
      121.   
      122.                         //Otherwise, mouseData is not used.  
      123.   
      124.                         break;  
      125.   
      126.                 }  
      127.   
      128.   
      129.                 //double clicks  
      130.   
      131.                 int clickCount = 0;  
      132.   
      133.                 if (button != MouseButtons.None)  
      134.   
      135.                     if (wParam == WM_LBUTTONDBLCLK || wParam == WM_RBUTTONDBLCLK) clickCount = 2;  
      136.   
      137.                     else clickCount = 1;  
      138.   
      139.   
      140.                 //generate event  
      141.   
      142.                  MouseEventArgs e = new MouseEventArgs(  
      143.   
      144.                                                     button,  
      145.   
      146.                                                     clickCount,  
      147.   
      148.                                                     mouseHookStruct.pt.x,  
      149.   
      150.                                                     mouseHookStruct.pt.y,  
      151.   
      152.                                                     mouseDelta);  
      153.   
      154.                 //raise it  
      155.   
      156.                 OnMouseActivity(this, e);  
      157.   
      158.             }  
      159.   
      160.             //call next hook  
      161.   
      162.             return CallNextHookEx(hMouseHook, nCode, wParam, lParam);  
      163.   
      164.         }  
      165.   
      166.   
      167. private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)  
      168. {  
      169.             //indicates if any of underlaing events set e.Handled flag  
      170.             bool handled = false;  
      171.             //it was ok and someone listens to events  
      172.             if ((nCode >= 0) && (KeyDown != null || KeyUp != null || KeyPress != null))  
      173.             {  
      174.                 //read structure KeyboardHookStruct at lParam  
      175.                 KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));  
      176.                 //raise KeyDown  
      177.                 if (KeyDown != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))  
      178.                 {  
      179.                     Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;  
      180.                     KeyEventArgs e = new KeyEventArgs(keyData);  
      181.                     KeyDown(this, e);  
      182.                     handled = handled || e.Handled;  
      183.                 }  
      184.   
      185.                 // raise KeyPress  
      186.                 if (KeyPress != null && wParam == WM_KEYDOWN)  
      187.                 {  
      188.                     bool isDownShift = ((GetKeyState(VK_SHIFT) & 0x80) == 0x80 ? true : false);  
      189.                     bool isDownCapslock = (GetKeyState(VK_CAPITAL) != 0 ? true : false);  
      190.   
      191.                     byte[] keyState = new byte[256];  
      192.                     GetKeyboardState(keyState);  
      193.                     byte[] inBuffer = new byte[2];  
      194.                     if (ToAscii(MyKeyboardHookStruct.vkCode,  
      195.                               MyKeyboardHookStruct.scanCode,  
      196.                               keyState,  
      197.                               inBuffer,  
      198.                               MyKeyboardHookStruct.flags) == 1)  
      199.                     {  
      200.                         char key = (char)inBuffer[0];  
      201.                         if ((isDownCapslock ^ isDownShift) && Char.IsLetter(key)) key = Char.ToUpper(key);  
      202.                         KeyPressEventArgs e = new KeyPressEventArgs(key);  
      203.                         KeyPress(this, e);  
      204.                         handled = handled || e.Handled;  
      205.                     }  
      206.                 }  
      207.   
      208.                 // raise KeyUp  
      209.                 if (KeyUp != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))  
      210.                 {  
      211.                     Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;  
      212.                     KeyEventArgs e = new KeyEventArgs(keyData);  
      213.                     KeyUp(this, e);  
      214.                     handled = handled || e.Handled;  
      215.                 }  
      216.   
      217.             }  
      218.   
      219.             //if event handled in application do not handoff to other listeners  
      220.             if (handled)  
      221.                 return 1;  
      222.             else  
      223.                 return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);  
      224.         }  
  • 相关阅读:
    【JZOJ3743】【BZOJ5158】Alice and Bob
    【JZOJ3719】K-D-Sequence
    【JZOJ1913】【BZOJ2124】等差子序列
    【JZOJ1914】【BZOJ2125】最短路
    【luoguP4768】【NOI2018】归程
    【JZOJ6435】【luoguP5666】【CSP-S2019】树的重心
    【JZOJ6434】【luoguP5665】【CSP-S2019】划分
    【JZOJ6433】【luoguP5664】【CSP-S2019】Emiya 家今天的饭
    【JZOJ6431】【luoguP5658】【CSP-S2019】括号树
    【JZOJ3673】【luoguP4040】【BZOJ3874】宅男计划
  • 原文地址:https://www.cnblogs.com/gc2013/p/3818201.html
Copyright © 2011-2022 走看看