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

大憨熊 提交于 2021-02-05 11:27:51

问题


My goal:

I want my application to be able to respond to specific keyboard shortcuts/hotkeys regardless of whether it is the foreground window without interfering with other applications' use of these shortcuts.

For instance, if another process has the foreground window and the user presses the VK_MEDIA_PLAY_PAUSE key, I want my application and the current foreground window to respond.

This function is a user setting, so I'm not concerned about undesired behavior.

Things I've tried that haven't worked:

  1. WM_KEYDOWN messages are only sent to the current foreground window, so my application does not receive them.
  2. GetKeyState(), according to the MS docs, returns the status of the key according to the most recently retrieved WM_KEY* messages, and because my application doesn't receive WM_KEYDOWN as background window, this status doesn't change.
  3. GetAsyncKeyState(), according to the MS docs, returns zero when:

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

I'm not sure what the second half of this means, but GetAsyncKeyState() returns zero when my window is not the foreground window.

  1. GetKeyboardState(), like GetKeyState(), only changes key status as messages are retrieved.

  2. RegisterHotKey()/UnregisterHotKey(): Unlike the other options, my application is able to respond to hotkeys even when it's not the foreground window; however, the current foreground window no longer responds. It appears that these hotkeys are redirected to only my application, and other applications no longer see them at all.

My only (messy) idea:

The only approaches I can think of are ones that I'm fairly certain would have me shunned by the Win32 community.

I could use RegisterHotKey()/UnregisterHotKey() to be notified of the hotkey, and then emulate the keypress to the current foreground window. Seeing as SendInput() would likely enter a loop, I would need to either unregister the hotkey first:

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

or emulate it directly with SendMessage():

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

Both of these seem like a hack that the Win32 architecture was not designed for.

Is there any (other) way to read/receive keyboard input from a non-foreground window without interfering with other applications?


回答1:


You can use SetWindowsHookEx with WH_KEYBOARD_LL parameter:

Here is a sample:

#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;
}

It works as follows:



来源:https://stackoverflow.com/questions/65210101/c-win32-keyboard-input-to-a-non-foreground-window

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!