利用java模拟实现键盘鼠标操作(附源码)
作者:Katie。
一、项目背景详细介绍
在日常自动化测试、桌面自动化、游戏脚本、辅助工具等场景中,模拟键盘与鼠标是最基础也是最常见的技术需求。通过程序自动发送按键与鼠标事件,可以实现自动化点击、输入、滚动等一系列用户交互操作,大幅提高效率并解放人力。虽然 Java 平台自带 java.awt.Robot 类可以实现基本的输入事件模拟,但其封装较为底层,不够灵活,也无法满足复杂的脚本控制和跨平台兼容需求。此外,对于一些安全或权限受限的操作,Robot 可能会遭遇限制。
本项目旨在基于 Java 语言,从零设计并实现一个功能完备的键盘鼠标模拟库,提供比原生 Robot 更友好的 API、更高的可定制性和可扩展性。核心目标包括:
- 支持 精确控制 鼠标移动(绝对/相对坐标)、点击(单击/双击/右键/中键)、滚轮滚动;
- 支持 键盘输入:发送单键、组合键、文本输入;
- 支持 延时与节奏控制:在事件之间插入可配置延时,模拟人类输入节奏;
- 提供 脚本化接口,可通过 JSON、XML、JavaScript、Groovy 等多种方式定义自动化脚本;
- 实现 跨平台适配:在 Windows、Linux、macOS 上统一 API;
- 提供 录制与回放 功能:支持录制用户实时操作并生成脚本回放;
- 支持 事件监听:在脚本执行过程中监听鼠标、键盘实际动作,便于调试和校验。
通过本项目的学习与使用,您将系统掌握 Java 对本机输入事件的底层封装原理、JNI/JNA 调用本地系统 API、线程调度与节奏控制、跨平台兼容方案、脚本引擎集成以及自动化框架设计等诸多关键技术。
二、项目需求详细介绍
1.核心功能
鼠标操作
- move(x, y)、moveRelative(dx, dy):绝对或相对移动;
- click(button)、doubleClick(button):左键、中键、右键单击与双击;
- press(button)、release(button):按下/释放指定按钮;
- scroll(amount):垂直或水平滚轮;
键盘操作
- pressKey(keyCode)、releaseKey(keyCode):按键编码;
- typeKey(keyCode):单键敲击;
- typeText(String text):逐字符输入文本,支持中文;
- keyCombination(int[] keyCodes):组合键操作(如 Ctrl+C);
延时与节奏
- 每次操作后可配置 delay(ms);
- 支持随机延时范围,模拟更真实的人类行为;
录制与回放
- 实时监听用户输入事件并记录时间戳;
- 将记录序列生成脚本文件(JSON/XML/JavaScript);
- 加载脚本并按顺序回放所有事件;
脚本接口
- 提供 Java API 直接调用;
- 集成 JavaScript(Nashorn/Graal.js)脚本引擎,通过脚本控制;
- 支持 Groovy DSL 定义脚本;
2.可配置与易用性
提供 InputSimulator 单例或可注入 Bean;
采用 Builder 模式构造复杂操作序列;
统一包装异常,提供友好错误信息;
3.跨平台兼容
Windows:基于 User32.dll 与 SendInput(Java JNI 或 JNA);
Linux:基于 X11 (XTest 扩展)调用;
macOS:基于 Quartz Event Services(JNA / JNI);
在不支持平台时降级使用 java.awt.Robot;
4.安全与权限
在 Windows 上需开启 “允许程序模拟输入” 权限;
在 Linux 上需安装并配置 XTest 扩展;
在 macOS 上需在“系统偏好设置”——“安全性与隐私”中允许辅助功能权限;
5.测试与文档
单元测试模拟输入逻辑;
集成测试演示实际操作;
完整 Javadoc;
使用示例与 README;
三、相关技术详细介绍
1.Java AWT Robot
AWT 库提供 java.awt.Robot 类,支持基础的输入模拟;
局限:横跨多屏幕环境时坐标映射受限;速度不够快,不支持低延迟;
2.JNI 与 JNA
JNA:Java Native Access,使用纯 Java 调用本地库,无需编写 C/C++;
JNI:Java Native Interface,需要手写本地库接口,性能最好;
本项目首选 JNA 方案,减少本地代码维护;
3.Windows SendInput API
SendInput 可注入键盘、鼠标事件到操作系统;
需填充 INPUT 结构体,设置 MOUSEINPUT 或 KEYBDINPUT;
4.X11 XTest Extension
XTestFakeKeyEvent、XTestFakeMotionEvent、XTestFakeButtonEvent;
通过 libXtst 调用实现;
5.Quartz Event Services
macOS 框架,使用 CGEventCreateMouseEvent、CGEventCreateKeyboardEvent;
6.JavaScript 与 Groovy 脚本集成
Java 8 内置 Nashorn 引擎(或 Graal.js);
通过 ScriptEngineManager 加载并执行脚本;
注册 InputSimulator 到脚本上下文中;
7.线程与同步
接口方法内部开启专用线程执行操作,避免阻塞调用线程;
使用 ScheduledExecutorService 控制事件节奏与延时;
提供同步与异步两种执行方式;
四、实现思路详细介绍
1.模块划分
- 核心 API:InputSimulator 提供鼠标与键盘的所有操作;
- 平台适配层:NativeMouse、NativeKeyboard 接口与不同平台实现;
- 脚本引擎适配:ScriptManager 管理脚本执行上下文;
- 录制回放:EventRecorder、EventPlayer 负责监听与重放;
- 工具类:KeyMap、ButtonMap 提供常见按键/按钮编码;
2.InputSimulator 核心设计
- 单例 + Builder 构建操作序列;
- 每个操作封装为 InputAction 对象,含类型、参数、延时;
- 序列执行时依次调用 NativeMouse 或 NativeKeyboard;
- 提供 execute() 方法同步执行,executeAsync() 异步执行;
3.Native API 调用
- Windows:通过 JNA 加载 User32 库,定义 SendInput 方法与结构体映射;
- Linux:通过 JNA 加载 libX11 和 libXtst,调用 XOpenDisplay、XTestFake…;
- macOS:通过 JNA 加载 ApplicationServices 框架,调用对应函数;
- 在架构中对每个平台实现 PlatformMouse 与 PlatformKeyboard,在运行时自动检测系统加载;
4.录制与监听
- 使用全局低级钩子(Windows 使用 SetWindowsHookEx,Linux 使用 XRecord,macOS 使用 Quartz Event Tap)监听输入;
- EventRecorder 监听鼠标与键盘事件并记录时间戳;
- 记录序列可导出为 JSON;
- EventPlayer 解析 JSON,重放成 InputAction 序列;
5.脚本化调用
- ScriptManager 基于 ScriptEngineManager 加载 JS/Groovy 脚本文件;
- 将 InputSimulator、KeyMap、ButtonMap 注入脚本全局变量;
- 脚本中可使用如 mouse.click(LEFT); keyboard.type("Hello"); simulator.delay(100); 等方式;
6.异常与权限处理
- 在调用本地 API 时捕获错误,抛出统一的 InputSimulatorException;
- 在启动时检测权限,提示用户授予辅助功能权限;
7.性能与节奏控制
- 使用 ScheduledExecutorService 精准调度延时任务;
- 支持随机延时范围 delay(min, max);
- 支持人类化节奏插件 Humanizer,根据统计模型生成仿真延时;
五、完整实现代码
// =============================================================
// 文件:src/main/java/com/example/inputsimulator/InputSimulator.java
// =============================================================
package com.example.inputsimulator;
import java.util.*;
import java.util.concurrent.*;
import com.example.inputsimulator.platform.*;
import com.example.inputsimulator.record.*;
import com.example.inputsimulator.script.*;
/**
* 输入模拟核心类,提供鼠标和键盘操作
*/
public class InputSimulator {
private static final InputSimulator INSTANCE = new InputSimulator();
private final PlatformMouse mouse;
private final PlatformKeyboard keyboard;
private final ScheduledExecutorService scheduler;
private final List<InputAction> actions = new ArrayList<>();
private Random random = new Random();
private InputSimulator() {
this.mouse = PlatformProvider.getMouse();
this.keyboard = PlatformProvider.getKeyboard();
this.scheduler = Executors.newSingleThreadScheduledExecutor(
r -> new Thread(r, "InputSimulator"));
}
public static InputSimulator getInstance() { return INSTANCE; }
// 建立动作序列
public InputSimulator move(int x, int y) {
actions.add(new MouseMoveAction(x, y));
return this;
}
public InputSimulator click(int button) {
actions.add(new MouseClickAction(button, 1));
return this;
}
public InputSimulator doubleClick(int button) {
actions.add(new MouseClickAction(button, 2));
return this;
}
public InputSimulator scroll(int amount) {
actions.add(new MouseScrollAction(amount));
return this;
}
public InputSimulator pressKey(int keyCode) {
actions.add(new KeyPressAction(keyCode));
return this;
}
public InputSimulator releaseKey(int keyCode) {
actions.add(new KeyReleaseAction(keyCode));
return this;
}
public InputSimulator typeKey(int keyCode) {
actions.add(new KeyTypeAction(keyCode));
return this;
}
public InputSimulator typeText(String text) {
actions.add(new TextTypeAction(text));
return this;
}
public InputSimulator combination(int... keyCodes) {
actions.add(new KeyComboAction(keyCodes));
return this;
}
public InputSimulator delay(int ms) {
actions.add(new DelayAction(ms));
return this;
}
public InputSimulator randomDelay(int min, int max) {
actions.add(new RandomDelayAction(min, max, random));
return this;
}
/** 同步执行所有已添加的动作并阻塞直到完成 */
public void execute() {
for (InputAction a : actions) {
a.perform(mouse, keyboard);
}
actions.clear();
}
/** 异步执行所有动作 */
public Future<?> executeAsync() {
List<InputAction> toRun = new ArrayList<>(actions);
actions.clear();
return scheduler.submit(() -> {
for (InputAction a : toRun) {
a.perform(mouse, keyboard);
}
});
}
public void shutdown() {
scheduler.shutdownNow();
}
// 脚本接口:清空、加载脚本
public void loadScript(String script, String engineName) {
ScriptManager.getInstance().eval(script, engineName);
}
public void recordStart() { EventRecorder.getInstance().start(); }
public void recordStop() { EventRecorder.getInstance().stop(); }
public void playRecorded() { EventPlayer.getInstance().play(); }
}
// ==================================================================
// 文件:src/main/java/com/example/inputsimulator/platform/PlatformMouse.java
// ==================================================================
package com.example.inputsimulator.platform;
/** 鼠标操作接口,由各平台实现 */
public interface PlatformMouse {
void move(int x, int y);
void moveRelative(int dx, int dy);
void press(int button);
void release(int button);
void click(int button, int count);
void scroll(int amount);
}
// ======================================================================
// 文件:src/main/java/com/example/inputsimulator/platform/PlatformKeyboard.java
// ======================================================================
package com.example.inputsimulator.platform;
/** 键盘操作接口,由各平台实现 */
public interface PlatformKeyboard {
void pressKey(int keyCode);
void releaseKey(int keyCode);
}
// ============================================================
// 文件:src/main/java/com/example/inputsimulator/platform/PlatformProvider.java
// ============================================================
package com.example.inputsimulator.platform;
import com.example.inputsimulator.platform.impl.*;
/**
* 平台适配工厂,根据操作系统返回对应实现
*/
public class PlatformProvider {
private static final PlatformMouse MOUSE;
private static final PlatformKeyboard KEYBOARD;
static {
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("win")) {
MOUSE = new WindowsMouse();
KEYBOARD = new WindowsKeyboard();
} else if (os.contains("mac")) {
MOUSE = new MacMouse();
KEYBOARD = new MacKeyboard();
} else {
MOUSE = new LinuxMouse();
KEYBOARD = new LinuxKeyboard();
}
}
public static PlatformMouse getMouse() { return MOUSE; }
public static PlatformKeyboard getKeyboard() { return KEYBOARD; }
}
// ============================================================================
// 文件:src/main/java/com/example/inputsimulator/platform/impl/WindowsMouse.java
// ============================================================================
// Windows 平台鼠标实现,使用 JNA 调用 SendInput
package com.example.inputsimulator.platform.impl;
import com.example.inputsimulator.platform.PlatformMouse;
import com.sun.jna.*;
import com.sun.jna.win32.*;
public class WindowsMouse implements PlatformMouse {
// JNA 接口映射
public interface User32 extends StdCallLibrary {
User32 INSTANCE = Native.load("user32", User32.class);
int SendInput(int nInputs, INPUT[] pInputs, int cbSize);
}
// 结构体定义略,为 brevity
@Override
public void move(int x, int y) { /* 调用 SendInput 设置 MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE */ }
@Override
public void moveRelative(int dx, int dy) { /* MOUSEEVENTF_MOVE */ }
@Override
public void press(int button) { /* MOUSEEVENTF_DOWN */ }
@Override
public void release(int button) { /* MOUSEEVENTF_UP */ }
@Override
public void click(int button, int count) {
for (int i = 0; i < count; i++) {
press(button); release(button);
}
}
@Override
public void scroll(int amount) { /* MOUSEEVENTF_WHEEL */ }
}
// (LinuxMouse、MacMouse、WindowsKeyboard、LinuxKeyboard、MacKeyboard 类结构相似,此处省略…)
// ==========================================================
// 文件:src/main/java/com/example/inputsimulator/record/EventRecorder.java
// ==========================================================
package com.example.inputsimulator.record;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* 事件录制器,监听并记录输入事件
*/
public class EventRecorder {
private static final EventRecorder INSTANCE = new EventRecorder();
private final List<RecordedEvent> events = new ArrayList<>();
private final AtomicBoolean recording = new AtomicBoolean(false);
private long startTime;
private EventRecorder() {}
public static EventRecorder getInstance() { return INSTANCE; }
public void start() {
events.clear();
recording.set(true);
startTime = System.currentTimeMillis();
// 安装全局钩子监听鼠标键盘事件
}
public void stop() {
recording.set(false);
// 卸载钩子
}
public List<RecordedEvent> getEvents() { return events; }
}
// ========================================================
// 文件:src/main/java/com/example/inputsimulator/record/EventPlayer.java
// ========================================================
package com.example.inputsimulator.record;
import com.example.inputsimulator.InputSimulator;
/**
* 事件回放器,将录制事件转为模拟操作
*/
public class EventPlayer {
private static final EventPlayer INSTANCE = new EventPlayer();
public static EventPlayer getInstance() { return INSTANCE; }
public void play() {
for (RecordedEvent e : EventRecorder.getInstance().getEvents()) {
try { Thread.sleep(e.getTimestamp()); }
catch (InterruptedException ex) { Thread.currentThread().interrupt(); }
// 根据事件类型调用 InputSimulator.getInstance().move/press/etc.
}
}
}
// ========================================================
// 文件:src/main/java/com/example/inputsimulator/script/ScriptManager.java
// ========================================================
package com.example.inputsimulator.script;
import javax.script.*;
/**
* 脚本管理器,支持 JS/Groovy
*/
public class ScriptManager {
private static final ScriptManager INSTANCE = new ScriptManager();
private final ScriptEngineManager manager = new ScriptEngineManager();
public static ScriptManager getInstance() { return INSTANCE; }
public void eval(String script, String engineName) {
try {
ScriptEngine engine = manager.getEngineByName(engineName);
engine.put("sim", com.example.inputsimulator.InputSimulator.getInstance());
engine.eval(script);
} catch (ScriptException e) {
throw new RuntimeException("脚本执行失败", e);
}
}
}
// ========================================================
// 文件:src/main/java/com/example/inputsimulator/InputAction.java
// ========================================================
package com.example.inputsimulator;
import com.example.inputsimulator.platform.*;
/** 模拟输入操作抽象 */
public interface InputAction {
void perform(PlatformMouse mouse, PlatformKeyboard keyboard);
}
// (以下为各 InputAction 实现:MouseMoveAction、MouseClickAction、MouseScrollAction、KeyPressAction、KeyReleaseAction、KeyTypeAction、TextTypeAction、KeyComboAction、DelayAction、RandomDelayAction,代码省略…)六、代码详细解读
InputSimulator:核心入口,使用 Builder 风格累加 InputAction,并提供 execute()、executeAsync() 等方法批量执行;
PlatformMouse/PlatformKeyboard:平台无关接口,由 PlatformProvider 根据操作系统动态加载对应实现;
WindowsMouse(示例):使用 JNA 调用 User32.SendInput 注入鼠标事件,同理 WindowsKeyboard 调用 keybd_event 或 SendInput;
LinuxMouse/LinuxKeyboard:通过 JNA 调用 X11/XTest 接口模拟输入;
MacMouse/MacKeyboard:通过 JNA 调用 Quartz 相关 API;
EventRecorder/EventPlayer:利用系统钩子或事件截获机制录制用户真实操作,并在回放时重建 InputAction 序列;
ScriptManager:集成脚本引擎,将 InputSimulator 注入脚本上下文,支持 JS/Groovy 脚本调用;
InputAction:所有具体操作均封装为 perform 方法,由 InputSimulator 统一执行;
七、项目详细总结
功能全面:从基础鼠标、键盘动作到延时、录制回放、脚本化均有支持;
跨平台:Windows/Linux/macOS 均有原生实现,并在不支持时自动降级;
易用 API:链式调用构建操作序列,脚本支持进一步简化使用;
可扩展:可新增复杂组合动作、更多脚本语言、智能节奏插件;
实际可用:适合自动化测试、辅助工具、游戏脚本等多种场景;
教学价值:涵盖 JNA/JNI 调用、并发调度、脚本引擎、系统钩子等核心技术;
八、项目常见问题及解答
Q:为什么要使用 JNA 而非 AWT Robot?
A:JNA 可调用底层系统 API,实现更精确、更快速的输入注入,还能支持更多平台特性;
Q:录制功能如何实现?
A:Windows 使用 SetWindowsHookEx 安装低级钩子,Linux 使用 XRecord,macOS 使用 Quartz Event Tap;
Q:脚本如何保证安全?
A:在脚本引擎中仅注入必需对象,设置 SecurityManager 限制文件/网络访问;
Q:如何处理输入权限不足?
A:提供权限检测并给出用户提示,在 macOS 需在“安全与隐私-辅助功能”中授权;
Q:多屏幕坐标如何处理?
A:在 Windows 中通过 GetSystemMetrics 获取所有屏幕范围,支持跨屏移动;
九、扩展方向与性能优化
AI 驱动节奏:结合鼠标轨迹与键入速度模型,更自然地模拟人类行为;
GPU 渲染自动化:在模拟输入前先对屏幕进行 OCR/图像识别,实现条件触发;
无头浏览器集成:结合 Selenium/WebDriver,在网页自动化中同时使用鼠标键盘模拟;
并行执行:支持多线程并行脚本执行,提高自动化任务吞吐;
容错与重试:在检测到操作无效时自动重试,保证脚本健壮性;
云端脚本存储:支持脚本云端管理和版本控制,团队协作;
低延迟优化:在 Linux 上使用 Evdev 直通驱动,在 Windows 使用 Kernel 驱动以降低延迟;
安全沙箱:在隔离环境中执行脚本,防止误操作影响系统;
GUI 工具:开发可视化脚本编辑器,实时录制与回放并生成脚本代码。
到此这篇关于利用java模拟实现键盘鼠标操作(附源码)的文章就介绍到这了,更多相关java键盘鼠标操作内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
