news 2026/5/11 2:20:27

基于GUI-PLUS 搭配 Java Robot 实现智能桌面操控

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于GUI-PLUS 搭配 Java Robot 实现智能桌面操控

目录

一、引言

二、代码实现

1. 新增工具类 CoordinateExtractUtil

1.1 核心方法说明

2. DesktopRobotUtil 修改

2.1 功能概述

2.2 核心方法解析

鼠标操作

键盘操作

滚轮操作

注意事项

3. OperationController 接口

三、结果演示


一、引言

在前文 基于GUI-PLUS 的桌面GUI交互全流程总结-CSDN博客 中一个最最简单的,能把桌面上各种软件位置定位的办法被我搞出来了,接下来,我会用Java 的 Robot 方法来实现将这个定位好的坐标用到实际操作上。

二、代码实现

1. 新增工具类 CoordinateExtractUtil

package gzj.spring.ai.util; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; /** * 从JSON坐标字符串中提取x/y值的工具方法 * @author DELL */ public class CoordinateExtractUtil { // 复用单例ObjectMapper private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); /** * 提取JSON字符串中的x和y坐标 * @param jsonStr 格式如 {"x": 1860, "y": 237} 的字符串 * @return CoordinateMappingUtil.Point 对象(包含x/y值) * @throws Exception 解析失败时抛出异常 */ public static CoordinateMappingUtil.Point extractXY(String jsonStr) throws Exception { // 1. 校验入参 if (jsonStr == null || jsonStr.trim().isEmpty()) { throw new IllegalArgumentException("JSON坐标字符串不能为空"); } // 2. 解析JSON字符串为JsonNode JsonNode jsonNode = OBJECT_MAPPER.readTree(jsonStr); // 3. 提取x/y值(path()方法容错:字段不存在时返回0,避免空指针) int x = jsonNode.path("x").asInt(); int y = jsonNode.path("y").asInt(); // 4. 校验提取结果(避免x/y均为0的无效情况) if (x == 0 && y == 0) { throw new RuntimeException("未从JSON字符串中提取到有效坐标,JSON:" + jsonStr); } // 5. 返回Point对象 return new CoordinateMappingUtil.Point(x, y); } // 测试示例 public static void main(String[] args) { try { // 你的目标JSON字符串 String jsonStr = "{\"x\": 1860, \"y\": 237}"; // 提取坐标 CoordinateMappingUtil.Point point = extractXY(jsonStr); // 输出结果 System.out.println("提取的x值:" + point.getX()); // 输出 1860 System.out.println("提取的y值:" + point.getY()); // 输出 237 } catch (Exception e) { e.printStackTrace(); } } }

该代码是一个Java工具类,专门用于从JSON格式的坐标字符串中提取x/y数值并封装为Point对象。

1.1 核心方法说明

extractXY(String jsonStr)
输入参数为JSON格式字符串(如{"x":1860,"y":237}),输出为包含x/y坐标的Point对象。方法执行流程如下:

  • 参数非空校验:若输入为空字符串或null,抛出IllegalArgumentException
  • JSON解析:使用Jackson库的ObjectMapper将字符串转为JsonNode对象
  • 坐标提取:通过path()方法安全获取x/y字段值(字段不存在时默认返回0)
  • 有效性校验:当x/y同时为0时抛出运行时异常(可能JSON格式错误或字段缺失)
  • 结果封装:返回新建的Point对象

2. DesktopRobotUtil 修改

package gzj.spring.ai.util; import java.awt.*; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; /** * 桌面操作工具类(基于java.awt.Robot) * 支持鼠标移动、点击、滚轮滑动、键盘输入,兼容屏幕缩放后的精准坐标 */ public class DesktopRobotUtil { private final Robot robot; // 屏幕分辨率(初始化时自动获取) private final int screenWidth; private final int screenHeight; // 系统显示缩放比例(如Windows 125%=1.25,需手动传入或自动识别) private final double scaleRatio; /** * 构造器(初始化Robot+屏幕参数) * @param scaleRatio 系统显示缩放比例(如1.25=125%) * @throws AWTException Robot初始化失败(如无AWT环境) */ public DesktopRobotUtil(double scaleRatio) throws AWTException { this.robot = new Robot(); // 获取系统屏幕的物理分辨率 this.screenWidth = Toolkit.getDefaultToolkit().getScreenSize().width; this.screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height; this.scaleRatio = scaleRatio; // 设置自动等待(操作间的默认间隔) robot.setAutoWaitForIdle(true); } // ====================== 鼠标基础操作 ====================== /** * 移动鼠标到指定坐标(已校准的原始屏幕物理像素) * @param x 校准后的X坐标 * @param y 校准后的Y坐标 */ public void moveMouse(int x, int y) { // 若系统有缩放,转换为Robot识别的逻辑像素(可选,根据实际场景) int logicX = (int) Math.round(x / scaleRatio); int logicY = (int) Math.round(y / scaleRatio); // 校验坐标在屏幕范围内 logicX = Math.max(0, Math.min(screenWidth - 1, logicX)); logicY = Math.max(0, Math.min(screenHeight - 1, logicY)); // 移动鼠标 robot.mouseMove(logicX, logicY); // 短暂延迟,确保鼠标移动到位 robot.delay(300); } /** * 鼠标左键单击(先移动到坐标,再点击) * @param x 校准后的X坐标 * @param y 校准后的Y坐标 */ public void leftClick(int x, int y) { moveMouse(x, y); // 按下左键 robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); // 释放左键 robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); robot.delay(200); } /** * 鼠标右键单击 * @param x 校准后的X坐标 * @param y 校准后的Y坐标 */ public void rightClick(int x, int y) { moveMouse(x, y); robot.mousePress(InputEvent.BUTTON3_DOWN_MASK); robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); robot.delay(200); } /** * 鼠标左键双击 * @param x 校准后的X坐标 * @param y 校准后的Y坐标 */ public void doubleClick(int x, int y) { // 1. 先移动到目标坐标,确保位置准确 moveMouse(x, y); // 2. 第一次单击(增加按压延迟,模拟人类点击力度) robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); robot.delay(120); // 按压后停留200ms,避免“轻触” robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); robot.delay(200); // 双击间隔设为300ms(匹配Windows默认双击阈值) // 3. 第二次单击(同样增加按压延迟) robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); robot.delay(120); robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); robot.delay(200); // 双击后等待1秒,给软件启动的时间 } // ====================== 滚轮滑动操作 ====================== /** * 鼠标滚轮滑动(上下) * @param direction 方向:正数=向上,负数=向下 * @param amount 滑动幅度(推荐1-10) */ public void scrollWheel(int direction, int amount) { // Robot的scroll方法:正数向上,负数向下,amount为滑动格数 robot.mouseWheel(direction * amount); robot.delay(500); } // ====================== 键盘操作 ====================== /** * 输入文本(支持普通字符) * @param text 要输入的文本 */ public void typeText(String text) { for (char c : text.toCharArray()) { // 转换字符为KeyCode(基础字符) int keyCode = KeyEvent.getExtendedKeyCodeForChar(c); if (keyCode != KeyEvent.VK_UNDEFINED) { robot.keyPress(keyCode); robot.keyRelease(keyCode); robot.delay(50); } } } /** * 按下组合键(如Ctrl+C、Alt+F4) * @param keyCodes 键码数组(如new int[]{KeyEvent.VK_CONTROL, KeyEvent.VK_C}) */ public void pressCombinationKey(int[] keyCodes) { // 按下所有键 for (int keyCode : keyCodes) { robot.keyPress(keyCode); robot.delay(50); } // 释放所有键 for (int keyCode : keyCodes) { robot.keyRelease(keyCode); robot.delay(50); } } // ====================== 辅助方法 ====================== /** * 自动识别Windows系统的显示缩放比例(可选,需JNA依赖) * 若无JNA,建议手动传入(如1.25=125%) */ public static double getWindowsScaleRatio() { try { // 需引入JNA依赖(可选) // import com.sun.jna.platform.win32.User32; // import com.sun.jna.platform.win32.WinDef; // WinDef.HDC hdc = User32.INSTANCE.GetDC(null); // int dpi = User32.INSTANCE.GetDeviceCaps(hdc, 88); // 水平DPI // User32.INSTANCE.ReleaseDC(null, hdc); // return dpi / 96.0; // Windows默认DPI=96,120DPI=125% return 1.0; // 无JNA时默认1.0 } catch (Exception e) { return 1.0; } } // ====================== 测试示例 ====================== // public static void main(String[] args) { // try { // // 初始化工具类(Windows 125%缩放=1.25) // DesktopRobotUtil robotUtil = new DesktopRobotUtil(1.25); // // // 1. 精准点击(结合前文校准后的坐标) // int targetX = 1753; // 校准后的X // int targetY = 278; // 校准后的Y // robotUtil.leftClick(targetX, targetY); // System.out.println("已点击坐标:(" + targetX + "," + targetY + ")"); // // // 2. 滚轮向下滑动 // robotUtil.scrollWheel(-1, 5); // -1=向下,5=幅度 // System.out.println("已向下滑动滚轮5格"); // // // 3. 输入文本 // robotUtil.typeText("Hello World!"); // System.out.println("已输入文本:Hello World!"); // // // 4. 按下Ctrl+C // robotUtil.pressCombinationKey(new int[]{KeyEvent.VK_CONTROL, KeyEvent.VK_C}); // System.out.println("已按下Ctrl+C"); // // } catch (AWTException e) { // e.printStackTrace(); // } // } }

2.1 功能概述

DesktopRobotUtil是一个基于 Java AWTRobot类的工具类,用于模拟鼠标和键盘操作。支持以下功能:

  • 鼠标移动、点击(左键、右键、双击)
  • 滚轮滑动
  • 键盘输入(单字符、组合键)
  • 自动校准屏幕缩放比例

2.2 核心方法解析

鼠标操作

moveMouse(int x, int y)
将鼠标移动到指定物理像素坐标(自动根据缩放比例转换为逻辑像素)。

  • 参数x/y:校准后的屏幕坐标(物理像素)。
  • 内部逻辑:通过scaleRatio转换坐标,并限制在屏幕范围内。

leftClick(int x, int y)
移动到目标坐标后执行左键单击。

  • 调用moveMouse确保位置准确,再触发mousePressmouseRelease

doubleClick(int x, int y)
模拟人类双击行为,包含两次单击和合理的延迟。

  • 每次单击后增加 120ms 按压延迟,双击间隔 200ms。
键盘操作

typeText(String text)
逐字符输入文本,支持普通字符(跳过未定义键码的字符)。

  • 使用KeyEvent.getExtendedKeyCodeForChar转换字符为键码。

pressCombinationKey(int[] keyCodes)
按下并释放组合键(如Ctrl+C)。

  • 参数keyCodes:按顺序传入组合键的键码(如{KeyEvent.VK_CONTROL, KeyEvent.VK_C})。
滚轮操作

scrollWheel(int direction, int amount)
控制滚轮滑动方向和幅度。

  • direction:正数为向上,负数为向下。
  • amount:滑动幅度(推荐 1-10)。
注意事项
  1. 权限问题:某些操作系统可能需要特殊权限才能使用Robot
  2. 坐标范围:自动校验坐标是否在屏幕物理分辨率范围内。

3. OperationController 接口

@PostMapping("/operation/interact") public String interact(@RequestBody OparetionRequest request) throws NoApiKeyException, UploadFileException, IOException, AWTException { log.info("接收交互请求:{}", request); String result = oparetionService.operation(request); CoordinateMappingUtil.Point point; try { DesktopRobotUtil robotUtil = new DesktopRobotUtil(1.0); point = extractXY(result); robotUtil.doubleClick(point.getX(), point.getY()); log.info("已点击坐标:{}", point); } catch (Exception e) { log.error("交互异常", e); return "交互异常:" + e.getMessage(); } return String.valueOf(point); }

三、结果演示

如果觉得这份修改实用、总结清晰,别忘了动动小手点个赞👍,再关注一下呀~ 后续还会分享更多 AI 接口封装、代码优化的干货技巧,一起解锁更多好用的功能,少踩坑多提效!🥰 你的支持就是我更新的最大动力,咱们下次分享再见呀~🌟

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/4 15:39:07

Langchain-Chatchat实现多租户知识隔离的技术方案

Langchain-Chatchat 实现多租户知识隔离的技术方案 在企业智能化转型加速的今天,越来越多组织开始构建基于大语言模型(LLM)的本地知识库系统。然而,一个现实难题摆在面前:如何让多个部门、子公司甚至外部客户共享同一套…

作者头像 李华
网站建设 2026/5/10 17:21:28

震撼发现!GPT-5记忆系统不用RAG?四大层级架构详解(建议收藏)

本文通过逆向工程揭秘GPT-5记忆系统架构,发现其摒弃了传统向量数据库和RAG技术,转而采用四大层级:会话元数据、用户记忆、近期对话摘要和当前会话滑动窗口。这种分层设计既实现了个性化体验,又避免了高计算开销,在速度…

作者头像 李华
网站建设 2026/5/10 3:41:32

AI应用架构师主动学习实践:解决实际难题

AI应用架构师主动学习实践:解决实际难题 关键词:AI应用架构师、主动学习、实际难题、数据处理、模型优化、应用部署 摘要:本文深入探讨AI应用架构师在主动学习方面的实践,旨在解决实际工作中面临的各类难题。通过阐述主动学习的概…

作者头像 李华
网站建设 2026/5/1 7:29:31

Pandas库基础概念和基础操作

Pandas 是 Python 中用于数据分析和处理最流行的开源库之一,建立在 NumPy 之上,提供了高性能、易用的数据结构和数据分析工具。它特别适合处理结构化数据(如表格型或异质型数据)。以下是 Pandas 的基础概念详细介绍:一…

作者头像 李华
网站建设 2026/5/10 17:15:02

Langchain-Chatchat如何评估不同Embedding模型效果?

Langchain-Chatchat 如何科学评估不同 Embedding 模型效果? 在企业智能化浪潮中,一个反复出现的挑战是:如何让大模型真正“读懂”自家文档?通用语言模型虽然能写诗作曲,却对公司的报销流程、产品手册一无所知。于是&am…

作者头像 李华