AutoCAD 3DMAX C语言 Pro/E UG JAVA编程 PHP编程 Maya动画 Matlab应用 Android
Photoshop Word Excel flash VB编程 VC编程 Coreldraw SolidWorks A Designer Unity3D
 首页 > .NET技术

C#+低级Windows API钩子拦截键盘输入

51自学网 http://www.51zixue.net

  五. 处理KeyIntercepted事件

  当一外键被按下时,这个KeyboardHook类激活一个包含一些KeyboardHookEventArgs的KeyIntercepted事件。这是通过一个KeyboardHookEventHandler类型的方法使用以下方式来实现的:

kh.KeyIntercepted += new KeyboardHook.KeyboardHookEventHandler(kh_KeyIntercepted);

  这个KeyboardHookEventArgs返回关于被按下键的下列信息:

  · KeyName:键名,通过把捕获的键代码强制转换为System.Windows.Forms.Keys而获得。

  · KeyCode:由键盘钩子返回的原来的键代码

  · PassThrough:指出是否这个KeyboardHook实例被配置以允许该击键传递到其它应用程序。如果你想允许一用户使用Alt+Tab或 Ctrl+Esc/Windows键切换到其它的应用程序的话,那么对之进行检查是很有用的。

  然后,使用一个具有适当签名的方法来执行击键所调用的任何任务。下面是一个示例片断:

void kh_KeyIntercepted(KeyboardHookEventArgs e)
{
 //检查是否这个键击事件被传递到其它应用程序并且停用TopMost,以防他们需要调到前端
 if (e.PassThrough)
 {
  this.TopMost = false;
 }
 ds.Draw(e.KeyName);
}

  本文的剩下部分将解释低级键盘钩子是如何在KeyboardHook中实现的。

  六. 实现一个低级Windows API键盘钩子

  在user32.dll中,Windows API包含三个方法来实现此目的:

  · SetWindowsHookEx,它负责建立键盘钩子

  · UnhookWindowsHookEx,它负责移去键盘钩子

  · CallNextHookEx,它负责把击键信息传递到下一个监听键盘事件的应用程序

  创建一个能够拦截键盘的应用程序的关键是,实现前面两个方法,而"放弃"第三个。结果是,任何击键都只能传递到这个应用程序中。

  为了实现这一目标,第一步是包括System.Runtime.InteropServices命名空间并且导入API方法,首先是SetWindowsHookEx:

using System.Runtime.InteropServices
...
//在类内部:
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

  导入UnhookWindowsHookEx和CallNextHookEx的代码请见后面的讨论。

  下一步是调用SetWindowsHookEx来建立钩子,这时需要传递下列四个参数:

  · idHook:

  这个数字决定了要建立的钩子的类型。例如,SetWindowsHookEx可以被用于钩住鼠标事件(当然还有其它事件)。在本文情况下,我们仅对13有兴趣,这是键盘钩子的id。为了使代码更易读些,我们把它赋值给一个常数WH_KEYBOARD_LL。

  · Lpfn:

  这是一个指向函数的长指针,该函数将负责处理键盘事件。在C#中,"指针"是通过传递一个代理类型的实例而获得的,从而使之引用一个适当的方法。这是我们在每次使用钩子时所调用的方法。

  这里值得注意的是,这个代理实例需要被存储于这个类的一个成员变量中。这是为了防止一旦第一个方法调用结束它会被作为垃圾回收。

  · hMod:

  建立钩子的应用程序的一个实例句柄。我找到的绝大多数实例仅把它设置为IntPtr.Zero,理由是不大可能存在该应用程序的多个实例。然而,这部分代码使用了来自于kernel32.dll的GetModuleHandle来标识准确的实例从而使这个类更具灵活性。

  · dwThreadId:

  当前进程的id。把它设置为0可以使这个钩子成为全局构子,这是相应于一个低级键盘钩子的正确设置。

  SetWindowsHookEx返回一个钩子id,这个id将被用于当应用程序结束时从钩子链中脱钩,因此它需要存储在一个成员变量中以备将来使用。KeyboardHook类中的相关代码如下:

private HookHandlerDelegate proc;
private IntPtr hookID = IntPtr.Zero;
private const int WH_KEYBOARD_LL = 13;
public KeyboardHook()
{
 proc = new HookHandlerDelegate(HookCallback);
 using (Process curProcess = Process.GetCurrentProcess())
 using (ProcessModule curModule = curProcess.MainModule)
 {
  hookID = SetWindowsHookEx(WH_KEYBOARD_LL, proc,GetModuleHandle(curModule.ModuleName), 0);
 }
}

 

 
 

上一篇:叩开C#之门系列之几个重要名词  下一篇:VC#2005快速入门之使用while语句