【问题标题】:Determine which window the message was sent (SetWindowsHookEx & WH_KEYBOARD)确定消息发送到哪个窗口(SetWindowsHookEx & WH_KEYBOARD)
【发布时间】:2022-01-09 08:51:12
【问题描述】:

我需要能够确定消息要发送到哪个窗口,但我不明白如何正确执行。在WH_MOUSE 中有一个特殊的结构(MOUSEHOOKSTRUCT)存储了窗口的hwnd,但是在WH_KEYBOARD 哪里可以得到hwnd?

LRESULT CALLBACK messageHandler(int nCode, WPARAM wParam, LPARAM lParam)
{
    // ???
}
 
DWORD WINAPI messageDispatcher(LPVOID thread)
{
    hookHandle = SetWindowsHookEx(WH_KEYBOARD, messageHandler, GetModuleHandle(nullptr), *reinterpret_cast<DWORD*>(thread));
 
    if (!hookHandle)
    {
        return GetLastError();
    }
 
    MSG message{};
 
    while (GetMessage(&message, 0, 0, 0) > 0)
    {
        TranslateMessage(&message);
        DispatchMessage(&message);
    }
 
    return 0;
}

理论上,我可以使用GetForegroundWindow,但在我看来,这是一个糟糕的选择,因为窗口可以从其他进程接收键盘消息(如果另一个进程向该窗口发送SendMessage)而不是当前窗口正是消息所针对的窗口这一事实。

【问题讨论】:

  • WH_KEYBOARD_LL 是一个全局挂钩。有了这个,一切对我来说都是正确的,因为我需要来自创建窗口的特定线程的消息。

标签: c++ c winapi setwindowshookex


【解决方案1】:

在生成键盘操作时,操作系统还不知道哪个窗口最终会收到该消息。这就是为什么WH_KEYBOARD 钩子没有像WH_MOUSE 钩子那样提供目标HWND(因为鼠标消息带有与窗口相关的坐标)。

当键盘消息被路由到目标时,消息被传递到当前具有输入焦点的窗口。

About Keyboard Input:

系统将键盘消息发送到前台线程的消息队列,该线程创建了具有键盘焦点的窗口。键盘焦点是窗口的临时属性。系统通过在用户的方向上将键盘焦点从一个窗口转移到另一个窗口,在显示器上的所有窗口之间共享键盘。具有键盘焦点的窗口(从创建它的线程的消息队列)接收所有键盘消息,直到焦点更改到另一个窗口。

由于你的钩子在目标线程的消息队列中运行,你可以使用GetFocus()来获取目标HWND

如果窗口附加到调用线程的消息队列,则检索具有键盘焦点的窗口的句柄。

否则,您可以改用WH_CALLWNDPROC/RET 挂钩,它会在消息实际传递到窗口时被调用。但是,您不能使用此挂钩阻止消息(正如您在 previous question 中询问的那样)。

【讨论】:

  • 据我所知,WH_CALLWNDPROC 根本没有注册键盘(我已经尝试过一次,然后切换到 WH_GETMESSAGE,我在上一个问题中问过)将尝试 GetFocus,希望对您有所帮助。谢谢!
  • WH_CALLWNDPROC 根本不注册键盘*" - 应该。WH_GETMESSAGE 在消息被分派到窗口之前,为从线程的消息队列中检索到的每条已发布消息调用. WH_CALLWNDPROC 为传递到窗口的每条消息调用,无论是已发送消息还是已发送的已发送消息。
【解决方案2】:

我认为您可能正在寻找的是WH_JOURNALRECORD 类型的钩子。

这样,Windows 为响应该钩子拦截的各种事件而调用的回调过程是JournalRecordProc 类型,传递给该函数的lparam 参数指向一个EVENTMSG 结构,看起来像这样:

typedef struct tagEVENTMSG {
  UINT  message;
  UINT  paramL;
  UINT  paramH;
  DWORD time;
  HWND  hwnd;
} EVENTMSG;

还有你的hwnd

【讨论】:

  • 日志挂钩用于记录用户输入,然后稍后播放。这不是这种情况下所需要的。
  • 不幸的是,这是一个全局钩子。我需要来自创建窗口的特定线程的消息。
猜你喜欢
  • 2012-02-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-11
  • 2019-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多