Win32 keyboardHook Callback receiving VK_LCTRL event whenever the top window is changed

177 Views Asked by At

I am using the Windows API on Windows7 with Visual Studio 2019.

I'm trying to set a low level keyboard hook and read the key input to the console, to do so I use the function: HHOOK SetWindowsHookExA( [in] int idHook, [in] HOOKPROC lpfn, [in] HINSTANCE hmod, [in] DWORD dwThreadId ) with the argument: WH_KEYBOARD_LL so I can monitor keyboard events.

This is my main function:

int main()
{
    ...

    HHOOK keyBoardHook = SetWindowsHookExW(WH_KEYBOARD_LL, keyboardHook, NULL, 0);
    
    MSG message;

    while (true)
    {
        while(PeekMessage(&message, NULL, 0, 0, PM_REMOVE) != 0)
        {
            DispatchMessage(&message);
        }
    }

    ...

    UnhookWindowsHookEx(keyBoardHook);

    return 0;
}

And this is the callback implementation:

LRESULT CALLBACK keyboardHook(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode == HC_ACTION)
    {
        KBDLLHOOKSTRUCT* keyData = (KBDLLHOOKSTRUCT*)lParam;

        if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)
        {
            fileHandler.addStr(keyHandler.translate(keyData,true,topWindowThreadId));
        }
        else if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP)
        {
            fileHandler.addStr(keyHandler.translate(keyData,false,topWindowThreadId));
        }
    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

How both variables work is not the issue here but just know that in the callback keyHandler translates the message and fileHandler prints the result to a file.

Here comes the issue. The callback receives:

  • a key down event when I press a key

  • a key up event when I release

  • a repeated key down event when I hold a key

  • a control key up event VK_LCONTROL when focused window changes

Why does that happen ? This behavior is never mentioned in the MSDN documentation as far as I know. If I switch from console window or any window to any other window this event is generated and a [left control up] message is printed by my keyHandler !

Now to make sure it's not a problem with my code I changed the Callback to this:

LRESULT CALLBACK keyboardHook(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode == HC_ACTION)
    {
        KBDLLHOOKSTRUCT* keyData = (KBDLLHOOKSTRUCT*)lParam;
        
        if (keyData->vkCode == VK_LCONTROL)
        {
            printf("CTRL");
        }
    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

And still CTRL is printed to the consol whenever I change the focused window, Note that only VK_LCONTROL is generated and wParam is always WM_KEYUP

This is not supposed to happen!

I tried analyzing and modifying my code, tried removing everything from the main function until it looked just like in the example above even rebooted the computer to check if it's an internal issue, nothing helps. and when searching the web for a similar post with a similar issue I found absolutely none, which makes it even more confusing.

Update

I tried compiling someone else's keyboard-hook related code from GitHub, same issue.. is this normal ? Why is it not documented ?

1

There are 1 best solutions below

0
On

According to the description of the SetWindowsHookExA in the official Microsoft documentation.

The global hooks are a shared resource, and installing one affects all applications in the same desktop as the calling thread. All global hook functions must be in libraries. Global hooks should be restricted to special-purpose applications or to use as a development aid during application debugging. Libraries that no longer need a hook should remove its hook procedure.

HHOOK SetWindowsHookExA(

[in] int idHook,

[in] HOOKPROC lpfn,

[in] HINSTANCE hmod,

[in] DWORD dwThreadId

);

For desktop apps, if this parameter(dwThreadId) is zero, the hook procedure is associated with all existing threads running in the same desktop as the calling thread. That's why after you changed the focused window, CTRL still printed to the console. So it is recommended that you use hook in DLL.