C++:模拟键盘鼠标(附带源码)
一、项目背景详细介绍
在实际工程中,我们经常需要让程序像“人”一样操作电脑:
- 自动化测试:点击按钮、输入文本
- 运维/工具:批量操作 GUI 程序
- 辅助工具:快捷操作、脚本化流程
- 教学实验:理解 OS 输入事件链路
这些需求的核心,都是:
程序如何向操作系统“注入”键盘与鼠标输入事件?
1. Windows 输入系统的基本认知
Windows 中,键盘和鼠标并不是直接“给应用”的,而是:
硬件 → 驱动 → 系统输入队列 → 消息分发 → 窗口
只要我们向系统输入队列提交合法事件,系统就会像处理真实硬件一样处理它。
2. 常见实现方式对比
| 方式 | 特点 | 是否推荐 |
|---|---|---|
| keybd_event / mouse_event | 老 API | ❌ 已过时 |
| SendInput | 官方推荐 | ✅ |
| 驱动层 | 复杂/高风险 | ❌ |
| 注入 DLL | 非必要 | ❌ |
本文只使用官方推荐的 SendInput。
3. 本项目目标
实现一个教学 + 工程可用的输入模拟模块,支持:
- 键盘按下 / 抬起
- 鼠标移动
- 鼠标点击(左 / 右)
- 简单组合输入
- 清晰、可复用的封装
二、项目需求详细介绍
1. 功能需求
实现以下能力:
- 模拟单个键按下与释放
- 模拟字符串输入
- 模拟鼠标移动到屏幕坐标
- 模拟鼠标左键 / 右键点击
- 支持组合示例(键盘 + 鼠标)
2. 技术约束
- 平台:Windows
- 语言:C++(C++11+)
- API:
SendInput - 不依赖第三方库
3. 合规与边界说明
- 仅用于自动化、测试、辅助工具
- 不包含隐藏、绕过、防检测等行为
- 不针对任何未授权系统
三、相关技术详细介绍
1. SendInput 是什么?
SendInput 是 Windows 提供的统一输入注入接口:
UINT SendInput( UINT cInputs, LPINPUT pInputs, int cbSize );
它可以一次性提交多个输入事件,系统会按顺序处理。
2. INPUT 结构体分类
INPUT { type: INPUT_KEYBOARD INPUT_MOUSE }
- 键盘:
KEYBDINPUT - 鼠标:
MOUSEINPUT
3. 键盘扫描码 vs 虚拟键码
- 虚拟键码(VK):更常用、更直观
- 扫描码:更底层(本文不展开)
4. 屏幕坐标说明
SendInput 的绝对坐标范围是:
X: 0 ~ 65535 Y: 0 ~ 65535
需要从屏幕像素转换。
四、实现思路详细介绍
1. 模块设计
封装一个 InputSimulator,提供:
KeyDown / KeyUpSendTextMouseMoveMouseClick
2. 核心思想
构造 INPUT 结构 → 调用 SendInput → 系统分发
3. 工程可扩展性
后续可扩展:
- 热键(Ctrl + C)
- 拖拽
- 滚轮
- 多屏支持
五、完整实现代码
/************************************************************ * 文件:InputSimulator.h * 描述:键盘与鼠标模拟工具(SendInput) ************************************************************/ #ifndef INPUT_SIMULATOR_H #define INPUT_SIMULATOR_H #include <windows.h> #include <string> /** * @brief 输入模拟器 */ class InputSimulator { public: /** * @brief 模拟按键按下 */ static void KeyDown(WORD vk) { INPUT input{}; input.type = INPUT_KEYBOARD; input.ki.wVk = vk; input.ki.dwFlags = 0; // 按下 SendInput(1, &input, sizeof(INPUT)); } /** * @brief 模拟按键释放 */ static void KeyUp(WORD vk) { INPUT input{}; input.type = INPUT_KEYBOARD; input.ki.wVk = vk; input.ki.dwFlags = KEYEVENTF_KEYUP; SendInput(1, &input, sizeof(INPUT)); } /** * @brief 发送一个按键(按下 + 抬起) */ static void KeyPress(WORD vk) { KeyDown(vk); Sleep(10); KeyUp(vk); } /** * @brief 模拟输入字符串(仅示例英文/ASCII) */ static void SendText(const std::string& text) { for (char c : text) { SHORT vk = VkKeyScanA(c); if (vk == -1) continue; bool shift = (vk & 0x0100) != 0; WORD vkCode = vk & 0xFF; if (shift) KeyDown(VK_SHIFT); KeyPress(vkCode); if (shift) KeyUp(VK_SHIFT); Sleep(5); } } /** * @brief 将屏幕像素坐标转换为 SendInput 绝对坐标 */ static LONG NormalizeX(int x) { return LONG(x * 65535.0f / GetSystemMetrics(SM_CXSCREEN)); } static LONG NormalizeY(int y) { return LONG(y * 65535.0f / GetSystemMetrics(SM_CYSCREEN)); } /** * @brief 移动鼠标到指定屏幕坐标 */ static void MouseMove(int x, int y) { INPUT input{}; input.type = INPUT_MOUSE; input.mi.dx = NormalizeX(x); input.mi.dy = NormalizeY(y); input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE; SendInput(1, &input, sizeof(INPUT)); } /** * @brief 鼠标左键点击 */ static void MouseLeftClick() { INPUT inputs[2]{}; inputs[0].type = INPUT_MOUSE; inputs[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN; inputs[1].type = INPUT_MOUSE; inputs[1].mi.dwFlags = MOUSEEVENTF_LEFTUP; SendInput(2, inputs, sizeof(INPUT)); } /** * @brief 鼠标右键点击 */ static void MouseRightClick() { INPUT inputs[2]{}; inputs[0].type = INPUT_MOUSE; inputs[0].mi.dwFlags = MOUSEEVENTF_RIGHTDOWN; inputs[1].type = INPUT_MOUSE; inputs[1].mi.dwFlags = MOUSEEVENTF_RIGHTUP; SendInput(2, inputs, sizeof(INPUT)); } }; #endif // INPUT_SIMULATOR_H /************************************************************ * 文件:main.cpp * 描述:模拟输入示例 ************************************************************/ #include <iostream> #include "InputSimulator.h" int main() { // 给用户 3 秒准备时间 Sleep(3000); // 模拟输入文字 InputSimulator::SendText("Hello World"); // 回车 InputSimulator::KeyPress(VK_RETURN); // 移动鼠标并点击 InputSimulator::MouseMove(500, 300); Sleep(500); InputSimulator::MouseLeftClick(); return 0; } 六、代码详细解读(仅解读方法作用)
1. KeyDown / KeyUp
作用:
- 构造键盘 INPUT
- 提交到系统输入队列
- 等价于真实按键
2. SendText
作用:
- 将字符映射为虚拟键码
- 自动处理 Shift
- 逐字符发送输入
3. MouseMove
作用:
- 使用绝对坐标模式
- 精确移动到屏幕位置
4. MouseLeftClick / MouseRightClick
作用:
- 组合 Down + Up
- 模拟完整点击行为
七、项目详细总结
本项目完整实现了一个:
✅ 官方 API
✅ 行为稳定
✅ 工程可复用
✅ 教学价值高
的 C++ 键盘鼠标模拟模块。
通过它,你应当真正理解:
- Windows 输入事件是如何产生的
SendInput的正确使用方式- 输入模拟与自动化测试的核心原理
八、项目常见问题及解答
Q1:为什么有些程序收不到模拟输入?
答:
- 高权限程序需要同等权限
- 某些游戏/安全软件会主动屏蔽
- 这是系统安全策略,不是代码问题
Q2:可以模拟中文输入吗?
答:
- 简单示例不支持
- 中文需:
- 输入法状态
- 或使用
KEYEVENTF_UNICODE
Q3:会被系统识别为“假输入”吗?
答:
SendInput是官方 API- 行为等同真实输入(但受安全策略限制)
九、扩展方向与性能优化
1. Unicode 输入支持
- 使用
KEYEVENTF_UNICODE - 支持中文/多语言
2. 组合键支持
- Ctrl + C / Alt + Tab
- 自动化测试高频需求
3. 鼠标拖拽与滚轮
- 拖动文件
- 模拟滚动
4. UI 自动化封装
- 结合窗口查找(FindWindow)
- 构建自动化测试框架