首页 文章

Windows:如何在低级键盘钩子中查询修改键的状态?

提问于
浏览
2

对于USB键盘配置工具,我需要截取所有键盘输入并检测同时按下哪些修改键和普通键 . 因此我使用一个Windows低级挂钩(WH_KEYBOARD_LL)工作正常,但我无法确定是否按下了WIN-Key(VK_LWIN / VK_RWIN)(控制/移位和alt工作) .

我做了一个小命令行工具来显示问题:

#include <Windows.h>
#include <iostream>

using namespace std;

HHOOK hKeyboardHook;


LRESULT CALLBACK LowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam )
{
    if (nCode < 0 || nCode != HC_ACTION )
        return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam);

    KBDLLHOOKSTRUCT* p = (KBDLLHOOKSTRUCT*)lParam;

    if(wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)
    {
        // working
        if(GetAsyncKeyState(VK_CONTROL) & 0x8000)
            cout << "CONTROL" << endl;
        if(GetAsyncKeyState(VK_SHIFT) & 0x8000)
            cout << "SHIFT" << endl;
        if(GetAsyncKeyState(VK_MENU) & 0x8000) // ALT
            cout << "ALT" << endl;

        // VK_xWIN not working at all
        if((GetAsyncKeyState(VK_LWIN) & 0x8000) || (GetAsyncKeyState(VK_RWIN) & 0x8000))
            cout << "WIN" << endl;

        // working for ALTGR/right-handed ALT
        if((GetAsyncKeyState(VK_LCONTROL) & 0x8000) || (GetAsyncKeyState(VK_RCONTROL) & 0x8000))
            cout << "LRCONTROL" << endl;

        // not working at all
        if((GetAsyncKeyState(VK_LSHIFT) & 0x8000) || (GetAsyncKeyState(VK_RSHIFT) & 0x8000))
            cout << "LRSHIFT" << endl;
        if((GetAsyncKeyState(VK_LMENU) & 0x8000) || (GetAsyncKeyState(VK_RMENU) & 0x8000))
            cout << "LRMENU" << endl;
    }

    //return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam);
    return 1;
}



int main(int argc, char* argv[])
{
    hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0 );

    MSG message;
    while (GetMessage(&message,NULL,0,0)) {
        TranslateMessage( &message );
        DispatchMessage( &message );
    }

    UnhookWindowsHookEx(hKeyboardHook);
    return 0;
}

如果我从LowLevelKeyboardProc返回“1”,则每次按键都被“吞下”(除了CTRL ALT DEL和WIN L) . 如果我在回调函数结束时调用下一个钩子,行为就会改变(并且键显然不会被吞下) . 然后,如果将WIN键与另一个键一起按下,我将获得按下WIN键的信息 .

我该怎么做才能拦截所有键盘输入并检测WIN键按下(使用GetAsyncKeyState)?或者是否有其他方法可以获得所有(墨水.WIN)按下的修改键?

2 回答

  • 0

    LowLevelKeyboardProc 的文档说明了关于返回值的以下内容:

    如果钩子过程处理了消息,它可能会返回非零值以防止系统将消息传递给钩子链的其余部分或目标窗口过程 .

    所以 return 1 说"I've processes the information, and there is nothing else that should be done with these keys" .

    我不确定你是如何通过自己检测WIN键来解决问题的 - 我怀疑系统只是简单地没有转发有键盘事件,直到按下第二个键 .

  • 0

    我没有找到为什么我无法从钩子中获取Windows键的状态,但是我实现了一个简单的解决方法,我不想让你退缩 .

    如果我按下/释放Windows键,则会调用回调函数 . 所以我只是自己保存密钥的状态,并在按下按键时使用这些信息 .

    所以更改后的回调函数如下所示:

    bool leftWinKeyPressed = false;
    bool rightWinKeyPressed = false;
    
    LRESULT CALLBACK LowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam )
    {
        if (nCode < 0 || nCode != HC_ACTION )
            return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam);
    
        KBDLLHOOKSTRUCT* p = (KBDLLHOOKSTRUCT*)lParam;
    
        // save state of win keys manually... (needs to be tested some more)
        if(p->vkCode == VK_LWIN)
            leftWinKeyPressed = (wParam == WM_KEYDOWN)?true:false;
        else if(p->vkCode == VK_RWIN)
            rightWinKeyPressed = (wParam == WM_KEYDOWN)?true:false;
    
        if(wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)
        {
            // not beautifull but working...
            if(leftWinKeyPressed || rightWinKeyPressed)
                cout << "WIN" << endl;
    
            // for example
            if(leftWinKeyPressed && p->vkCode == 68 )
                cout << "LEFT WINDOWS + D";
        }
    
        return 1;
    }
    

    为了清理它,我可能会对所有修改键执行此操作,并使用位字段来存储修改键的状态 . 所以我不依赖于 GetAsyncKeyState ,这是奇怪的行为 . 但如果有人发现它为什么会这样,请告诉我 .

相关问题