最可靠方式是windows用sendinput、linux用uinput、macos用cgevent;需注意权限、事件时序、坐标单位及平台特异性限制。

Windows 下用 SendInput 模拟鼠标键盘最可靠
直接调 SendInput 是 Windows 平台唯一被系统级支持的模拟方式,比 keybd_event 和 mouse_event 更稳定,也比第三方库(如 AutoIt 绑定)更可控。它走的是底层输入队列,能绕过多数游戏反作弊对 PostMessage 的拦截。
常见错误是只填了 INPUT_KEYBOARD 类型却忘了设 wVk 或 wScan —— 两者必须至少填一个,否则输入无效;模拟组合键(如 Ctrl+C)必须分三步:按 Ctrl → 按 C → 松 C → 松 Ctrl,漏掉任一帧都会失败。
-
SendInput要求输入结构体数组连续内存,别用 vector 存再传 data(),最好栈上分配或 new[] - 模拟鼠标移动时,
dx/dy是相对坐标,单位是“微移”(1/16 像素),不是像素值,直接填 100 会飞出去 - 需要管理员权限才能对全屏独占程序(如某些游戏)生效,但普通桌面程序不需要
Linux 下用 uinput 设备节点发事件
Linux 没有等效 SendInput 的 API,得自己创建虚拟设备节点。核心是打开 /dev/uinput,写入设备能力(比如 EV_KEY、EV_REL),再通过 write() 发 struct input_event。
容易卡在权限问题:默认只有 root 能写 /dev/uinput。不要 chmod 777,正确做法是加 udev 规则,比如新建 /etc/udev/rules.d/99-uinput.rules,内容:KERNEL=="uinput", MODE="0660", GROUP="input",然后把用户加进 input 组。
立即学习“C++免费学习笔记(深入)”;
AutoIt v3 版本, 这是一个使用类似 BASIC 脚本语言的免费软件, 它设计用于 Windows GUI(图形用户界面)中进行自动化操作. 利用模拟键盘按键, 鼠标移动和窗口/控件的组合来实现自动化任务. 而这是其它语言不可能做到或无可靠方法实现的(比如VBScript和SendKeys). AutoIt 非常小巧, 完全运行在所有windows操作系统上.(thesnow注:现在已经不再支持win 9x,微软连XP都能放弃, 何况一个win 9x支持), 并且不需要任何运行库. AutoIt
- 必须先调
ioctl(fd, UI_SET_EVBIT, EV_KEY)等声明支持的事件类型,否则 write 会返回 -1 - 键盘码用 Linux 的
KEY_A这类宏(定义在linux/input.h),不是 ASCII 或 Win32 的 VK_A - 模拟鼠标点击后不跟移动事件,光标不会自动跳,这是正常行为,不是 bug
macOS 上只能用 CGEventCreateMouseEvent 系列 API
macOS 完全禁止用户态进程注入输入事件,除非开启「辅助功能」权限。没授权时调 CGEventPost 直接静默失败,连错误码都不给。
授权不是一次性的:macOS 12+ 之后,每次应用重签名或更新 bundle ID,都要重新点系统设置里手动勾选。开发调试阶段建议用 csrutil disable 关掉 SIP(仅限测试机),否则连调试都卡住。
- 鼠标坐标系是全局屏幕坐标(左上角 0,0),且 Y 轴向下增长,和 Quartz 坐标系一致
- 键盘事件必须带
kCGKeyboardEventAutorepeat标志控制是否允许长按重复,不设就只触发单次 - 无法模拟触摸板手势(如三指滑动)、触控栏操作,这些 API 不开放
跨平台封装要注意事件时序和阻塞
不同系统对“按键按下→释放”的最小间隔容忍度不同。Windows SendInput 在 5ms 内连发两个 key down 可能被合并;macOS 要求两次 CGEventPost 至少间隔 10ms,否则后一次丢弃;Linux uinput 最宽松,但驱动层可能做去抖。
所有平台都不保证事件立即生效——特别是目标进程正在忙或挂起时。别在循环里狂发 SendInput 后立刻检查窗口状态,大概率读到旧画面。
- 真实自动化中,必须加
std::this_thread::sleep_for(Windows/macOS 建议 ≥15ms,Linux ≥5ms) - 避免用
GetAsyncKeyState或XQueryKeymap实时监听自己发的键,它们查的是物理设备状态,不是输入队列 - 如果目标程序用了 DirectInput 或 Raw Input,模拟事件可能被完全忽略,这时候只能换方案(比如内存注入或 DLL 注入)
跨平台最难的不是发事件,而是判断“什么时候该发下一个”。坐标偏移、焦点丢失、渲染延迟,这些没法靠统一 API 解决,得结合具体场景做容错。









