You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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;
}

关键细节说明

  1. 全局低级别键盘钩子(WH_KEYBOARD_LL):

    • 无需注入其他进程,仅需当前进程保持运行即可监听全局按键
    • 必须配合消息循环(PeekMessage)才能正常触发回调
  2. 按键模拟用SendInput:

    • 这是Windows官方推荐的模拟输入API,比旧版keybd_event更可靠,能模拟真实用户输入
    • 模拟完整按键需分两步:先发送按下事件,再发送释放事件
  3. 按键状态检测优化:

    • 使用GetAsyncKeyState替代_kbhit(),支持全局按键检测
    • 添加Sleep(10)避免程序占用过高CPU资源
  4. 编译注意事项:

    • 需在Windows平台编译(MSVC/MinGW均可)
    • MinGW编译时需手动链接user32.lib,添加编译参数-luser32

内容的提问来源于stack exchange,提问作者Nick Vinesmoke

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 01:02:51