Windows:如何在低级键盘挂钩中查询修饰键的状态
Windows: How to query state of modifier keys within low level keyboard hook?
对于USB键盘配置工具,我需要拦截所有键盘输入并检测同时按下了哪些修饰键和普通键。因此,我使用了一个窗口低级钩子 (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)?或者有没有另一种方法可以得到所有(inkl。赢)按下修改键?
LowLevelKeyboardProc
的文档对返回值进行了如下说明:
如果挂钩过程处理了消息,则可能会返回一个非零值 防止系统将消息传递给挂钩的其余部分 链或目标窗口过程。
因此,return 1
说"我已经处理了信息,没有其他事情应该用这些密钥做
我不确定您如何自行解决检测 WIN 键的问题 - 我怀疑系统只是在按下第二个键之前不会转发具有键盘事件的问题。
我没有找出为什么我无法从钩子中获取 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
,这是奇怪的行为。但是,如果有人发现为什么它会这样,请告诉我。
我可能迟到了,但 CTRL + ALT + DELETE 和其他序列是受保护的键序列,无法拦截或覆盖。如果我是对的,在 Windows 7 中有一些方法可以做到这一点,但据我所知,今天没有,或者它真的很难或被认为是一个漏洞。
这个问题很老,所以要从 2022 年开始做一些更新。
我遇到了同样的问题,由于我们不能在LowLevelKeyboardProc
中使用 API 函数GetAsyncKeyState
我发现的唯一方法是编写一些自定义代码:
void SetModifiers(YOUR_STRUCT_TYPE* sStruct)
{
// Get a code
auto const code = sStruct->vkCode;
// Check if key is a modifier key
bool const is_control = code == VK_CONTROL || code == VK_LCONTROL || code == VK_RCONTROL;
bool const is_alt = code == VK_MENU || code == VK_LMENU || code == VK_RMENU;
bool const is_shift = code == VK_SHIFT || code == VK_LSHIFT || code == VK_RSHIFT;
bool const is_caps_lock = code == VK_CAPITAL;
// If the key is a modifier, then set it to `true/false` if the key is `DOWN/UP`, otherwise - ignore and keep prev state(if the key is not a modifier)
// I use my custom struct here, but you can change it for global vars or something else
sStruct->control = is_control ? !sStruct->keyUp : sStruct->control;
sStruct->alt = is_alt ? !sStruct->keyUp : sStruct->alt;
sStruct->shift = is_shift ? !sStruct->keyUp : sStruct->shift;
sStruct->capsLock = is_caps_lock ? !sStruct->keyUp : sStruct->capsLock;
}
不确定它是否是最好的,但它正是我想要的。
- Mongodb c++驱动程序:如何查询元素的数组
- 查询SQLite数据库中的日期
- 如何在ArangoDb AQL查询中指定数据库
- Constexpr替代了新的放置方式,可以让内存中的对象保持未初始化状态
- 我不断收到 [错误] ID 返回 1 退出状态错误,但看不到问题所在
- OSX MetalKit CVMetalTextureCacheCreateTextureFromImage失败,状态:
- Qt SQLite没有查询或参数计数不匹配
- 如何使用c++在VS 2019上运行SQL查询
- std::future_error:无关联状态
- 从返回的顶点缓冲区查询顶点结构
- 如何避免LED在循环状态变化中闪烁?
- 以非特权用户身份查询 NTFS 特殊文件的元数据?
- C/C++ - 查询平台相关的换行符(用于内存映射文件)
- boost 是否有按特殊类型值编码状态"compact optional"?
- 为什么系统函数总是在C++中返回已转移的退出状态?
- C++ 中的编译错误:未定义对"主"的引用 collect2:错误:ld 返回 1 个退出状态
- 重新设置了以前的状态3查询
- C++ atomic_flag查询状态
- 无法删除 QSql数据库 - 查询仍处于活动状态
- Windows:如何在低级键盘挂钩中查询修饰键的状态