利用java模擬實現(xiàn)鍵盤鼠標操作(附源碼)
一、項目背景詳細介紹
在日常自動化測試、桌面自動化、游戲腳本、輔助工具等場景中,模擬鍵盤與鼠標是最基礎(chǔ)也是最常見的技術(shù)需求。通過程序自動發(fā)送按鍵與鼠標事件,可以實現(xiàn)自動化點擊、輸入、滾動等一系列用戶交互操作,大幅提高效率并解放人力。雖然 Java 平臺自帶 java.awt.Robot 類可以實現(xiàn)基本的輸入事件模擬,但其封裝較為底層,不夠靈活,也無法滿足復雜的腳本控制和跨平臺兼容需求。此外,對于一些安全或權(quán)限受限的操作,Robot 可能會遭遇限制。
本項目旨在基于 Java 語言,從零設(shè)計并實現(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é)奏控制、跨平臺兼容方案、腳本引擎集成以及自動化框架設(shè)計等諸多關(guān)鍵技術(shù)。
二、項目需求詳細介紹
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)偏好設(shè)置”——“安全性與隱私”中允許輔助功能權(quán)限;
5.測試與文檔
單元測試模擬輸入邏輯;
集成測試演示實際操作;
完整 Javadoc;
使用示例與 README;
三、相關(guān)技術(shù)詳細介紹
1.Java AWT Robot
AWT 庫提供 java.awt.Robot 類,支持基礎(chǔ)的輸入模擬;
局限:橫跨多屏幕環(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)體,設(shè)置 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 核心設(shè)計
- 單例 + 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)用對應(yīng)函數(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)度延時任務(wù);
- 支持隨機延時范圍 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)返回對應(yī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 設(shè)置 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:平臺無關(guān)接口,由 PlatformProvider 根據(jù)操作系統(tǒng)動態(tài)加載對應(yīng)實現(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 相關(guān) API;
EventRecorder/EventPlayer:利用系統(tǒng)鉤子或事件截獲機制錄制用戶真實操作,并在回放時重建 InputAction 序列;
ScriptManager:集成腳本引擎,將 InputSimulator 注入腳本上下文,支持 JS/Groovy 腳本調(diào)用;
InputAction:所有具體操作均封裝為 perform 方法,由 InputSimulator 統(tǒng)一執(zhí)行;
七、項目詳細總結(jié)
功能全面:從基礎(chǔ)鼠標、鍵盤動作到延時、錄制回放、腳本化均有支持;
跨平臺:Windows/Linux/macOS 均有原生實現(xiàn),并在不支持時自動降級;
易用 API:鏈式調(diào)用構(gòu)建操作序列,腳本支持進一步簡化使用;
可擴展:可新增復雜組合動作、更多腳本語言、智能節(jié)奏插件;
實際可用:適合自動化測試、輔助工具、游戲腳本等多種場景;
教學價值:涵蓋 JNA/JNI 調(diào)用、并發(fā)調(diào)度、腳本引擎、系統(tǒng)鉤子等核心技術(shù);
八、項目常見問題及解答
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:在腳本引擎中僅注入必需對象,設(shè)置 SecurityManager 限制文件/網(wǎng)絡(luò)訪問;
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í)行,提高自動化任務(wù)吞吐;
容錯與重試:在檢測到操作無效時自動重試,保證腳本健壯性;
云端腳本存儲:支持腳本云端管理和版本控制,團隊協(xié)作;
低延遲優(yōu)化:在 Linux 上使用 Evdev 直通驅(qū)動,在 Windows 使用 Kernel 驅(qū)動以降低延遲;
安全沙箱:在隔離環(huán)境中執(zhí)行腳本,防止誤操作影響系統(tǒng);
GUI 工具:開發(fā)可視化腳本編輯器,實時錄制與回放并生成腳本代碼。
到此這篇關(guān)于利用java模擬實現(xiàn)鍵盤鼠標操作(附源碼)的文章就介紹到這了,更多相關(guān)java鍵盤鼠標操作內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java異常(Exception)處理以及常見異??偨Y(jié)
在《Java編程思想》中這樣定義異常,阻止當前方法或作用域繼續(xù)執(zhí)行的問題,雖然java中有異常處理機制,但是要明確一點,決不應(yīng)該用"正常"的態(tài)度來看待異常,這篇文章主要給大家介紹了關(guān)于Java異常(Exception)處理以及常見異常的相關(guān)資料,需要的朋友可以參考下2021-10-10Spring MVC+FastJson+hibernate-validator整合的完整實例教程
這篇文章主要給大家介紹了關(guān)于Spring MVC+FastJson+hibernate-validator整合的完整實例教程,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。2018-04-04spring cloud 使用Eureka 進行服務(wù)治理方法
這篇文章主要介紹了spring cloud 使用Eureka 進行服務(wù)治理方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-05-05