c++cwinapisetwindowshookex

Determine which window the message was sent (SetWindowsHookEx & WH_KEYBOARD)


I need to be able to determine which window the message is intended for, but I don’t understand how to do it correctly. In WH_MOUSE has a special structure (MOUSEHOOKSTRUCT) that stores the hwnd of the window, but where to get the hwnd in WH_KEYBOARD?

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;
}

In theory, I could use GetForegroundWindow, but it seems to me that this is a terrible option, because the window can receive a keyboard message from some other process (if another process sends a SendMessage to this window) and not the fact that the current window will be exactly the one for which the message was intended.


Solution

  • At the time a keyboard action is generated, the OS doesn't know yet which window will eventually receive the message. That is why the WH_KEYBOARD hook doesn't provide a target HWND, like a WH_MOUSE hook does (since a mouse message carries window-related coordinates).

    When a keyboard message is being routed to a target, the message gets delivered to the window that currently has input focus.

    Per About Keyboard Input:

    The system posts keyboard messages to the message queue of the foreground thread that created the window with the keyboard focus. The keyboard focus is a temporary property of a window. The system shares the keyboard among all windows on the display by shifting the keyboard focus, at the user's direction, from one window to another. The window that has the keyboard focus receives (from the message queue of the thread that created it) all keyboard messages until the focus changes to a different window.

    Since your hook runs inside of the message queue of the target thread, you can use GetFocus() to get the target HWND at that time:

    Retrieves the handle to the window that has the keyboard focus, if the window is attached to the calling thread's message queue.

    Otherwise, you can use a WH_CALLWNDPROC/RET hook instead, which gets called when the message is actually delivered to a window. However, you can't block messages with this hook (as you were asking about in your previous question).