java Robot源码解析(史上最全)

简介:此类用于生成本机系统输入事件,出于测试自动化、自运行演示和其他可以控制鼠标和键盘的应用程序这是需要的。机器人的主要目的是方便用户Java平台实现的自动化测试

方法介绍及解析:以下private开头方法为Robot内部使用,方法,public方法为对外开放方法,请重点关注public方法

Robot中对外提供接口
使用要点代码示例说明
1.实例化方法new Robot();无参实例化,详见1
new Robot(
GraphicsEnvironment.getLocalGraphicsEnvironment()
    .getDefaultScreenDevice());
带参实例化,详见2
2.屏幕截图Robot robot = new Robot();  //初始化Robot对象
    Rectangle rect = new Rectangle(0, 0, 50, 50);  //构建范围
    BufferedImage buffer = robot.createScreenCapture(rect); //截取
详见17,截取固定区域屏幕图片
3.延时休眠robot.delay(1000);//延时1秒,详见23
4.键盘模拟robot.keyPress(KeyEvent.VK_A);按下A键,键盘上所有按键的ASCII码都在KeyEvent中定义了静态常量
robot.keyRelease(KeyEvent.VK_A);弹起A键
5.鼠标模拟robot.mouseMove(10,20);将鼠标移动至(10,20)这个坐标点

robot.mousePress(InputEvent.BUTTON1_MASK);//左键

robot.mousePress(InputEvent.BUTTON2_MASK);//中键(早期鼠标才有,已被滚轮替代)

robot.mousePress(InputEvent.BUTTON3_MASK)//右键

鼠标按下事件

robot.mouseRelease(InputEvent.BUTTON1_MASK);//左键

robot.mouseRelease(InputEvent.BUTTON2_MASK);//中键(早期鼠标才有,已被滚轮替代)

robot.mouseRelease(InputEvent.BUTTON3_MASK)//右键

鼠标弹起事件
robot.mouseWheel(key);鼠标滚轮事件,详见12

1.Robot无参构造方法:此方法作用是在主屏幕构建机器人对象。GraphicsEnvironment.isHeadless()此方法是测试当前服务器鼠标键盘是否支持GraphicsEnvironment.getLocalGraphicsEnvironment() .getDefaultScreenDevice(),其中GraphicsEnvironment.getLocalGraphicsEnvironment()为获取当前系统环境,getDefaultScreenDevice为获取默认屏幕设备

init方法为将此屏幕初始化进Robot对象中,iinit()方法详解见下文第3点

    public Robot() throws AWTException {
        if (GraphicsEnvironment.isHeadless()) {
            throw new AWTException("headless environment");
        }
        init(GraphicsEnvironment.getLocalGraphicsEnvironment()
            .getDefaultScreenDevice());
    }

2.Robot带参构造方法:此方法作用为给定屏幕创建机器人对象(注意此方法重点,实现钩子函数必须掌握,可在后台运行得点击脚本会依赖此方法)

checkIsScreenDevice:检查screen是否为屏幕设备

init方法为将此屏幕初始化进Robot对象中,init()方法详解见下文第3点

    public Robot(GraphicsDevice screen) throws AWTException {
        checkIsScreenDevice(screen);
        init(screen);
    }

3.init方法:初始化屏幕,将屏幕写入服务内存中

checkRobotAllowed:检查当前设备安全策略是否允许创建机器人

Toolkit toolkit = Toolkit.getDefaultToolkit();//获取默认工具箱,此方法加入synchronized标识,即为线程安全,判断Toolkit是否为ComponentFactory工具包

初始化RobotPeer

初始化机器人处理器RobotDisposer

sun.java2d.Disposer.addRecord(anchor, disposer);//将机器人处理器加入window系统处理器中,此代码含义是执行调用windows底层处理器

initLegalButtonMask:初始化鼠标按钮掩码,详见第4点

private void init(GraphicsDevice screen) throws AWTException {
        checkRobotAllowed();
        Toolkit toolkit = Toolkit.getDefaultToolkit();
        if (toolkit instanceof ComponentFactory) {
            peer = ((ComponentFactory)toolkit).createRobot(this, screen);
            disposer = new RobotDisposer(peer);
            sun.java2d.Disposer.addRecord(anchor, disposer);
        }
        initLegalButtonMask();
    }

 4.initLegalButtonMask:初始化合法的鼠标按钮掩码(所谓掩码即为ASCII码)。

  • 判定按钮使用标识LEGAL_BUTTON_MASK,0为默认未使用,1为已使用
  • 判定默认工具箱中是否允许处理和发布额外的鼠标按钮事件
  • 获取鼠标按钮数
  • 将鼠标按钮值做位或运算,并存入tmpMask中
    private static synchronized void initLegalButtonMask() {
        if (LEGAL_BUTTON_MASK != 0) return;

        int tmpMask = 0;
        if (Toolkit.getDefaultToolkit().areExtraMouseButtonsEnabled()){
            if (Toolkit.getDefaultToolkit() instanceof SunToolkit) {
                final int buttonsNumber = ((SunToolkit)(Toolkit.getDefaultToolkit())).getNumberOfButtons();
                for (int i = 0; i < buttonsNumber; i++){
                    tmpMask |= InputEvent.getMaskForButton(i+1);
                }
            }
        }
        tmpMask |= InputEvent.BUTTON1_MASK|
            InputEvent.BUTTON2_MASK|
            InputEvent.BUTTON3_MASK|
            InputEvent.BUTTON1_DOWN_MASK|
            InputEvent.BUTTON2_DOWN_MASK|
            InputEvent.BUTTON3_DOWN_MASK;
        LEGAL_BUTTON_MASK = tmpMask;
    }

5.checkRobotAllowed:判定当前设备的安全策略机制

  • 获取当前系统安全管理器
  • 检测安全管理器是否允许创建Robot机器人
private void checkRobotAllowed() {
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            security.checkPermission(SecurityConstants.AWT.CREATE_ROBOT_PERMISSION);
        }
    }

6.checkIsScreenDevice:检测屏幕设备。检测device是否是一个屏幕设备

    private void checkIsScreenDevice(GraphicsDevice device) {
        if (device == null || device.getType() != GraphicsDevice.TYPE_RASTER_SCREEN) {
            throw new IllegalArgumentException("not a valid screen device");
        }
    }

7.RobotDisposer :机器人处理器类

    static class RobotDisposer implements sun.java2d.DisposerRecord {
        private final RobotPeer peer;
        public RobotDisposer(RobotPeer peer) {
            this.peer = peer;
        }
        public void dispose() {
            if (peer != null) {
                peer.dispose();
            }
        }
    }

8.mouseMove:鼠标移动方法(线程安全),其中x,y为当前设备像素点

    public synchronized void mouseMove(int x, int y) {
        peer.mouseMove(x, y);
        afterEvent();
    }

9:mousePress:鼠标按下事件,传入的参数buttons,为鼠标哪一个键,其常用参数如下

InputEvent.BUTTON1_MASK:鼠标左键

InputEvent.BUTTON2_MASK:鼠标滚轮

InputEvent.BUTTON3_MASK:鼠标右键

    public synchronized void mousePress(int buttons) {
        checkButtonsArgument(buttons);
        peer.mousePress(buttons);
        afterEvent();
    }

10:mouseRelease:鼠标弹起事件,传入的参数和mousePress类似,此方法一般和mousePress联合使用,按下鼠标的同时也会弹起鼠标。

  • checkButtonsArgument:检查按钮的标志组合
  • peer.mouseRelease(buttons):调用window底层,在当前屏幕将buttons按钮弹起
  • afterEvent:生成事件后调用,见下文
    public synchronized void mouseRelease(int buttons) {
        checkButtonsArgument(buttons);
        peer.mouseRelease(buttons);
        afterEvent();
    }

11.checkButtonsArgument:检查按钮参数

    private void checkButtonsArgument(int buttons) {
        if ( (buttons|LEGAL_BUTTON_MASK) != LEGAL_BUTTON_MASK ) {
            throw new IllegalArgumentException("Invalid combination of button flags");
        }
    }

12.mouseWheel:鼠标滚动事件,wheelAmt为鼠标滚动的刻度,如果wheelAmt大于0则向上滚动,如果小于0则向下滚动,例如向上滚动一个刻度,则robot.mouseWheel(1)

public synchronized void mouseWheel(int wheelAmt) {
        peer.mouseWheel(wheelAmt);
        afterEvent();
    }

13.keyPress:按钮按下事件(此类所有int入参都是ASCII进制码)

    public synchronized void keyPress(int keycode) {
        checkKeycodeArgument(keycode);
        peer.keyPress(keycode);
        afterEvent();
    }

14.keyRelease:按钮弹起事件

    public synchronized void keyRelease(int keycode) {
        checkKeycodeArgument(keycode);
        peer.keyRelease(keycode);
        afterEvent();
    }

15.checkKeycodeArgument:检测按钮是否定义

    private void checkKeycodeArgument(int keycode) {
        if (keycode == KeyEvent.VK_UNDEFINED) {
            throw new IllegalArgumentException("Invalid key code");
        }
    }

16.getPixelColor:返回给定坐标屏幕的颜色

    public synchronized Color getPixelColor(int x, int y) {
        Color color = new Color(peer.getRGBPixel(x, y));
        return color;
    }

17.创建包含从屏幕读取的像素的图像。这张照片确实如此不包括鼠标光标

@param screenRect 要在屏幕坐标中捕获,

checkScreenCaptureAllowed:检测当前设备是否被允许读取屏幕像素:不能则会抛出异常

checkValidRect:检测screeRect宽度和高度,如果screeRect宽度和高度小于等于0,则抛出IllegalArgumentException

后半部分为读取图像

    public synchronized BufferedImage createScreenCapture(Rectangle screenRect) {
        checkScreenCaptureAllowed();

        checkValidRect(screenRect);

        BufferedImage image;
        DataBufferInt buffer;
        WritableRaster raster;

        if (screenCapCM == null) {
            /*
             * Fix for 4285201
             * Create a DirectColorModel equivalent to the default RGB ColorModel,
             * except with no Alpha component.
             */

            screenCapCM = new DirectColorModel(24,
                                               /* red mask */    0x00FF0000,
                                               /* green mask */  0x0000FF00,
                                               /* blue mask */   0x000000FF);
        }

        // need to sync the toolkit prior to grabbing the pixels since in some
        // cases rendering to the screen may be delayed
        Toolkit.getDefaultToolkit().sync();

        int pixels[];
        int[] bandmasks = new int[3];

        pixels = peer.getRGBPixels(screenRect);
        buffer = new DataBufferInt(pixels, pixels.length);

        bandmasks[0] = screenCapCM.getRedMask();
        bandmasks[1] = screenCapCM.getGreenMask();
        bandmasks[2] = screenCapCM.getBlueMask();

        raster = Raster.createPackedRaster(buffer, screenRect.width, screenRect.height, screenRect.width, bandmasks, null);
        SunWritableRaster.makeTrackable(buffer);

        image = new BufferedImage(screenCapCM, raster, false, null);

        return image;
    }

18.checkValidRect:检查坐标

    private static void checkValidRect(Rectangle rect) {
        if (rect.width <= 0 || rect.height <= 0) {
            throw new IllegalArgumentException("Rectangle width and height must be > 0");
        }
    }

19.checkScreenCaptureAllowed:检查读取像素权限

    private static void checkScreenCaptureAllowed() {
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            security.checkPermission(
                SecurityConstants.AWT.READ_DISPLAY_PIXELS_PERMISSION);
        }
    }

20.afterEvent:事件后调用函数,此方法为内部方法

    private void afterEvent() {
        autoWaitForIdle();
        autoDelay();
    }

21.参数isAutoWaitForIdle的set和get方法

    public synchronized boolean isAutoWaitForIdle() {
        return isAutoWaitForIdle;
    }
    public synchronized void setAutoWaitForIdle(boolean isOn) {
        isAutoWaitForIdle = isOn;
    }

21.autoWaitForIdle:判定是否自动调用

private void autoWaitForIdle() {
    if (isAutoWaitForIdle) {
        waitForIdle();
    }
}

22.此方法为autoDelay的set和get方法,如果你是用robot编写按键脚本,建议每次调用事件aotoDelay设置为一个随机数,防止被服务器检测出来

public synchronized int getAutoDelay() {
        return autoDelay;
    }
public synchronized void setAutoDelay(int ms) {
        checkDelayArgument(ms);
        autoDelay = ms;
    }

23.delay:主线程休眠,其中ms为多少毫秒

    public synchronized void delay(int ms) {
        checkDelayArgument(ms);
        try {
            Thread.sleep(ms);
        } catch(InterruptedException ite) {
            ite.printStackTrace();
        }
    }

24.checkDelayArgument:延迟参数检测方法,该参数必须大于0且小于60s

    private void checkDelayArgument(int ms) {
        if (ms < 0 || ms > MAX_DELAY) {
            throw new IllegalArgumentException("Delay must be to 0 to 60,000ms");
        }
    }

25:waitForIdle:等待事件队列中当前所有事件处理完毕

    public synchronized void waitForIdle() {
        checkNotDispatchThread();
        // post a dummy event to the queue so we know when
        // all the events before it have been processed
        try {
            SunToolkit.flushPendingEvents();
            EventQueue.invokeAndWait( new Runnable() {
                                            public void run() {
                                                // dummy implementation
                                            }
                                        } );
        } catch(InterruptedException ite) {
            System.err.println("Robot.waitForIdle, non-fatal exception caught:");
            ite.printStackTrace();
        } catch(InvocationTargetException ine) {
            System.err.println("Robot.waitForIdle, non-fatal exception caught:");
            ine.printStackTrace();
        }
    }

26.checkNotDispatchThread:检测还未分派的线程,如果队里中存在,将抛出异常,Cannot call method from the event dispatcher thread(无法从事件调度程序线程调用方法)

    private void checkNotDispatchThread() {
        if (EventQueue.isDispatchThread()) {
            throw new IllegalThreadStateException("Cannot call method from the event dispatcher thread");
        }
    }

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
JavaRobot类详解 概述 概述 JavaRobot类位于java.awt.Robot,该类⽤于为测试⾃动化,⾃运⾏演⽰程序和其他需要控制⿏标和键盘的应⽤程序⽣成本机系统输⼊ 事件,Robot类的主要⽬的是便于Java平台实现⾃动测试。 Robot可以模拟⿏标和键盘的输⼊,相当于Java版的按键精灵。 常⽤⽅法 常⽤⽅法 1.创建实例 Robot robot = new Robot(); 2.延时函数 robot.delay(毫秒值); 3.⿏标按下 robot.mousePress(⿏标上的按键); //⿏标左键:InputEvent.BUTTON1_DOWN_MASK //⿏标中键:InputEvent.BUTTON2_DOWN_MASK //⿏标右键:InputEvent.BUTTON3_DOWN_MASK 4.⿏标释放 robot.mouseRelease(⿏标上的按键); //⿏标左键:InputEvent.BUTTON1_DOWN_MASK //⿏标中键:InputEvent.BUTTON2_DOWN_MASK //⿏标右键:InputEvent.BUTTON3_DOWN_MASK 5.⿏标移动 //⿏标移动到指定位置 robot.mouseMove(int x,int y); 6.⿏标滚轮滑动 //⿏标滚动(参数⼩于0,表⽰向上滚动;参数⼤于0,表⽰向下滚动) robot.mouseWheel(int wheelAmt); 7.键盘按下指定的键 //键盘按下指定的键-----keycode:键盘键值常量,定义在KeyEvent.VK_XXX 中 //KeyEvent.VK_WINDOWS:键盘上的windows键 //KeyEvent.VK_CONTROL:键盘上的ctrl键 //KeyEvent.VK_L:键盘上的L键 robot.keyPress(int keycode); 8.键盘释放指定的键 //键盘按下指定的键-----keycode:键盘键值常量,定义在KeyEvent.VK_XXX 中 //KeyEvent.VK_WINDOWS:键盘上的windows键 //KeyEvent.VK_CONTROL:键盘上的ctrl键 //KeyEvent.VK_L:键盘上的L键 robot.keyRelease(int keycode); 9.获取屏幕指定坐标处像素颜⾊ //获取指定坐标处的像素颜⾊ Color color=robot.getPixelColor(int x,int y); 10.截取指定区域的图像(截图功能) //获取指定矩形区域的图像(截图) BufferedImage bufferedimage=robot.createScreenCapture(Rectangle screenRect); ⽰例:截取指定矩形区域的图像,并保存到指定的路径 public static void main(String[] args) throws AWTException, IOException { Robot robot=new Robot(); //获取指定矩形区域的屏幕图像 BufferedImage bufferedImage=robot.createScreenCapture(new Rectangle(100,100,500,500)); File f=new File("D:\\save.jpg"); OutputStream os=new FileOutputStream(f); ImageIO.write(bufferedImage, "jpg", os); } ⽰例:在指定区域⾃动输⼊指定字符 robot.mouseMove(342, 626); robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); robot.delay(500); robot.keyPress(KeyEvent.VK_L); robot.keyRelease(KeyEvent.VK_L); robot.delay(500); robot.keyPress(KeyEvent.VK_O); robot.keyRelease(KeyEvent.VK_O); robot.delay(500); robot.keyPress(KeyEvent.VK_V); robot.keyRelease(KeyEvent.VK_V); robot.delay(500); robot.keyPress(KeyEvent.VK_E); robot.keyRelease(KeyEvent.VK_E)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

疯狂攻城师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值