C++/Win32:非前台的键盘输入 window
C++/Win32: Keyboard input to a non-foreground window
我的目标:
我希望我的应用程序能够响应特定的键盘shortcuts/hotkeys,无论它是否是前台window而不干扰其他应用程序'使用这些快捷方式。
例如,如果另一个进程有前台 window 并且用户按下 VK_MEDIA_PLAY_PAUSE
键,我希望我的应用程序 和 当前前台 window 回复。
此功能是一项用户设置,因此我不担心出现不良行为。
我尝试过但没有奏效的方法:
WM_KEYDOWN
消息只发送到当前前台window,所以我的应用程序没有收到它们。
GetKeyState()
,根据the MS docs,returns密钥的状态根据最近检索到的WM_KEY*
消息,因为我的应用没有收到WM_KEYDOWN
作为背景window,此状态不变。
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.
GetKeyboardState()
,与 GetKeyState()
一样,仅在检索消息时更改密钥状态。
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 键盘输入而不干扰其他应用程序?
您可以将 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;
}
它的工作原理如下:
我的目标:
我希望我的应用程序能够响应特定的键盘shortcuts/hotkeys,无论它是否是前台window而不干扰其他应用程序'使用这些快捷方式。
例如,如果另一个进程有前台 window 并且用户按下 VK_MEDIA_PLAY_PAUSE
键,我希望我的应用程序 和 当前前台 window 回复。
此功能是一项用户设置,因此我不担心出现不良行为。
我尝试过但没有奏效的方法:
WM_KEYDOWN
消息只发送到当前前台window,所以我的应用程序没有收到它们。GetKeyState()
,根据the MS docs,returns密钥的状态根据最近检索到的WM_KEY*
消息,因为我的应用没有收到WM_KEYDOWN
作为背景window,此状态不变。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.
GetKeyboardState()
,与GetKeyState()
一样,仅在检索消息时更改密钥状态。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 键盘输入而不干扰其他应用程序?
您可以将 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;
}
它的工作原理如下: