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 ?
According to the description of the SetWindowsHookExA in the official Microsoft documentation.
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.