SendInput能真正模拟全局按键,但需满足严格前提:目标进程权限不得高于当前进程,当前线程需处于前台或已获焦点,Windows 10 1809+受UIPI策略限制,管理员程序无法向非管理员进程注入输入;返回成功却无响应时,应优先检查权限匹配、AttachThreadInput误用及KEYEVENTF_KEYUP是否缺失。

SendInput 能不能真正模拟全局按键?
能,但有严格前提:目标进程不能以更高权限运行,且当前线程需处于前台或已获取输入焦点(部分系统版本下还要求调用 SetThreadExecutionState 防止休眠干扰)。Windows 10 1809+ 对 UIPI(用户界面特权隔离)更敏感,以管理员身份运行的程序无法用 SendInput 向非管理员进程注入输入——这不是 API 失效,而是系统安全策略拦截。
常见错误现象:SendInput 返回成功(非零值),但目标窗口无响应。此时先检查目标进程权限是否高于当前进程;再确认是否调用过 AttachThreadInput 或误用了 INPUT_KEYBOARD 却没设置 KEYEVENTF_KEYUP 导致键被卡住。
怎么构造一个可靠的键盘输入结构体?
关键在 INPUT 结构体的 ki.wVk(虚拟键码)和 ki.dwFlags 组合。别直接用 ASCII 值填 wVk,比如想输 'a',该用 VK_A(0x41),不是 97;若需组合 Shift+a 输出 'A',必须分两步:先发 VK_SHIFT 按下,再发 VK_A 按下,然后反向抬起(顺序错会导致大小写异常)。
实操要点:
立即学习“C++免费学习笔记(深入)”;
-
ki.dwFlags = 0表示按键按下,KEYEVENTF_KEYUP表示抬起;单独发按下不配抬起,等效于长按 - 需要输入 Unicode 字符(如中文)时,改用
ki.wScan+KEYEVENTF_UNICODE,此时wVk必须为 0 - 避免硬编码虚拟键码,优先包含
winuser.h并使用VK_*宏
鼠标点击为什么总偏移或没反应?
SendInput 的鼠标事件基于屏幕坐标系(左上角为 0,0),且默认单位是“物理点”(1/65535 屏幕宽高)。直接传像素值会严重偏移。正确做法是用 GetSystemMetrics(SM_CXSCREEN) 和 GetSystemMetrics(SM_CYSCREEN) 获取分辨率,再将目标像素坐标映射为归一化值:
long x = 100; // 目标横坐标(像素)
long y = 200;
INPUT input = {};
input.type = INPUT_MOUSE;
input.mi.dx = (x * 65535) / GetSystemMetrics(SM_CXSCREEN);
input.mi.dy = (y * 65535) / GetSystemMetrics(SM_CYSCREEN);
input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
注意:MOUSEEVENTF_ABSOLUTE 必须和归一化坐标一起用;漏掉它,dx/dy 就变成相对移动量,极易误触。
为什么 SendInput 在某些游戏或远程桌面里完全失效?
游戏常绕过 Win32 消息循环,直接读取底层 HID 设备;远程桌面(RDP)会截断本地 SendInput 请求,只允许其服务端生成输入。这两种场景下,SendInput 不是 bug,而是设计如此。
替代方案有限且各有代价:
- 对游戏:尝试
keybd_event(已废弃但部分旧游戏仍认)或驱动级工具(如 Logitech GHUB SDK、AutoHotkey 的SendPlay) - 对 RDP:必须在远程会话内运行代码,或改用 Windows 自动化 API(
UIAutomation)操作控件 - 所有方案都绕不开 UAC 和 UIPI——这是 Windows 输入模拟最常被忽略的硬边界
实际用起来,SendInput 看似简单,但坐标的归一化、权限层级、键状态管理(按下/抬起配对)、以及目标程序的输入处理路径,四个点只要错一个,就表现为“明明写了代码却没反应”。


















