如何用C++实现按键释放触发模拟按键(跨程序生效)?
需求实现:释放按键时触发模拟另一按键(全局生效)
我正在开发一款程序,需要实现以下功能:
- 释放A键时,自动模拟按下D键
- 释放D键时,自动模拟按下A键
程序需要能模拟用户按键操作,且在其他程序处于前台时仍能生效。
以下是我目前编写的代码:
原代码
Header.h
#include <iostream> #include <windows.h> #include <conio.h> //#include<stdlib.h> bool isOn = false; //bool a = false; //bool d = false;
Source.cpp
#include "Header.h" void OnOff(); void Action(); int main() { printf("Press: Home to start\n"); while (true) { OnOff(); if (isOn) Action(); //std::cout << a << "," << d << std::endl; } } void Action() { // code should be here } void OnOff() { if (_kbhit()) { switch (_getch()) { case 71: if (!isOn) { printf("ON\n"); isOn = true; break; } else if (isOn) { printf("OFF\n"); isOn = false; break; } } } }
解决方案
原代码使用的_kbhit()和_getch()仅能检测当前控制台窗口的按键,无法实现全局(后台)监听。要达成需求,需使用Windows全局低级别键盘钩子配合SendInput()模拟真实按键操作。
修改后的完整代码
Header.h
#include <iostream> #include <windows.h> // 功能全局开关 bool isOn = false; // 键盘钩子句柄 HHOOK keyboardHook = NULL;
Source.cpp
#include "Header.h" // 键盘钩子回调函数,处理全局按键事件 LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { if (nCode >= 0 && isOn) { KBDLLHOOKSTRUCT* kbStruct = (KBDLLHOOKSTRUCT*)lParam; // 仅处理按键释放事件(WM_KEYUP) if (wParam == WM_KEYUP) { INPUT input = {0}; input.type = INPUT_KEYBOARD; // 释放A键时,模拟按下并释放D键 if (kbStruct->vkCode == 'A') { input.ki.wVk = 'D'; SendInput(1, &input, sizeof(INPUT)); // 模拟按下D input.ki.dwFlags = KEYEVENTF_KEYUP; SendInput(1, &input, sizeof(INPUT)); // 模拟释放D } // 释放D键时,模拟按下并释放A键 else if (kbStruct->vkCode == 'D') { input.ki.wVk = 'A'; SendInput(1, &input, sizeof(INPUT)); // 模拟按下A input.ki.dwFlags = KEYEVENTF_KEYUP; SendInput(1, &input, sizeof(INPUT)); // 模拟释放A } } } // 将事件传递给下一个钩子,避免阻塞系统按键 return CallNextHookEx(keyboardHook, nCode, wParam, lParam); } // 注册/卸载全局键盘钩子 void ToggleHook() { if (isOn) { keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, GetModuleHandle(NULL), 0); if (!keyboardHook) { printf("钩子注册失败,错误码:%d\n", GetLastError()); isOn = false; return; } printf("功能已开启,后台按键监听生效\n"); } else { if (keyboardHook) { UnhookWindowsHookEx(keyboardHook); keyboardHook = NULL; } printf("功能已关闭\n"); } } int main() { printf("按下Home键开启/关闭功能\n"); MSG msg; while (true) { // 处理系统消息,低级别钩子依赖消息循环才能触发回调 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } // 检测Home键按下(避免重复触发,等待按键释放) if (GetAsyncKeyState(VK_HOME) & 0x8000) { while (GetAsyncKeyState(VK_HOME) & 0x8000); isOn = !isOn; ToggleHook(); } // 降低CPU占用率 Sleep(10); } return 0; }
关键细节说明
全局低级别键盘钩子(WH_KEYBOARD_LL):
- 无需注入其他进程,仅需当前进程保持运行即可监听全局按键
- 必须配合消息循环(
PeekMessage)才能正常触发回调
按键模拟用SendInput:
- 这是Windows官方推荐的模拟输入API,比旧版
keybd_event更可靠,能模拟真实用户输入 - 模拟完整按键需分两步:先发送按下事件,再发送释放事件
- 这是Windows官方推荐的模拟输入API,比旧版
按键状态检测优化:
- 使用
GetAsyncKeyState替代_kbhit(),支持全局按键检测 - 添加
Sleep(10)避免程序占用过高CPU资源
- 使用
编译注意事项:
- 需在Windows平台编译(MSVC/MinGW均可)
- MinGW编译时需手动链接
user32.lib,添加编译参数-luser32
内容的提问来源于stack exchange,提问作者Nick Vinesmoke
相关产品推荐
相关产品推荐

