5

I'm using a low-level keyboard hook on windows. It works like a charme, despite of the fact that I'm currently unable to tell whether the key was initially pressed or pressed again. The documentation (+here) says, that bit 7 holds the transition state. But this seems only to be true when the key is being released. Bit 7 is sadly not set when I firstly press the key.

Is there any way to tell whether the key is pressed initially?

The Wavelength
  • 2,836
  • 2
  • 25
  • 44
  • One of the many problems with keyboard hooks, keyboard state is a per-process property. So what you get entirely depends on what process happens to own the foreground window and whether *it* has seen the key before. – Hans Passant Aug 27 '14 at 11:52
  • I know, but I don't care in this case. I expect the user to focus only my process, but I'm aware of the risk, thanks! – The Wavelength Aug 27 '14 at 12:31
  • 3
    @Hans Keyboard state is controlled per thread (or thread group, if several threads are tied together as a result of calling `AttachThreadInput`). Replacing all occurrences of *process* with *thread or thread group* fixes your comment. – IInspectable Aug 27 '14 at 14:30
  • Answer to this question can be found in this question: https://stackoverflow.com/questions/56415321/low-level-hook-setwindowshookex-lparam-auto-repeat Pretty much its too low level, and the answer below is the correct answer. – Aleksander Fular Jul 14 '21 at 00:02

1 Answers1

1

I happen to run into this problem recently. I can't find any good solutions, but I ended up using a flag and a GetAsyncKeyState before SetWindowHookEx.

BOOL wasDown;

LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode == HC_ACTION) {
        LPKBDLLHOOKSTRUCT key = (LPKBDLLHOOKSTRUCT) lParam;
        if (key->vkCode == VK_SOMETHING) {
            switch (wParam) {
                case WM_KEYDOWN:
                case WM_SYSKEYDOWN:
                    if (!wasDown) {
                        // Processing on first key down
                        wasDown = true;
                    }
                    break;
                case WM_KEYUP:
                case WM_SYSKEYUP:
                    // Processing on key up
                    wasDown = FALSE;
                    break;
            }
    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

wasDown = GetAsyncKeyState(VK_SOMETHING) < 0;
hHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, hInstance, 0);

Of course, this code only does it for one key. You can use an array of flags to do multiple keys. Depending on your application you could also unconditionally set the flag to false if you want the first press after your hook is set.

quantum
  • 3,672
  • 29
  • 51