Использование KBDLLHOOKSTRUCT для определения первого нажатия клавиши

Я использую низкоуровневый хук клавиатуры в Windows. Это работает как шарм, несмотря на то, что в настоящее время я не могу сказать, была ли клавиша нажата изначально или нажата снова. документация ( +здесь) говорит, что бит 7 содержит переходное состояние. Но это кажется правдой только тогда, когда ключ отпускается. К сожалению, бит 7 не установлен, когда я впервые нажимаю клавишу.

Есть ли способ узнать, была ли клавиша нажата изначально?


person The Wavelength    schedule 27.08.2014    source источник
comment
Одна из многих проблем с клавиатурными перехватчиками — состояние клавиатуры — свойство каждого процесса. То, что вы получите, полностью зависит от того, какому процессу принадлежит окно переднего плана и видел ли он ключ раньше.   -  person Hans Passant    schedule 27.08.2014
comment
Я знаю, но в данном случае мне все равно. Я ожидаю, что пользователь сосредоточится только на моем процессе, но я осознаю риск, спасибо!   -  person The Wavelength    schedule 27.08.2014
comment
@Hans Состояние клавиатуры контролируется для каждого потока (или группы потоков, если несколько потоков связаны вместе в результате вызова AttachThreadInput). Замена всех вхождений процесса на поток или группу потоков исправит ваш комментарий.   -  person IInspectable    schedule 27.08.2014
comment
Ответ на этот вопрос можно найти в этом вопросе: stackoverflow.com/questions/56415321/ В значительной степени это слишком низкий уровень, и ответ ниже является правильным ответом.   -  person Aleksander Fular    schedule 14.07.2021


Ответы (1)


Недавно я столкнулся с этой проблемой. Я не могу найти хороших решений, но в итоге я использовал флаг и GetAsyncKeyState перед 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);

Конечно, этот код делает это только для одного ключа. Вы можете использовать массив флагов для выполнения нескольких ключей. В зависимости от вашего приложения вы также можете безоговорочно установить флаг на false, если вы хотите, чтобы первое нажатие было установлено после того, как ваш хук установлен.

person quantum    schedule 28.08.2014
comment
Это именно то, что я делаю сейчас, пока кто-нибудь не опубликует лучшее решение. Спасибо! - person The Wavelength; 28.08.2014