C++/Win32:非前台的键盘输入 window

C++/Win32: Keyboard input to a non-foreground window

我的目标:

我希望我的应用程序能够响应特定的键盘shortcuts/hotkeys,无论它是否是前台window而不干扰其他应用程序'使用这些快捷方式。

例如,如果另一个进程有前台 window 并且用户按下 VK_MEDIA_PLAY_PAUSE 键,我希望我的应用程序 当前前台 window 回复。

此功能是一项用户设置,因此我不担心出现不良行为。

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

  1. WM_KEYDOWN消息只发送到当前前台window,所以我的应用程序没有收到它们。
  2. GetKeyState(),根据the MS docs,returns密钥的状态根据最近检索到的WM_KEY*消息,因为我的应用没有收到WM_KEYDOWN作为背景window,此状态不变。
  3. GetAsyncKeyState(),根据the MS docs,returns归零时:

The foreground thread belongs to another process and the desktop does not allow the hook or the journal record.

我不确定后半部分是什么意思,但是当我的 window 不是前景时 GetAsyncKeyState() returns 零 window.

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

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

我唯一(凌乱)的想法:

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

我可以使用 RegisterHotKey()/UnregisterHotKey() 来通知热键,然后将按键模拟到当前前台 window。鉴于 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 体系结构并非设计用于的 hack。

是否有任何(其他)方法可以从非前台 window read/receive 键盘输入而不干扰其他应用程序?

您可以将 SetWindowsHookExWH_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;
}

它的工作原理如下: