【问题标题】:C++/Win32: Keyboard input to a non-foreground windowC++/Win32:非前台窗口的键盘输入
【发布时间】:2021-03-20 10:25:23
【问题描述】:

我的目标:

我希望我的应用程序能够响应特定的键盘快捷键/热键,无论它是否是前台窗口而不会干扰其他应用程序对这些快捷键的使用。

例如,如果另一个进程有前台窗口并且用户按下VK_MEDIA_PLAY_PAUSE 键,我希望我的应用程序和当前前台窗口做出响应。

此功能是用户设置,所以我不担心不良行为。

我尝试过但没有奏效的方法:

  1. WM_KEYDOWN 消息只发送到当前前台窗口,所以我的应用程序没有收到它们。
  2. GetKeyState(),根据the MS docs,根据最近检索到的WM_KEY*消息返回key的状态,因为我的应用没有收到WM_KEYDOWN作为后台窗口,所以这个状态不会改变。
  3. GetAsyncKeyState(),根据the MS docs,在以下情况下返回零:

前台线程属于另一个进程,桌面不允许hook或者journal记录。

我不确定这后半部分是什么意思,但是当我的窗口不是前景窗口时,GetAsyncKeyState() 返回零。

  1. GetKeyboardState() 与GetKeyState() 一样,仅在检索消息时更改密钥状态。

  2. RegisterHotKey()/UnregisterHotKey():与其他选项不同,我的应用程序能够响应热键,即使它不是前台窗口;但是,当前前台窗口不再响应。这些热键似乎只重定向到我的应用程序,而其他应用程序根本看不到它们。

我唯一的(凌乱的)想法:

我能想到的唯一方法是我相当肯定会被 Win32 社区回避的方法。

我可以使用RegisterHotKey()/UnregisterHotKey() 来通知热键,然后模拟按键到当前前台窗口。看到SendInput() 可能会进入循环,我需要先取消注册热键:

case WM_HOTKEY:
     UnregisterHotKey(...);        // unregister the hotkey to avoid looping
     SendInput(...);               // send keyboard input
     RegisterHotKey(...);          // restore it

或直接用SendMessage()模拟:

case WM_HOTKEY:
     SendMessage(GetForegroundWindow(), WM_KEYDOWN, ...);
     // send WM_KEYUP ?

这两者似乎都是 Win32 架构并非设计用于的黑客攻击。

是否有任何(其他)方法可以在不干扰其他应用程序的情况下从非前台窗口读取/接收键盘输入?

【问题讨论】:

    标签: c++ windows winapi keyboard keyboard-shortcuts


    【解决方案1】:

    您可以将SetWindowsHookEx 与WH_KEYBOARD_LL 参数一起使用:

    这是一个示例:

    #include <windows.h>
    #include <iostream>
    HHOOK _k_hook;
    LRESULT __stdcall k_Callback1(int nCode, WPARAM wParam, LPARAM lParam)
    {
        PKBDLLHOOKSTRUCT key = (PKBDLLHOOKSTRUCT)lParam;
        //a key was pressed
        if (wParam == WM_KEYDOWN && nCode == HC_ACTION)
        {
            switch (key->vkCode)
            {
            case VK_ESCAPE:
                puts("ESC pressed");
                break;
            case 'A':
                puts("A pressed");
                break;
            case VK_RETURN:
                puts("RETURN pressed");
                break;
            }
        }
    
        return CallNextHookEx(NULL, nCode, wParam, lParam);
    }
    
    
    int main()
    {
        _k_hook = SetWindowsHookEx(WH_KEYBOARD_LL, k_Callback1, NULL, 0);
        MSG msg;
        while (GetMessage(&msg, NULL, 0, 0) != 0)
        {
            TranslateMessage(&msg);
            DispatchMessageW(&msg);
        }
        if (_k_hook)
            UnhookWindowsHookEx(_k_hook);
        return TRUE;
    }
    

    它的工作原理如下:

    【讨论】:

    • 这正是我需要的,谢谢!是否还有一种方法可以检查此回调中的 control 和 shift 键的状态?如果没有,我可以没有它。
    • @TheTrueJard 尝试使用VK_LCONTROL、VK_RCONTROL、VK_LSHIFT 和VK_RSHIFT
    • 那行得通,我能够通过静态布尔值来监控它们,这些值在收到这些关键代码时会更新。谢谢!
    • 最好使用RegisterRawInputDevices并检查WindowProc中的WM_INPUT消息
    猜你喜欢
    • 2010-10-01
    • 2021-06-23
    • 2023-03-31
    • 2014-06-19
    • 1970-01-01
    • 1970-01-01
    • 2021-07-28
    • 2011-01-16
    相关资源
    最近更新 更多