键盘挂钩改变键的行为

我正在创build一个安装键盘钩子的程序来捕获所有键并显示一些与它们相关的文本。

但是,我遇到了一个障碍,这是一些键更改行为,当安装钩。

我会看到发布一个小的,但完整的testing程序,但现在我只是描述了这个问题。

这个问题展现在Windows 7 64位,.NET 4.0(一个C#程序)上。 我认为这些都不重要。

我的钩子通过SetWindowsHookEx自行安装,然后处理在系统中处理的所有密钥。

如果钩子方法简单地返回,或者对键的最小处理(我将发布什么改变了一秒钟的行为),则键盘按照预期在程序中起作用。

但是,如果我从User32.dll中调用这个函数ToAscii ,找出我的键盘上的OemTilde或类似的键,那么任何“覆盖下一个键”的键将停止运行。 我不知道这样的键的正确名称,但是两个撇号types,“和” , as well asand ¨,都不起作用。

例如,如果我点击~然后是N ,则显示如下:

  • 没有安装键盘挂钩:
  • 随着键盘挂钩安装:n(通知no〜以上)

有谁知道为什么发生这种情况,我怎么能解决这个问题?

现在我只好在其他程序中正确处理密钥,即使这意味着我将无法在自己的程序中正确检测到正确的密钥序列。

一些更多的信息:

如果我将ToAscii函数作为钩子方法的一部分,则会出现不同的问题。 像¨键是处理两次,即。 如果我打了¨一次,记事本收到两个¨¨字符,现在打N只是加了N

但是,如果我使用BeginInvoke来处理单独的线程上的键,键盘钩子方法返回后,第一个问题发生。


我的程序可能有点特别:

  • 我不使用键盘状态(即我传递的“键状态”256字节数组只是满了0)
  • 我不在乎死钥匙(在我的程序不会处理它们的意义上,我只关心他们,我不希望我的程序使它们对系统的其他部分无用)

就这样,我的代码最终看起来如下:

 private bool IsDeadKey(uint key) { return ((Hook.Interop.MapVirtualKey(key, 2) & 2147483648) == 2147483648); } void _Hook_KeyDown_Async(KeyDownEventArgs e) { var inBuffer = new byte[2]; char key = '\0'; if (!IsDeadKey((uint)e.KeyCode)) { int ascii = Hook.Interop.ToAscii((int) e.KeyCode, e.ScanCode, _KeyState, inBuffer, e.Flags); if (ascii == 1) { key = Char.ToUpper((char) inBuffer[0]); } } BeginInvoke( new Action<Keys, Boolean, Boolean, Boolean, Char>(ProcessKeyboardEvent), e.KeyCode, e.Control, e.Shift, e.Alt, key); } 

Solutions Collecting From Web of "键盘挂钩改变键的行为"

这些密钥称为ToAscii ,您可以通过删除对ToAscii的调用来解决问题。 另请参阅以下相关主题:

在键盘挂钩ToAscii / ToUnicode销毁死锁。

更新:我没有看到你的代码,但是当处理KeyboardProc回调函数的参数时,你能否检查你在code参数小于0时是否传递了键盘消息? 该文件说:

代码 [in] int

钩子程序用来确定如何处理消息的代码。 如果代码小于零,则挂钩过程必须将消息传递给CallNextHookEx函数而不作进一步处理,并应返回由CallNextHookEx返回的值。

有一个在MSDN中设置托管钩子的示例:

 if (nCode < 0) { return CallNextHookEx(hHook, nCode, wParam, lParam); } else { // process message here return CallNextHookEx(hHook, nCode, wParam, lParam); } 

您的问题中缺少一些关键信息,您使用的是两个键盘钩子中的哪一个? 简单的,WH_KEYBOARD_LL不能工作。 您最终会使用程序的键盘状态,而不是实际获得按键的程序。 死钥匙确实有所作为。

困难的WH_KEYBOARD需要一个钩子,你不能在托管代码中写入。 您将需要一个可以在每个进程中注入的非托管DLL。 一旦你明白了,我只是不打扰一个键盘挂钩,不妨用WH_CALLWNDPROC记录WM_CHAR消息。

一个示例DLL 在这里可用。

你可能在这里看到的是试图映射一个密钥时,死锁的影响。 键盘映射是一个相当复杂的过程,在产生这种行为的某些类型的键周围有许多陷阱。

我鼓励你阅读Michael Kaplan关于这个主题的以下博客系列。 它帮助我理清了一些错误。

鉴于目前的答案和对国际行为的参考,您可能需要考虑“编码”。 代码页根据国家而改变。

示例国家代码页

  • 美国,英国437
  • 多语言850
  • 斯拉夫852
  • 葡萄牙语860
  • 冰岛861
  • 加拿大,法国863
  • 斯堪的纳维亚/北欧865

更多信息

MSDN信息

Windows应用程序国际化