为什么使用GetAsyncKeyState判断按键时会无限触发按键发送?
问题原因分析
你的代码存在4个核心问题,共同导致松开空格后仍然持续触发发送:
- 自触发循环问题:你调用
keybd_event模拟发送的空格按键事件,会被GetAsyncKeyState正常检测到。哪怕你已经松开物理空格键,上一轮模拟发送的空格状态会被下一轮循环的GetAsyncKeyState识别为“空格按下”,进而触发新一轮的模拟发送,形成永久触发的死循环。 GetAsyncKeyState返回值判断错误:GetAsyncKeyState返回值为SHORT类型,只有最高位(0x8000掩码位)为1时,才代表当前时刻按键处于物理按下状态。你直接用if (GetAsyncKeyState(VK_SPACE))判断,会命中返回值最低位的“历史按下”标记,哪怕按键已经松开也可能触发逻辑。- 延时位置不合理:你在检测到按键按下后先执行了
Sleep(10),后续还有总计21ms的延时,这段时间即使用户松开按键,当前轮次的模拟发送逻辑也会全部执行完,进一步放大误触发概率。 - 多线程变量可见性问题:
bhop是跨线程共享的开关变量,如果没有加volatile修饰或者用原子变量,线程可能会缓存变量值,无法及时感知到外部对bhop状态的修改。
修复代码
#include <windows.h> // 共享开关变量加volatile保证线程可见 volatile bool bhop = false; DWORD WINAPI BhopThread(LPVOID lp) { // 标记当前是否是自己在发送模拟按键,用于过滤自触发 bool selfSending = false; while (true) { if (!bhop) { Sleep(1); // 空转时降低CPU占用 continue; } // 仅当不是自发送、且物理空格真实按下时才触发逻辑 if (!selfSending && (GetAsyncKeyState(VK_SPACE) & 0x8000)) { selfSending = true; // 模拟空格点击 keybd_event(0x20, 0, 0, 0); Sleep(1); keybd_event(0x20, 0, KEYEVENTF_KEYUP, 0); selfSending = false; // 控制连点频率 Sleep(10); } else { Sleep(1); } } return 0; }
修复逻辑说明:
- 加
selfSending标记过滤自己模拟发送的按键事件,避免形成自触发循环 - 用
GetAsyncKeyState(VK_SPACE) & 0x8000只判断当前物理按键的真实按下状态,忽略历史按下标记 - 调整延时位置,空转时仅Sleep 1ms降低CPU占用,按键判断逻辑前置,可及时响应松开动作
- 给共享变量
bhop加volatile修饰,保证多线程下的状态可见性
内容的提问来源于stack exchange,提问作者poop
相关产品推荐
相关产品推荐

