news 2026/4/23 11:31:36

基于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/4/23 10:54:46

Langchain-Chatchat构建IT运维知识库的落地实践

Langchain-Chatchat构建IT运维知识库的落地实践 在企业IT系统日益复杂的今天,一线运维工程师常常面临一个尴尬的局面:明明公司有厚厚的《故障处理手册》《系统配置指南》和上百份应急响应文档,但当服务器突然宕机、数据库主从同步中断时&…

作者头像 李华
网站建设 2026/4/16 14:20:20

Langchain-Chatchat结合Neo4j图数据库的知识建模

Langchain-Chatchat 结合 Neo4j 图数据库的知识建模 在企业智能化转型的浪潮中,一个反复出现的挑战是:如何让 AI 助手真正“懂”自家的知识?通用大模型虽然能谈天说地,但面对内部文档、技术手册或组织架构时,往往答非所…

作者头像 李华
网站建设 2026/4/17 18:29:44

Langchain-Chatchat如何实现问答过程的日志审计?

Langchain-Chatchat 如何实现问答过程的日志审计? 在企业级 AI 应用日益普及的今天,一个看似简单的“问与答”背后,往往牵涉到数据安全、合规审查和责任追溯等严肃问题。尤其是在金融、医疗、政务等敏感领域,AI 不只是助手&#x…

作者头像 李华
网站建设 2026/4/18 6:07:38

随机森林(初步学习)

随机森林是一种集成学习(Ensemble Learning) 算法,核心思想是构建多个决策树,通过投票或平均的方式输出结果,以此降低单一决策树过拟合的风险,提升模型的泛化能力。它在机器学习的分类、回归、特征重要性评…

作者头像 李华