利用java模擬實現(xiàn)鍵盤鼠標操作(附源碼)
一、項目背景詳細介紹
在日常自動化測試、桌面自動化、游戲腳本、輔助工具等場景中,模擬鍵盤與鼠標是最基礎也是最常見的技術需求。通過程序自動發(fā)送按鍵與鼠標事件,可以實現(xiàn)自動化點擊、輸入、滾動等一系列用戶交互操作,大幅提高效率并解放人力。雖然 Java 平臺自帶 java.awt.Robot 類可以實現(xiàn)基本的輸入事件模擬,但其封裝較為底層,不夠靈活,也無法滿足復雜的腳本控制和跨平臺兼容需求。此外,對于一些安全或權(quán)限受限的操作,Robot 可能會遭遇限制。
本項目旨在基于 Java 語言,從零設計并實現(xiàn)一個功能完備的鍵盤鼠標模擬庫,提供比原生 Robot 更友好的 API、更高的可定制性和可擴展性。核心目標包括:
- 支持 精確控制 鼠標移動(絕對/相對坐標)、點擊(單擊/雙擊/右鍵/中鍵)、滾輪滾動;
- 支持 鍵盤輸入:發(fā)送單鍵、組合鍵、文本輸入;
- 支持 延時與節(jié)奏控制:在事件之間插入可配置延時,模擬人類輸入節(jié)奏;
- 提供 腳本化接口,可通過 JSON、XML、JavaScript、Groovy 等多種方式定義自動化腳本;
- 實現(xiàn) 跨平臺適配:在 Windows、Linux、macOS 上統(tǒng)一 API;
- 提供 錄制與回放 功能:支持錄制用戶實時操作并生成腳本回放;
- 支持 事件監(jiān)聽:在腳本執(zhí)行過程中監(jiān)聽鼠標、鍵盤實際動作,便于調(diào)試和校驗。
通過本項目的學習與使用,您將系統(tǒng)掌握 Java 對本機輸入事件的底層封裝原理、JNI/JNA 調(diào)用本地系統(tǒng) API、線程調(diào)度與節(jié)奏控制、跨平臺兼容方案、腳本引擎集成以及自動化框架設計等諸多關鍵技術。
二、項目需求詳細介紹
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);
延時與節(jié)奏
- 每次操作后可配置 delay(ms);
- 支持隨機延時范圍,模擬更真實的人類行為;
錄制與回放
- 實時監(jiān)聽用戶輸入事件并記錄時間戳;
- 將記錄序列生成腳本文件(JSON/XML/JavaScript);
- 加載腳本并按順序回放所有事件;
腳本接口
- 提供 Java API 直接調(diào)用;
- 集成 JavaScript(Nashorn/Graal.js)腳本引擎,通過腳本控制;
- 支持 Groovy DSL 定義腳本;
2.可配置與易用性
提供 InputSimulator 單例或可注入 Bean;
采用 Builder 模式構(gòu)造復雜操作序列;
統(tǒng)一包裝異常,提供友好錯誤信息;
3.跨平臺兼容
Windows:基于 User32.dll 與 SendInput(Java JNI 或 JNA);
Linux:基于 X11 (XTest 擴展)調(diào)用;
macOS:基于 Quartz Event Services(JNA / JNI);
在不支持平臺時降級使用 java.awt.Robot;
4.安全與權(quán)限
在 Windows 上需開啟 “允許程序模擬輸入” 權(quán)限;
在 Linux 上需安裝并配置 XTest 擴展;
在 macOS 上需在“系統(tǒng)偏好設置”——“安全性與隱私”中允許輔助功能權(quán)限;
5.測試與文檔
單元測試模擬輸入邏輯;
集成測試演示實際操作;
完整 Javadoc;
使用示例與 README;
三、相關技術詳細介紹
1.Java AWT Robot
AWT 庫提供 java.awt.Robot 類,支持基礎的輸入模擬;
局限:橫跨多屏幕環(huán)境時坐標映射受限;速度不夠快,不支持低延遲;
2.JNI 與 JNA
JNA:Java Native Access,使用純 Java 調(diào)用本地庫,無需編寫 C/C++;
JNI:Java Native Interface,需要手寫本地庫接口,性能最好;
本項目首選 JNA 方案,減少本地代碼維護;
3.Windows SendInput API
SendInput 可注入鍵盤、鼠標事件到操作系統(tǒng);
需填充 INPUT 結(jié)構(gòu)體,設置 MOUSEINPUT 或 KEYBDINPUT;
4.X11 XTest Extension
XTestFakeKeyEvent、XTestFakeMotionEvent、XTestFakeButtonEvent;
通過 libXtst 調(diào)用實現(xiàn);
5.Quartz Event Services
macOS 框架,使用 CGEventCreateMouseEvent、CGEventCreateKeyboardEvent;
6.JavaScript 與 Groovy 腳本集成
Java 8 內(nèi)置 Nashorn 引擎(或 Graal.js);
通過 ScriptEngineManager 加載并執(zhí)行腳本;
注冊 InputSimulator 到腳本上下文中;
7.線程與同步
接口方法內(nèi)部開啟專用線程執(zhí)行操作,避免阻塞調(diào)用線程;
使用 ScheduledExecutorService 控制事件節(jié)奏與延時;
提供同步與異步兩種執(zhí)行方式;
四、實現(xiàn)思路詳細介紹
1.模塊劃分
- 核心 API:InputSimulator 提供鼠標與鍵盤的所有操作;
- 平臺適配層:NativeMouse、NativeKeyboard 接口與不同平臺實現(xiàn);
- 腳本引擎適配:ScriptManager 管理腳本執(zhí)行上下文;
- 錄制回放:EventRecorder、EventPlayer 負責監(jiān)聽與重放;
- 工具類:KeyMap、ButtonMap 提供常見按鍵/按鈕編碼;
2.InputSimulator 核心設計
- 單例 + Builder 構(gòu)建操作序列;
- 每個操作封裝為 InputAction 對象,含類型、參數(shù)、延時;
- 序列執(zhí)行時依次調(diào)用 NativeMouse 或 NativeKeyboard;
- 提供 execute() 方法同步執(zhí)行,executeAsync() 異步執(zhí)行;
3.Native API 調(diào)用
- Windows:通過 JNA 加載 User32 庫,定義 SendInput 方法與結(jié)構(gòu)體映射;
- Linux:通過 JNA 加載 libX11 和 libXtst,調(diào)用 XOpenDisplay、XTestFake…;
- macOS:通過 JNA 加載 ApplicationServices 框架,調(diào)用對應函數(shù);
- 在架構(gòu)中對每個平臺實現(xiàn) PlatformMouse 與 PlatformKeyboard,在運行時自動檢測系統(tǒng)加載;
4.錄制與監(jiān)聽
- 使用全局低級鉤子(Windows 使用 SetWindowsHookEx,Linux 使用 XRecord,macOS 使用 Quartz Event Tap)監(jiān)聽輸入;
- EventRecorder 監(jiān)聽鼠標與鍵盤事件并記錄時間戳;
- 記錄序列可導出為 JSON;
- EventPlayer 解析 JSON,重放成 InputAction 序列;
5.腳本化調(diào)用
- ScriptManager 基于 ScriptEngineManager 加載 JS/Groovy 腳本文件;
- 將 InputSimulator、KeyMap、ButtonMap 注入腳本全局變量;
- 腳本中可使用如 mouse.click(LEFT); keyboard.type("Hello"); simulator.delay(100); 等方式;
6.異常與權(quán)限處理
- 在調(diào)用本地 API 時捕獲錯誤,拋出統(tǒng)一的 InputSimulatorException;
- 在啟動時檢測權(quán)限,提示用戶授予輔助功能權(quán)限;
7.性能與節(jié)奏控制
- 使用 ScheduledExecutorService 精準調(diào)度延時任務;
- 支持隨機延時范圍 delay(min, max);
- 支持人類化節(jié)奏插件 Humanizer,根據(jù)統(tǒng)計模型生成仿真延時;
五、完整實現(xiàn)代碼
// =============================================================
// 文件: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;
}
/** 同步執(zhí)行所有已添加的動作并阻塞直到完成 */
public void execute() {
for (InputAction a : actions) {
a.perform(mouse, keyboard);
}
actions.clear();
}
/** 異步執(zhí)行所有動作 */
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;
/** 鼠標操作接口,由各平臺實現(xiàn) */
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;
/** 鍵盤操作接口,由各平臺實現(xiàn) */
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.*;
/**
* 平臺適配工廠,根據(jù)操作系統(tǒng)返回對應實現(xiàn)
*/
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 平臺鼠標實現(xiàn),使用 JNA 調(diào)用 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);
}
// 結(jié)構(gòu)體定義略,為 brevity
@Override
public void move(int x, int y) { /* 調(diào)用 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 類結(jié)構(gòu)相似,此處省略…)
// ==========================================================
// 文件:src/main/java/com/example/inputsimulator/record/EventRecorder.java
// ==========================================================
package com.example.inputsimulator.record;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* 事件錄制器,監(jiān)聽并記錄輸入事件
*/
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();
// 安裝全局鉤子監(jiān)聽鼠標鍵盤事件
}
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;
/**
* 事件回放器,將錄制事件轉(zhuǎn)為模擬操作
*/
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(); }
// 根據(jù)事件類型調(diào)用 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("腳本執(zhí)行失敗", 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 實現(xiàn):MouseMoveAction、MouseClickAction、MouseScrollAction、KeyPressAction、KeyReleaseAction、KeyTypeAction、TextTypeAction、KeyComboAction、DelayAction、RandomDelayAction,代碼省略…)六、代碼詳細解讀
InputSimulator:核心入口,使用 Builder 風格累加 InputAction,并提供 execute()、executeAsync() 等方法批量執(zhí)行;
PlatformMouse/PlatformKeyboard:平臺無關接口,由 PlatformProvider 根據(jù)操作系統(tǒng)動態(tài)加載對應實現(xiàn);
WindowsMouse(示例):使用 JNA 調(diào)用 User32.SendInput 注入鼠標事件,同理 WindowsKeyboard 調(diào)用 keybd_event 或 SendInput;
LinuxMouse/LinuxKeyboard:通過 JNA 調(diào)用 X11/XTest 接口模擬輸入;
MacMouse/MacKeyboard:通過 JNA 調(diào)用 Quartz 相關 API;
EventRecorder/EventPlayer:利用系統(tǒng)鉤子或事件截獲機制錄制用戶真實操作,并在回放時重建 InputAction 序列;
ScriptManager:集成腳本引擎,將 InputSimulator 注入腳本上下文,支持 JS/Groovy 腳本調(diào)用;
InputAction:所有具體操作均封裝為 perform 方法,由 InputSimulator 統(tǒng)一執(zhí)行;
七、項目詳細總結(jié)
功能全面:從基礎鼠標、鍵盤動作到延時、錄制回放、腳本化均有支持;
跨平臺:Windows/Linux/macOS 均有原生實現(xiàn),并在不支持時自動降級;
易用 API:鏈式調(diào)用構(gòu)建操作序列,腳本支持進一步簡化使用;
可擴展:可新增復雜組合動作、更多腳本語言、智能節(jié)奏插件;
實際可用:適合自動化測試、輔助工具、游戲腳本等多種場景;
教學價值:涵蓋 JNA/JNI 調(diào)用、并發(fā)調(diào)度、腳本引擎、系統(tǒng)鉤子等核心技術;
八、項目常見問題及解答
Q:為什么要使用 JNA 而非 AWT Robot?
A:JNA 可調(diào)用底層系統(tǒng) API,實現(xiàn)更精確、更快速的輸入注入,還能支持更多平臺特性;
Q:錄制功能如何實現(xiàn)?
A:Windows 使用 SetWindowsHookEx 安裝低級鉤子,Linux 使用 XRecord,macOS 使用 Quartz Event Tap;
Q:腳本如何保證安全?
A:在腳本引擎中僅注入必需對象,設置 SecurityManager 限制文件/網(wǎng)絡訪問;
Q:如何處理輸入權(quán)限不足?
A:提供權(quán)限檢測并給出用戶提示,在 macOS 需在“安全與隱私-輔助功能”中授權(quán);
Q:多屏幕坐標如何處理?
A:在 Windows 中通過 GetSystemMetrics 獲取所有屏幕范圍,支持跨屏移動;
九、擴展方向與性能優(yōu)化
AI 驅(qū)動節(jié)奏:結(jié)合鼠標軌跡與鍵入速度模型,更自然地模擬人類行為;
GPU 渲染自動化:在模擬輸入前先對屏幕進行 OCR/圖像識別,實現(xiàn)條件觸發(fā);
無頭瀏覽器集成:結(jié)合 Selenium/WebDriver,在網(wǎng)頁自動化中同時使用鼠標鍵盤模擬;
并行執(zhí)行:支持多線程并行腳本執(zhí)行,提高自動化任務吞吐;
容錯與重試:在檢測到操作無效時自動重試,保證腳本健壯性;
云端腳本存儲:支持腳本云端管理和版本控制,團隊協(xié)作;
低延遲優(yōu)化:在 Linux 上使用 Evdev 直通驅(qū)動,在 Windows 使用 Kernel 驅(qū)動以降低延遲;
安全沙箱:在隔離環(huán)境中執(zhí)行腳本,防止誤操作影響系統(tǒng);
GUI 工具:開發(fā)可視化腳本編輯器,實時錄制與回放并生成腳本代碼。
到此這篇關于利用java模擬實現(xiàn)鍵盤鼠標操作(附源碼)的文章就介紹到這了,更多相關java鍵盤鼠標操作內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java異常(Exception)處理以及常見異??偨Y(jié)
在《Java編程思想》中這樣定義異常,阻止當前方法或作用域繼續(xù)執(zhí)行的問題,雖然java中有異常處理機制,但是要明確一點,決不應該用"正常"的態(tài)度來看待異常,這篇文章主要給大家介紹了關于Java異常(Exception)處理以及常見異常的相關資料,需要的朋友可以參考下2021-10-10
Spring MVC+FastJson+hibernate-validator整合的完整實例教程
這篇文章主要給大家介紹了關于Spring MVC+FastJson+hibernate-validator整合的完整實例教程,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。2018-04-04
spring cloud 使用Eureka 進行服務治理方法
這篇文章主要介紹了spring cloud 使用Eureka 進行服務治理方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-05-05

