当前位置: 首页 > news >正文

基于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 接口封装、代码优化的干货技巧,一起解锁更多好用的功能,少踩坑多提效!🥰 你的支持就是我更新的最大动力,咱们下次分享再见呀~🌟

http://www.cnnetsun.cn/news/161234.html

相关文章:

  • Langchain-Chatchat能否导出知识图谱可视化结果?
  • Spring boot社区医院管理系统信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】
  • 前后端分离MVC自习室管理和预约系统系统|SpringBoot+Vue+MyBatis+MySQL完整源码+部署教程
  • 【必收藏】LangGraph深度研究智能体实战:LangChain官方OpenDeepResearch完整源码解析与本地部署指南
  • 清华/人大/新国大联合发布:AI Agent记忆系统全面解析,解决灾难性遗忘与上下文溢出问题
  • Langchain-Chatchat如何评估知识库问答的准确性?
  • 大语言模型的 “思考” 秘密:一文读懂 prompt 工程核心逻辑
  • Langchain-Chatchat支持Excel表格内容作为知识源吗?
  • 多智能体系统在竞争优势分析中的应用:寻找护城河
  • AI生成的音乐,到底能商用吗
  • Linux GPIO-KEYS
  • OmniThoughtV:面向多模态深度思考的高质量数据蒸馏
  • 面试不是考试,而是“技术交流与信任构建”
  • 45、WPF 打印与 XPS 文档处理全解析
  • 46、WPF应用开发:从打印到过渡效果与世界浏览器应用构建
  • 【仿真测试】基于FPGA的完整64QAM通信链路实现,含频偏锁定,帧同步,定时点,Viterbi译码,信道,误码统计
  • Day35:DMA 原理与架构
  • Java如何通过组件优化WebUploader分片上传效率?
  • 阿里云客服支持与服务状态查询指南
  • 【毕业设计】SpringBoot+Vue+MySQL Spring Boot校园闲置物品交易系统平台源码+数据库+论文+部署文档
  • 11、Hyper-V与VMM 2008:服务器虚拟化的利器
  • 手把手教你用Dify接入本地大模型:AI知识库实战教程!
  • Scrapy框架实战教程:从入门到精通的专业爬虫开发指南(包含python环境配置)
  • 联想摩托罗拉与鸿日达设立3D打印联合实验室,开展通信设备轻量化及结构设计
  • 技术解读“创世纪计划”:架构、协作与开源挑战
  • ETSC:挖掘潜力,减少与工作相关的道路交通伤亡事故(英) 2025
  • Langchain-Chatchat问答系统灰度期间服务可用性保障
  • Activiti7工作流(八)流程变量
  • Langchain-Chatchat能否支持文档标签分类管理?
  • Langchain-Chatchat能否支持文档访问统计?