键盘"全局钩子"的使用 ..

来源:互联网 发布:linux命令文件大小变化 编辑:程序博客网 时间:2024/05/16 10:58
  1. /// <summary>
  2.     ///键盘钩子
  3.     /// </summary>
  4.     public class KeyboardHook  {
  5.         
  6.         public event KeyEventHandler KeyDownEvent;
  7.         public event KeyPressEventHandler KeyPressEvent;
  8.         public event KeyEventHandler KeyUpEvent;
  9.         public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
  10.         static int hKeyboardHook = 0; //声明键盘钩子处理的初始值。
  11.         //值在Microsoft SDK的Winuser.h里查询
  12.         public const int WH_KEYBOARD_LL = 13;    //线程键盘钩子监听鼠标消息设为2,全局键盘监听鼠标消息设为13。    
  13.         HookProc KeyboardHookProcedure; //声明KeyboardHookProcedure作为HookProc类型。
  14.             
  15.         //键盘结构 
  16.         [StructLayout(LayoutKind.Sequential)]
  17.         public class KeyboardHookStruct
  18.         {
  19.             public int vkCode;    //定一个虚拟键码。该代码必须有一个价值的范围1至254 。 
  20.             public int scanCode; // 指定的硬件扫描码的关键。 
  21.             public int flags;  // 键标志
  22.             public int time; // 指定的时间戳记的这个讯息。
  23.             public int dwExtraInfo; // 指定额外信息相关的信息。
  24.         }
  25.         //使用此功能,安装了一个钩子。
  26.         [DllImport("user32.dll",CharSet=CharSet.Auto,
  27.             CallingConvention=CallingConvention.StdCall)]
  28.         public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, 
  29.                                                   IntPtr hInstance, int threadId);
  30.         //调用此函数卸载钩子。
  31.         [DllImport("user32.dll",CharSet=CharSet.Auto,
  32.             CallingConvention=CallingConvention.StdCall)]
  33.         public static extern bool UnhookWindowsHookEx(int idHook);
  34.         //使用此功能,通过信息钩子继续下一个钩子
  35.         [DllImport("user32.dll",CharSet=CharSet.Auto,
  36.             CallingConvention=CallingConvention.StdCall)]
  37.         public static extern int CallNextHookEx(int idHook, int nCode, 
  38.                                                 Int32 wParam, IntPtr lParam);
  39.         
  40.         // 取得当前线程编号(线程钩子需要用到) 
  41.         [DllImport("kernel32.dll")]
  42.         static extern int GetCurrentThreadId(); 
  43.         public void Start()
  44.         {
  45.             // 安装键盘钩子
  46.             if(hKeyboardHook == 0)
  47.             {
  48.                 KeyboardHookProcedure = new HookProc(KeyboardHookProc);
  49.                 hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL,KeyboardHookProcedure, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]),0);
  50.                 //************************************ 
  51.                 //键盘线程钩子 
  52.                 //SetWindowsHookEx( 2,KeyboardHookProcedure, IntPtr.Zero, GetCurrentThreadId());//指定要监听的线程idGetCurrentThreadId(),
  53.                 //键盘全局钩子,需要引用空间(using System.Reflection;) 
  54.                 //SetWindowsHookEx( 13,MouseHookProcedure,Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]),0); 
  55.                 // 
  56.                 //关于SetWindowsHookEx (int idHook, HookProc lpfn, IntPtr hInstance, int threadId)函数将钩子加入到钩子链表中,说明一下四个参数: 
  57.                 //idHook 钩子类型,即确定钩子监听何种消息,上面的代码中设为2,即监听键盘消息并且是线程钩子,如果是全局钩子监听键盘消息应设为13, 
  58.                 //线程钩子监听鼠标消息设为7,全局钩子监听鼠标消息设为14。lpfn 钩子子程的地址指针。如果dwThreadId参数为0 或是一个由别的进程创建的 
  59.                 //线程的标识,lpfn必须指向DLL中的钩子子程。 除此以外,lpfn可以指向当前进程的一段钩子子程代码。钩子函数的入口地址,当钩子钩到任何 
  60.                 //消息后便调用这个函数。hInstance应用程序实例的句柄。标识包含lpfn所指的子程的DLL。如果threadId 标识当前进程创建的一个线程,而且子 
  61.                 //程代码位于当前进程,hInstance必须为NULL。可以很简单的设定其为本应用程序的实例句柄。threaded 与安装的钩子子程相关联的线程的标识符。 
  62.                 //如果为0,钩子子程与所有的线程关联,即为全局钩子。 
  63.                 //************************************ 
  64.                 //如果SetWindowsHookEx失败。
  65.                 if(hKeyboardHook == 0 )    {
  66.                     Stop();
  67.                     throw new Exception("安装键盘钩子失败");
  68.                 }
  69.             }
  70.         }
  71.         public void Stop()
  72.         {
  73.             bool retKeyboard = true;
  74.     
  75.             
  76.             if(hKeyboardHook != 0)
  77.             {
  78.                 retKeyboard = UnhookWindowsHookEx(hKeyboardHook);
  79.                 hKeyboardHook = 0;
  80.             } 
  81.             
  82.             if (!(retKeyboard)) throw new Exception("卸载钩子失败!");
  83.         }
  84.         //ToAscii职能的转换指定的虚拟键码和键盘状态的相应字符或字符。
  85.         [DllImport("user32")]
  86.         public static extern int ToAscii(int uVirtKey, //[in] 指定虚拟关键代码进行翻译。 
  87.                                          int uScanCode, // [in] 指定的硬件扫描码的关键须翻译成英文。高阶位的这个值设定的关键,如果是(不压) 。
  88.                                          byte[] lpbKeyState, // [in] 指针,以256字节数组,包含当前键盘的状态。每个元素(字节)的数组包含状态的一个关键。如果高阶位的字节是一套,关键是下跌(按下)。在低比特,如果设置表明,关键是对切换。在此功能,只有肘位的CAPS LOCK键是相关的。在切换状态的NUM个锁和滚动锁定键被忽略。
  89.                                          byte[] lpwTransKey, // [out] 指针的缓冲区收到翻译字符或字符。 
  90.                                          int fuState); // [in] Specifies whether a menu is active. This parameter must be 1 if a menu is active, or 0 otherwise. 
  91.         //获取按键的状态
  92.         [DllImport("user32")] 
  93.         public static extern int GetKeyboardState(byte[] pbKeyState);
  94.         private const int WM_KEYDOWN = 0x100;//KEYDOWN 
  95.         private const int WM_KEYUP = 0x101;//KEYUP
  96.         private const int WM_SYSKEYDOWN = 0x104;//SYSKEYDOWN
  97.         private const int WM_SYSKEYUP = 0x105;//SYSKEYUP
  98.         private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
  99.         {
  100.             // 侦听键盘事件
  101.             if ((nCode >= 0) && (KeyDownEvent != null || KeyUpEvent != null || KeyPressEvent != null))
  102.             {
  103.                 KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct) Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
  104.                 // raise KeyDown
  105.                 if (KeyDownEvent != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
  106.                 {
  107.                     Keys keyData=(Keys)MyKeyboardHookStruct.vkCode;
  108.                     KeyEventArgs e = new KeyEventArgs(keyData);
  109.                     KeyDownEvent(this, e);
  110.                 }
  111.                 //键盘按下
  112.                 if (KeyPressEvent != null && wParam == WM_KEYDOWN)
  113.                 {
  114.                     byte[] keyState = new byte[256];
  115.                     GetKeyboardState(keyState);
  116.                     byte[] inBuffer= new byte[2];
  117.                     if (ToAscii(MyKeyboardHookStruct.vkCode,
  118.                                 MyKeyboardHookStruct.scanCode,
  119.                                 keyState,
  120.                                 inBuffer,
  121.                                 MyKeyboardHookStruct.flags)==1) 
  122.                     {
  123.                         KeyPressEventArgs e = new KeyPressEventArgs((char)inBuffer[0]);
  124.                         KeyPressEvent(this, e);
  125.                     }
  126.                 }
  127.                 // 键盘抬起 
  128.                 if (KeyUpEvent != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))
  129.                 {
  130.                     Keys keyData=(Keys)MyKeyboardHookStruct.vkCode;
  131.                     KeyEventArgs e = new KeyEventArgs(keyData);
  132.                     KeyUpEvent(this, e);
  133.                 }
  134.             }
  135.             //如果返回1,则结束消息,这个消息到此为止,不再传递。
  136.             //如果返回0或调用CallNextHookEx函数则消息出了这个钩子继续往下传递,也就是传给消息真正的接受者 
  137.             return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam); 
  138.         }
  139.         ~KeyboardHook()
  140.         {
  141.             Stop();
  142.         }
  143.     }
  1. //以下是调用 
  2. private KeyboardHook k_hook;
  3. private void HookForm_Load(object sender, EventArgs e)
  4.         {
  5.         try
  6.             {
  7.                 if (this.buttonKeyHook.Text == "安装键盘钩子")
  8.                 {
  9.                     k_hook = new KeyboardHook();
  10.                     k_hook.KeyDownEvent += new KeyEventHandler(hook_KeyDown);
  11.                     k_hook.Start();
  12.                     this.buttonKeyHook.Text = "卸载键盘钩子";
  13.                 }else if(k_hook!=null)
  14.                 {
  15.                     k_hook.Stop();
  16.                     this.buttonKeyHook.Text = "安装键盘钩子";
  17.                 }
  18.             }
  19.             catch (Exception ex)
  20.             {
  21.                 MessageBox.Show(ex.Message);
  22.             }
  23.         }
  24. private void hook_KeyDown(object sender, KeyEventArgs e)
  25.         {
  26.             //自己写吧 
  27.         }