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

如何让WM_KEYBOARD全局钩子向目标程序注入指定文本

解决方法

你的问题核心在于cout是输出到当前进程的标准流,而非向目标应用的输入控件发送键盘输入事件。要实现向激活窗口注入文本,需要使用模拟键盘输入的方式,通过SendInput函数向系统发送键盘消息,让目标应用认为是用户手动输入了文本。

关键修改步骤

  1. 替换输出逻辑:移除cout,改用SendInput模拟Unicode字符输入,无需处理复杂的虚拟键映射。
  2. 拦截原热键消息:处理热键后返回TRUE,阻止原LeftAlt+Q/A的按键消息传递到目标应用,避免额外输入Q/A字符。
  3. 统一宽字符处理:将字符串改为wstring,适配Windows的Unicode环境。

修改后的钩子DLL代码

#include "pch.h"
#include <windows.h>
#include <string>

using namespace std;
HHOOK hHook{ NULL };

#define     VK_HOT_1        0x51 // Q
#define     VK_HOT_2        0x41 // A
const wstring S1 = L"First string";
const wstring S2 = L"Second string";

// 模拟发送Unicode字符串到激活窗口
void SendString(const wstring& text) {
    INPUT* inputs = new INPUT[text.length() * 2];
    ZeroMemory(inputs, sizeof(INPUT) * text.length() * 2);

    for (size_t i = 0; i < text.length(); ++i) {
        // 按下字符
        inputs[i * 2].type = INPUT_KEYBOARD;
        inputs[i * 2].ki.wVk = 0;
        inputs[i * 2].ki.wScan = text[i];
        inputs[i * 2].ki.dwFlags = KEYEVENTF_UNICODE;

        // 释放字符
        inputs[i * 2 + 1].type = INPUT_KEYBOARD;
        inputs[i * 2 + 1].ki.wVk = 0;
        inputs[i * 2 + 1].ki.wScan = text[i];
        inputs[i * 2 + 1].ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
    }

    SendInput(text.length() * 2, inputs, sizeof(INPUT));
    delete[] inputs;
}

extern "C" __declspec(dllexport)
LRESULT CALLBACK KeyboardHookProc(int code, WPARAM wParam, LPARAM lParam)
{
    if (code < 0) return CallNextHookEx(hHook, code, wParam, lParam);

    WORD keyFlags = HIWORD(lParam);
    BOOL isKeyReleased = (keyFlags & KF_UP) == KF_UP;
    BOOL altDown = (keyFlags & KF_ALTDOWN) == KF_ALTDOWN;
    WORD vkCode = wParam;

    if (isKeyReleased && (vkCode == VK_HOT_1 || vkCode == VK_HOT_2) && altDown )
    {
        SHORT lAltState = GetKeyState(VK_LMENU);
        BOOL lAltDown = (lAltState & 0x8000) != 0; // 修正左Alt按下状态判断
        if (lAltDown)
        {
            // 发送对应字符串
            if (vkCode == VK_HOT_1)
                SendString(S1);
            else
                SendString(S2);
            
            // 拦截原消息,避免Q/A字符被输入到目标应用
            return TRUE;
        }
    }
    return CallNextHookEx(hHook, code, wParam, lParam);
}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        // 禁用不必要的线程通知,优化性能
        DisableThreadLibraryCalls(hModule);
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

补充说明

  • SendInput优势:相比旧的keybd_event,SendInput是更可靠的现代API,支持直接发送Unicode字符,无需处理字符与虚拟键的复杂映射。
  • 状态判断修正:原代码用HSHELL_HIGHBIT判断左Alt状态是错误的,正确方式是用0x8000(高位为1表示按键当前处于按下状态)。
  • 消息拦截:处理完热键后返回TRUE,阻止原按键消息继续传递,避免目标窗口额外接收到Q/A字符。
  • DLL优化:调用DisableThreadLibraryCalls减少不必要的线程通知,降低钩子对系统性能的影响。

内容的提问来源于stack exchange,提问作者Kalle Svensson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 13:58:19