C++使用Windows LLKeyboard Hook实现组合键检测的异常排查
异常产生原因
- 核心问题是
GetAsyncKeyState返回值的判断逻辑错误:该函数返回short类型的结果,两个有效位对应不同含义:- 最高位(值为
0x8000)为1:代表当前时刻目标按键处于按下状态 - 最低位(值为
0x0001)为1:代表上一次调用GetAsyncKeyState之后目标按键曾经被按下过,哪怕当前已经完全松开
- 最高位(值为
- 你当前的代码直接写
if(GetAsyncKeyState(VK_LCONTROL)),只要最低位为1(即之前按过左Ctrl,不管现在是否松开),整个判断条件就为真,就会触发组合键判定,因此出现松开左Ctrl后按X/V仍然触发的异常。
修复方案
方案1:修改判断逻辑(最小代码改动)
仅需给GetAsyncKeyState的返回值增加& 0x8000的位与判断,仅当左Ctrl当前真实处于按下状态时才触发逻辑,修改后的代码如下:
HHOOK hookHandle; KBDLLHOOKSTRUCT hookdata; LRESULT __stdcall HookCallback(int code, WPARAM wparam, LPARAM lparam) { if (code >= 0) { if (wparam == WM_KEYDOWN) { hookdata = *((KBDLLHOOKSTRUCT*)lparam); switch(hookdata.vkCode) { case(88): // 仅判断最高位,确认左Ctrl当前按下 if(GetAsyncKeyState(VK_LCONTROL) & 0x8000) { std::cout<<"CTRL X PRESSED"; } break; case (86): // 仅判断最高位,确认左Ctrl当前按下 if(GetAsyncKeyState(VK_LCONTROL) & 0x8000) { std::cout<<"CTRL V PRESSED"; } break; } } } return CallNextHookEx(hookHandle, code, wparam, lparam); }
方案2:自主维护按键状态(更稳定)
GetAsyncKeyState取的是调用瞬间的系统按键状态,极端场景下可能存在时序偏差,你可以通过钩子事件自主维护左Ctrl的按下状态,判断精度更高:
HHOOK hookHandle; KBDLLHOOKSTRUCT hookdata; // 新增全局变量存储左Ctrl按下状态 bool g_isLCtrlPressed = false; LRESULT __stdcall HookCallback(int code, WPARAM wparam, LPARAM lparam) { if (code >= 0) { hookdata = *((KBDLLHOOKSTRUCT*)lparam); // 先更新左Ctrl的按下状态 if (hookdata.vkCode == VK_LCONTROL) { if (wparam == WM_KEYDOWN) { g_isLCtrlPressed = true; } else if (wparam == WM_KEYUP) { g_isLCtrlPressed = false; } } // 处理组合键判定 if (wparam == WM_KEYDOWN) { switch(hookdata.vkCode) { case(88): if(g_isLCtrlPressed) { std::cout<<"CTRL X PRESSED"; } break; case (86): if(g_isLCtrlPressed) { std::cout<<"CTRL V PRESSED"; } break; } } } return CallNextHookEx(hookHandle, code, wparam, lparam); }
提示:代码中硬编码的88对应X键、86对应V键,建议替换为系统定义的
VK_X、VK_V宏,代码可读性更强。
内容的提问来源于stack exchange,提问作者Macer
相关产品推荐
相关产品推荐

