【问题标题】:Low level keyboard hook delay低级键盘挂钩延迟
【发布时间】:2014-08-21 10:50:28
【问题描述】:

我目前正在用 C 编写一个需要跟踪按键和释放的库。为了达到最佳效果,我使用了一个low level keyboard hook,它调用一个回调函数来处理这些关键事件。

我遇到的问题是按键似乎被延迟了。我的程序循环执行得越慢,关键事件到达所需的时间就越长。我的回调函数将所有按下的键存储在一个数组中,稍后我可以从中轮询它们。如果程序会延迟一秒钟,那么当我之后检查它时,我希望所有关键事件都在数组中。不是这样的,这种情况下好像只存储了一个事件,剩下的在后面来。

我的回调函数如下,不相关的部分总结如下:

static LRESULT CALLBACK llKeyProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if(nCode == HC_ACTION) {
        //The keys are processed and stored in an array to be polled by the user in the future
    }

    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

钩子附加到进程(_window->llKeyHook是HHOOK类型):

_window->llKeyHook = SetWindowsHookEx(WH_KEYBOARD_LL, llKeyProc, NULL, 0);

在我的主循环中轮询关键事件。此循环的帧速率当前受到每次迭代后调用 Sleep(ms) 的限制。睡眠时间的长短由主循环的执行速度决定。当我将其设置为较高的值(如 300 毫秒)时,每 300 毫秒仅捕获一个键,即使我在其间按下了许多键。

【问题讨论】:

  • 从您链接到的文档中:“调用是通过向安装挂钩的线程发送消息来进行的。因此,安装挂钩的线程必须具有消息循环。”所以你描述的行为完全符合预期。你不应该在你的消息循环中睡觉。

标签: c winapi keyboard hook delay


【解决方案1】:

我的程序循环执行得越慢,关键事件到达所需的时间就越长。

documentation 涵盖了该问题,其中指出:

这个钩子在安装它的线程的上下文中被调用。通过向安装钩子的线程发送消息来进行调用。因此,安装钩子的线程必须有消息循环。

键盘输入可以来自本地键盘驱动程序,也可以来自对 keybd_event 函数的调用。如果输入来自对 keybd_event 的调用,则输入被“注入”。但是,WH_KEYBOARD_LL 挂钩不会注入到另一个进程中。相反,上下文切换回安装钩子的进程,并在其原始上下文中调用它。然后上下文切换回生成事件的应用程序。

钩子程序处理消息的时间应该少于在以下注册表项中的 LowLevelHooksTimeout 值中指定的数据条目:

HKEY_CURRENT_USER\控制面板\桌面

该值以毫秒为单位。如果钩子过程超时,系统将消息传递给下一个钩子。但是,在 Windows 7 及更高版本上,该挂钩会在不被调用的情况下被静默删除。应用程序无法知道挂钩是否被移除。

注意调试挂钩无法跟踪此类低级键盘挂钩。 如果应用程序必须使用低级挂钩,它应该在专用线程上运行挂钩,将工作传递给工作线程,然后立即返回。

因此,您的主应用程序接收键盘通知的速度仅与安装钩子的线程可以轮询其消息队列以获取来自钩子的新消息的速度一样快。如果您放慢轮询速度,您的通知就会延迟。

文档还指出:

在应用程序需要使用低级挂钩的大多数情况下,它应该改为监视原始输入。这是因为原始输入可以比低级挂钩更有效地异步监视针对其他线程的鼠标和键盘消息。有关原始输入的更多信息,请参阅Raw Input。

所以你应该考虑改用它。

【讨论】:

  • 感谢您澄清这一点,我又在正确的轨道上。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多