Path: blob/master/test/jdk/lib/client/ExtendedRobot.java
41144 views
/*1* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425import java.awt.AWTException;26import java.awt.Robot;27import java.awt.GraphicsDevice;28import java.awt.Toolkit;29import java.awt.Point;30import java.awt.MouseInfo;31import java.awt.event.InputEvent;32import java.awt.event.KeyEvent;3334/**35* ExtendedRobot is a subclass of {@link java.awt.Robot}. It provides some convenience methods that are36* ought to be moved to {@link java.awt.Robot} class.37* <p>38* ExtendedRobot uses delay {@link #getSyncDelay()} to make syncing threads with {@link #waitForIdle()}39* more stable. This delay can be set once on creating object and could not be changed throughout object40* lifecycle. Constructor reads vm integer property {@code java.awt.robotdelay} and sets the delay value41* equal to the property value. If the property was not set 500 milliseconds default value is used.42* <p>43* When using jtreg you would include this class via something like:44* <pre>45* {@literal @}library ../../../../lib/testlibrary46* {@literal @}build ExtendedRobot47* </pre>48*49* @author Dmitriy Ermashov50* @since 951*/5253public class ExtendedRobot extends Robot {5455private static int DEFAULT_SPEED = 20; // Speed for mouse glide and click56private static int DEFAULT_SYNC_DELAY = 500; // Default Additional delay for waitForIdle()57private static int DEFAULT_STEP_LENGTH = 2; // Step length (in pixels) for mouse glide5859private final int syncDelay = DEFAULT_SYNC_DELAY;6061//TODO: uncomment three lines below after moving functionality to java.awt.Robot62//{63// syncDelay = AccessController.doPrivileged(new GetIntegerAction("java.awt.robotdelay", DEFAULT_SYNC_DELAY));64//}6566/**67* Constructs an ExtendedRobot object in the coordinate system of the primary screen.68*69* @throws AWTException if the platform configuration does not allow low-level input70* control. This exception is always thrown when71* GraphicsEnvironment.isHeadless() returns true72* @throws SecurityException if {@code createRobot} permission is not granted73*74* @see java.awt.GraphicsEnvironment#isHeadless75* @see SecurityManager#checkPermission76* @see java.awt.AWTPermission77*/78public ExtendedRobot() throws AWTException {79super();80}8182/**83* Creates an ExtendedRobot for the given screen device. Coordinates passed84* to ExtendedRobot method calls like mouseMove and createScreenCapture will85* be interpreted as being in the same coordinate system as the specified screen.86* Note that depending on the platform configuration, multiple screens may either:87* <ul>88* <li>share the same coordinate system to form a combined virtual screen</li>89* <li>use different coordinate systems to act as independent screens</li>90* </ul>91* This constructor is meant for the latter case.92* <p>93* If screen devices are reconfigured such that the coordinate system is94* affected, the behavior of existing ExtendedRobot objects is undefined.95*96* @param screen A screen GraphicsDevice indicating the coordinate97* system the Robot will operate in.98* @throws AWTException if the platform configuration does not allow low-level input99* control. This exception is always thrown when100* GraphicsEnvironment.isHeadless() returns true.101* @throws IllegalArgumentException if {@code screen} is not a screen102* GraphicsDevice.103* @throws SecurityException if {@code createRobot} permission is not granted104*105* @see java.awt.GraphicsEnvironment#isHeadless106* @see GraphicsDevice107* @see SecurityManager#checkPermission108* @see java.awt.AWTPermission109*/110public ExtendedRobot(GraphicsDevice screen) throws AWTException {111super(screen);112}113114/**115* Returns delay length for {@link #waitForIdle()} method116*117* @return Current delay value118*119* @see #waitForIdle()120*/121public int getSyncDelay(){ return this.syncDelay; }122123/**124* Clicks mouse button(s) by calling {@link java.awt.Robot#mousePress(int)} and125* {@link java.awt.Robot#mouseRelease(int)} methods126*127*128* @param buttons The button mask; a combination of one or more mouse button masks.129* @throws IllegalArgumentException if the {@code buttons} mask contains the mask for130* extra mouse button and support for extended mouse buttons is131* {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java132* @throws IllegalArgumentException if the {@code buttons} mask contains the mask for133* extra mouse button that does not exist on the mouse and support for extended134* mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() enabled}135* by Java136*137* @see #mousePress(int)138* @see #mouseRelease(int)139* @see InputEvent#getMaskForButton(int)140* @see Toolkit#areExtraMouseButtonsEnabled()141* @see java.awt.event.MouseEvent142*/143public void click(int buttons) {144mousePress(buttons);145waitForIdle(DEFAULT_SPEED);146mouseRelease(buttons);147waitForIdle();148}149150/**151* Clicks mouse button 1152*153* @throws IllegalArgumentException if the {@code buttons} mask contains the mask for154* extra mouse button and support for extended mouse buttons is155* {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java156* @throws IllegalArgumentException if the {@code buttons} mask contains the mask for157* extra mouse button that does not exist on the mouse and support for extended158* mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() enabled}159* by Java160*161* @see #click(int)162*/163public void click() {164click(InputEvent.BUTTON1_DOWN_MASK);165}166167/**168* Waits until all events currently on the event queue have been processed with given169* delay after syncing threads. It uses more advanced method of synchronizing threads170* unlike {@link java.awt.Robot#waitForIdle()}171*172* @param delayValue Additional delay length in milliseconds to wait until thread173* sync been completed174* @throws sun.awt.SunToolkit.IllegalThreadException if called on the AWT event175* dispatching thread176*/177public synchronized void waitForIdle(int delayValue) {178super.waitForIdle();179delay(delayValue);180}181182/**183* Waits until all events currently on the event queue have been processed with delay184* {@link #getSyncDelay()} after syncing threads. It uses more advanced method of185* synchronizing threads unlike {@link java.awt.Robot#waitForIdle()}186*187* @throws sun.awt.SunToolkit.IllegalThreadException if called on the AWT event188* dispatching thread189*190* @see #waitForIdle(int)191*/192@Override193public synchronized void waitForIdle() {194waitForIdle(syncDelay);195}196197/**198* Move the mouse in multiple steps from where it is199* now to the destination coordinates.200*201* @param x Destination point x coordinate202* @param y Destination point y coordinate203*204* @see #glide(int, int, int, int)205*/206public void glide(int x, int y) {207Point p = MouseInfo.getPointerInfo().getLocation();208glide(p.x, p.y, x, y);209}210211/**212* Move the mouse in multiple steps from where it is213* now to the destination point.214*215* @param dest Destination point216*217* @see #glide(int, int)218*/219public void glide(Point dest) {220glide(dest.x, dest.y);221}222223/**224* Move the mouse in multiple steps from source coordinates225* to the destination coordinates.226*227* @param fromX Source point x coordinate228* @param fromY Source point y coordinate229* @param toX Destination point x coordinate230* @param toY Destination point y coordinate231*232* @see #glide(int, int, int, int, int, int)233*/234public void glide(int fromX, int fromY, int toX, int toY) {235glide(fromX, fromY, toX, toY, DEFAULT_STEP_LENGTH, DEFAULT_SPEED);236}237238/**239* Move the mouse in multiple steps from source point to the240* destination point with default speed and step length.241*242* @param src Source point243* @param dest Destination point244*245* @see #glide(int, int, int, int, int, int)246*/247public void glide(Point src, Point dest) {248glide(src.x, src.y, dest.x, dest.y, DEFAULT_STEP_LENGTH, DEFAULT_SPEED);249}250251/**252* Move the mouse in multiple steps from source point to the253* destination point with given speed and step length.254*255* @param srcX Source point x cordinate256* @param srcY Source point y cordinate257* @param destX Destination point x cordinate258* @param destY Destination point y cordinate259* @param stepLength Approximate length of one step260* @param speed Delay between steps.261*262* @see #mouseMove(int, int)263* @see #delay(int)264*/265public void glide(int srcX, int srcY, int destX, int destY, int stepLength, int speed) {266int stepNum;267double tDx, tDy;268double dx, dy, ds;269double x, y;270271dx = (destX - srcX);272dy = (destY - srcY);273ds = Math.sqrt(dx*dx + dy*dy);274275tDx = dx / ds * stepLength;276tDy = dy / ds * stepLength;277278int stepsCount = (int) ds / stepLength;279280// Walk the mouse to the destination one step at a time281mouseMove(srcX, srcY);282283for (x = srcX, y = srcY, stepNum = 0;284stepNum < stepsCount;285stepNum++) {286x += tDx;287y += tDy;288mouseMove((int)x, (int)y);289delay(speed);290}291292// Ensure the mouse moves to the right destination.293// The steps may have led the mouse to a slightly wrong place.294mouseMove(destX, destY);295}296297/**298* Moves mouse pointer to given screen coordinates.299*300* @param position Target position301*302* @see java.awt.Robot#mouseMove(int, int)303*/304public synchronized void mouseMove(Point position) {305mouseMove(position.x, position.y);306}307308309/**310* Emulate native drag and drop process using {@code InputEvent.BUTTON1_DOWN_MASK}.311* The method successively moves mouse cursor to point with coordinates312* ({@code fromX}, {@code fromY}), presses mouse button 1, drag mouse to313* point with coordinates ({@code toX}, {@code toY}) and releases mouse314* button 1 at last.315*316* @param fromX Source point x coordinate317* @param fromY Source point y coordinate318* @param toX Destination point x coordinate319* @param toY Destination point y coordinate320*321* @see #mousePress(int)322* @see #glide(int, int, int, int)323*/324public void dragAndDrop(int fromX, int fromY, int toX, int toY){325mouseMove(fromX, fromY);326mousePress(InputEvent.BUTTON1_DOWN_MASK);327waitForIdle();328glide(toX, toY);329mouseRelease(InputEvent.BUTTON1_DOWN_MASK);330waitForIdle();331}332333/**334* Emulate native drag and drop process using {@code InputEvent.BUTTON1_DOWN_MASK}.335* The method successively moves mouse cursor to point {@code from},336* presses mouse button 1, drag mouse to point {@code to} and releases337* mouse button 1 at last.338*339* @param from Source point340* @param to Destination point341*342* @see #mousePress(int)343* @see #glide(int, int, int, int)344* @see #dragAndDrop(int, int, int, int)345*/346public void dragAndDrop(Point from, Point to){347dragAndDrop(from.x, from.y, to.x, to.y);348}349350/**351* Successively presses and releases a given key.352* <p>353* Key codes that have more than one physical key associated with them354* (e.g. {@code KeyEvent.VK_SHIFT} could mean either the355* left or right shift key) will map to the left key.356*357* @param keycode Key to press (e.g. {@code KeyEvent.VK_A})358* @throws IllegalArgumentException if {@code keycode} is not359* a valid key360*361* @see java.awt.Robot#keyPress(int)362* @see java.awt.Robot#keyRelease(int)363* @see java.awt.event.KeyEvent364*/365public void type(int keycode) {366keyPress(keycode);367waitForIdle(DEFAULT_SPEED);368keyRelease(keycode);369waitForIdle(DEFAULT_SPEED);370}371372/**373* Types given character374*375* @param c Character to be typed (e.g. {@code 'a'})376*377* @see #type(int)378* @see java.awt.event.KeyEvent379*/380public void type(char c) {381type(KeyEvent.getExtendedKeyCodeForChar(c));382}383384/**385* Types given array of characters one by one386*387* @param symbols Array of characters to be typed388*389* @see #type(char)390*/391public void type(char[] symbols) {392for (int i = 0; i < symbols.length; i++) {393type(symbols[i]);394}395}396397/**398* Types given string399*400* @param s String to be typed401*402* @see #type(char[])403*/404public void type(String s) {405type(s.toCharArray());406}407}408409410