SetWindowsHookEx 在快速输入或键盘按钮按住时冻结

Posted

技术标签:

【中文标题】SetWindowsHookEx 在快速输入或键盘按钮按住时冻结【英文标题】:SetWindowsHookEx freezes on fast input or keyboard button hold 【发布时间】:2014-08-22 15:05:46 【问题描述】:

我遇到了键盘记录器的问题。直到今天测试的每个系统都运行良好,除了一个 Windows 7 Embedded Standard 32 位,它显然与当前的构建版本不同。

我需要做的是记录从键盘输入的击键,直到获得一定数量的击键。当我这样做时,我会调用某个程序。

我有一个这样定义的钩子:

SetWindowsHookEx(WH_KEYBOARD_LL, keyboardProcedure, GetModuleHandle(NULL), 0);

还有一个keyboardProcedure回调:

LRESULT CALLBACK SystemKeyboardReadWrite::keyboardProcedure(int nCode, WPARAM wParam, LPARAM lParam)

   ... 

我正在为这个应用程序使用 Qt 5.2。

因此,更深入地讲,当您输入键太快或按住某个键的时间较长时,就会出现问题,这将迫使键盘发送多个键盘事件。发生这种情况时,钩子将冻结并且不再向回调发送任何事件。 (不是整个应用程序,应用程序仍会继续运行,但键盘记录器除外)

此问题仅在此操作系统上发生,在其他 Windows 7 操作系统或 Windows XP 上我没有注意到此问题。我有 2 台具有相同设置的计算机,它们都显示相同的问题,而且我正在 Windows 7 专业版上开发该应用程序,它看起来也很好。 我想知道这是我的应用程序的问题,还是我无法控制的问题。

感谢大家的帮助。

【问题讨论】:

从给定的签名来看,看起来你的钩子过程是一个类中的 member 函数。那不应该奏效。如果它是在类中定义的,它必须是一个静态函数。我假设您只是忽略了复制和粘贴 static 修饰符?除此之外,这个问题的通常原因是在钩子过程中做了太多的工作。你没有向我们展示它包含的任何代码,所以我们只能猜测。不过,当然应该在其他系统上引起问题。无论如何,我都不是嵌入式 Windows 方面的专家。很难想象有什么不同。 我粘贴了 .cpp 文件中的代码。但是,是的,这是一个静态方法,这是标题中的定义。 static LRESULT CALLBACK keyboardProcedure(int nCode, WPARAM wParam, LPARAM lParam);。我只粘贴了解决问题所需的基本内容,我计算了一个小型构建,回调的内容相对较小,问题仍然存在,因此回调中的细节无关紧要。不过感谢您的关注 【参考方案1】:

我不了解 Windows Embedded,但我熟悉 Windows 7 和 LowLevel Hooks,包括鼠标和键盘。

可以使用 LowLevelHooksTimeOut 注册表值减少/修改被踢出钩子列表的症状。修改后必须重新启动系统。基本上,该值表示钩子必须与键交互的毫秒数。

如果你也从钩子方法中编写文件,那也可能是它超时的确切时间。

例如,您获得 100 次击键,然后将其写入文件。如果他们按住 100 到 101+ 之间的键,并且您使用挂钩的时间超过了最大时间,那么 Windows 会将您的挂钩回调列入黑名单并将您从挂钩列表中踢出。

我认为 Windows 7(桌面)的默认时间是 200 毫秒。对于嵌入式,如果它更少,我不会感到惊讶。此外,当多个程序都在钩住键盘时,它会影响允许钩子访问它的时间。

我也只真正使用了在 dll 中建立的钩子,并持有一个全局 HHOOK 句柄。观察你的函数的所有返回码也可以对情况有所了解。

有关 LowLevelHooksTimeout 的更多信息:

Low level Keyboard Hook works on one on Windows 7 x64 and not another

【讨论】:

谢谢,很有用!我将尝试更改注册表值,看看它是否有效。我会在几个小时内告诉你。再次感谢:) 另外作为一个潜在的解决方案,我会尝试从不同的线程运行键盘挂钩,这会有所不同吗?我注意到这是一个潜在的解决方案:social.msdn.microsoft.com/Forums/windowsdesktop/en-US/… 谢谢你的意见 :) 是的。除了在 DLL 中运行之外,我总是在单独的高优先级线程中启动和运行我的钩子。 哦,好的。你能找到一个例子来说明这一点吗? Qt 可以很好地处理线程。阅读 QThread,您应该能够做到。

以上是关于SetWindowsHookEx 在快速输入或键盘按钮按住时冻结的主要内容,如果未能解决你的问题,请参考以下文章

SetWindowsHookEx - 防病毒问题

无法在 Borland C++ Builder 中使用 SetWindowsHookEx 和 LowLevelKeyboardProc

SetWindowsHookex Global 不是很全球化

调用 SetWindowsHookEx() 的应用程序能否捕获自动完成 URL 和密码?

怎么使C语言程序在后台运行并接收键盘输入?

手把手教你用SetWindowsHookEx做一个键盘记录器