如何让WM_KEYBOARD全局钩子向目标程序注入指定文本
解决方法
你的问题核心在于cout是输出到当前进程的标准流,而非向目标应用的输入控件发送键盘输入事件。要实现向激活窗口注入文本,需要使用模拟键盘输入的方式,通过SendInput函数向系统发送键盘消息,让目标应用认为是用户手动输入了文本。
关键修改步骤
- 替换输出逻辑:移除
cout,改用SendInput模拟Unicode字符输入,无需处理复杂的虚拟键映射。 - 拦截原热键消息:处理热键后返回
TRUE,阻止原LeftAlt+Q/A的按键消息传递到目标应用,避免额外输入Q/A字符。 - 统一宽字符处理:将字符串改为
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
相关产品推荐
相关产品推荐

