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

目录

一、引言

二、代码实现

[1. 新增工具类 CoordinateExtractUtil](#1. 新增工具类 CoordinateExtractUtil)

[1.1 核心方法说明](#1.1 核心方法说明)

[2. DesktopRobotUtil 修改](#2. DesktopRobotUtil 修改)

[2.1 功能概述](#2.1 功能概述)

[2.2 核心方法解析](#2.2 核心方法解析)

鼠标操作

键盘操作

滚轮操作

注意事项

[3. OperationController 接口](#3. OperationController 接口)

三、结果演示


一、引言

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

二、代码实现

1. 新增工具类 CoordinateExtractUtil

java 复制代码
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 修改

java 复制代码
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 AWT Robot 类的工具类,用于模拟鼠标和键盘操作。支持以下功能:

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

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 接口

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

相关推荐
用户3721574261352 小时前
Python 实现 PDF 文档压缩:完整指南
java
ew452182 小时前
【JAVA】实现word的DOCX/DOC文档内容替换、套打、支持表格内容替换。
java·开发语言·word
贺今宵2 小时前
装Maven并在idea上配置
java·maven·intellij-idea
企微自动化2 小时前
企业微信外部群自动化系统的异常处理机制设计
开发语言·python
我不是小upper2 小时前
ARIMA-LSTM-Prophet 融合模型在股票预测中的应用
人工智能·rnn·lstm
黑客思维者2 小时前
机器学习008:监督学习【回归算法】(逻辑回归)--AI世界的“是非判断题大师”
人工智能·学习·机器学习·逻辑回归
墨&白.2 小时前
如何卸载/更新Mac上的R版本
开发语言·macos·r语言
1张驰咨询12 小时前
智慧城市交付困局:用六西格玛培训,将项目毛利从行业平均的12%提升至龙头水平的22%
人工智能·职场和发展·智慧城市·六西格玛
AI营销资讯站2 小时前
AI营销内容生产领域原圈科技多智能体系统优势分析
大数据·人工智能