0N/A/*
2362N/A * Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage java.awt;
0N/A
430N/Aimport java.awt.event.InputEvent;
430N/Aimport java.awt.event.KeyEvent;
430N/Aimport java.awt.image.BufferedImage;
430N/Aimport java.awt.image.DataBufferInt;
430N/Aimport java.awt.image.DirectColorModel;
430N/Aimport java.awt.image.Raster;
430N/Aimport java.awt.image.WritableRaster;
430N/Aimport java.awt.peer.RobotPeer;
0N/Aimport java.lang.reflect.InvocationTargetException;
0N/Aimport sun.awt.ComponentFactory;
0N/Aimport sun.awt.SunToolkit;
430N/Aimport sun.awt.image.SunWritableRaster;
0N/Aimport sun.security.util.SecurityConstants;
0N/A
0N/A/**
0N/A * This class is used to generate native system input events
0N/A * for the purposes of test automation, self-running demos, and
0N/A * other applications where control of the mouse and keyboard
0N/A * is needed. The primary purpose of Robot is to facilitate
0N/A * automated testing of Java platform implementations.
0N/A * <p>
0N/A * Using the class to generate input events differs from posting
0N/A * events to the AWT event queue or AWT components in that the
0N/A * events are generated in the platform's native input
0N/A * queue. For example, <code>Robot.mouseMove</code> will actually move
0N/A * the mouse cursor instead of just generating mouse move events.
0N/A * <p>
0N/A * Note that some platforms require special privileges or extensions
0N/A * to access low-level input control. If the current platform configuration
0N/A * does not allow input control, an <code>AWTException</code> will be thrown
0N/A * when trying to construct Robot objects. For example, X-Window systems
0N/A * will throw the exception if the XTEST 2.2 standard extension is not supported
0N/A * (or not enabled) by the X server.
0N/A * <p>
0N/A * Applications that use Robot for purposes other than self-testing should
0N/A * handle these error conditions gracefully.
0N/A *
0N/A * @author Robi Khan
0N/A * @since 1.3
0N/A */
0N/Apublic class Robot {
0N/A private static final int MAX_DELAY = 60000;
0N/A private RobotPeer peer;
0N/A private boolean isAutoWaitForIdle = false;
0N/A private int autoDelay = 0;
1398N/A private static int LEGAL_BUTTON_MASK = 0;
0N/A
0N/A // location of robot's GC, used in mouseMove(), getPixelColor() and captureScreenImage()
0N/A private Point gdLoc;
0N/A
0N/A private DirectColorModel screenCapCM = null;
0N/A
0N/A /**
0N/A * Constructs a Robot object in the coordinate system of the primary screen.
0N/A * <p>
0N/A *
0N/A * @throws AWTException if the platform configuration does not allow
0N/A * low-level input control. This exception is always thrown when
0N/A * GraphicsEnvironment.isHeadless() returns true
0N/A * @throws SecurityException if <code>createRobot</code> permission is not granted
0N/A * @see java.awt.GraphicsEnvironment#isHeadless
0N/A * @see SecurityManager#checkPermission
0N/A * @see AWTPermission
0N/A */
0N/A public Robot() throws AWTException {
0N/A if (GraphicsEnvironment.isHeadless()) {
0N/A throw new AWTException("headless environment");
0N/A }
0N/A init(GraphicsEnvironment.getLocalGraphicsEnvironment()
0N/A .getDefaultScreenDevice());
0N/A }
0N/A
0N/A /**
0N/A * Creates a Robot for the given screen device. Coordinates passed
0N/A * to Robot method calls like mouseMove and createScreenCapture will
0N/A * be interpreted as being in the same coordinate system as the
0N/A * specified screen. Note that depending on the platform configuration,
0N/A * multiple screens may either:
0N/A * <ul>
0N/A * <li>share the same coordinate system to form a combined virtual screen</li>
0N/A * <li>use different coordinate systems to act as independent screens</li>
0N/A * </ul>
0N/A * This constructor is meant for the latter case.
0N/A * <p>
0N/A * If screen devices are reconfigured such that the coordinate system is
0N/A * affected, the behavior of existing Robot objects is undefined.
0N/A *
0N/A * @param screen A screen GraphicsDevice indicating the coordinate
0N/A * system the Robot will operate in.
0N/A * @throws AWTException if the platform configuration does not allow
0N/A * low-level input control. This exception is always thrown when
0N/A * GraphicsEnvironment.isHeadless() returns true.
0N/A * @throws IllegalArgumentException if <code>screen</code> is not a screen
0N/A * GraphicsDevice.
0N/A * @throws SecurityException if <code>createRobot</code> permission is not granted
0N/A * @see java.awt.GraphicsEnvironment#isHeadless
0N/A * @see GraphicsDevice
0N/A * @see SecurityManager#checkPermission
0N/A * @see AWTPermission
0N/A */
0N/A public Robot(GraphicsDevice screen) throws AWTException {
0N/A checkIsScreenDevice(screen);
0N/A init(screen);
0N/A }
0N/A
0N/A private void init(GraphicsDevice screen) throws AWTException {
0N/A checkRobotAllowed();
0N/A gdLoc = screen.getDefaultConfiguration().getBounds().getLocation();
0N/A Toolkit toolkit = Toolkit.getDefaultToolkit();
0N/A if (toolkit instanceof ComponentFactory) {
0N/A peer = ((ComponentFactory)toolkit).createRobot(this, screen);
0N/A disposer = new RobotDisposer(peer);
0N/A sun.java2d.Disposer.addRecord(anchor, disposer);
0N/A }
1398N/A initLegalButtonMask();
1398N/A }
1398N/A
1398N/A private static synchronized void initLegalButtonMask() {
1398N/A if (LEGAL_BUTTON_MASK != 0) return;
1398N/A
1398N/A int tmpMask = 0;
1398N/A if (Toolkit.getDefaultToolkit().areExtraMouseButtonsEnabled()){
1398N/A if (Toolkit.getDefaultToolkit() instanceof SunToolkit) {
1398N/A final int buttonsNumber = ((SunToolkit)(Toolkit.getDefaultToolkit())).getNumberOfButtons();
1398N/A for (int i = 0; i < buttonsNumber; i++){
1398N/A tmpMask |= InputEvent.getMaskForButton(i+1);
1398N/A }
1398N/A }
1398N/A }
1398N/A tmpMask |= InputEvent.BUTTON1_MASK|
1398N/A InputEvent.BUTTON2_MASK|
1398N/A InputEvent.BUTTON3_MASK|
1398N/A InputEvent.BUTTON1_DOWN_MASK|
1398N/A InputEvent.BUTTON2_DOWN_MASK|
1398N/A InputEvent.BUTTON3_DOWN_MASK;
1398N/A LEGAL_BUTTON_MASK = tmpMask;
0N/A }
0N/A
0N/A /* determine if the security policy allows Robot's to be created */
0N/A private void checkRobotAllowed() {
0N/A SecurityManager security = System.getSecurityManager();
0N/A if (security != null) {
1714N/A security.checkPermission(SecurityConstants.AWT.CREATE_ROBOT_PERMISSION);
0N/A }
0N/A }
0N/A
0N/A /* check if the given device is a screen device */
0N/A private void checkIsScreenDevice(GraphicsDevice device) {
0N/A if (device == null || device.getType() != GraphicsDevice.TYPE_RASTER_SCREEN) {
0N/A throw new IllegalArgumentException("not a valid screen device");
0N/A }
0N/A }
0N/A
0N/A private transient Object anchor = new Object();
0N/A
0N/A static class RobotDisposer implements sun.java2d.DisposerRecord {
0N/A private final RobotPeer peer;
0N/A public RobotDisposer(RobotPeer peer) {
0N/A this.peer = peer;
0N/A }
0N/A public void dispose() {
0N/A if (peer != null) {
0N/A peer.dispose();
0N/A }
0N/A }
0N/A }
0N/A
0N/A private transient RobotDisposer disposer;
0N/A
0N/A /**
0N/A * Moves mouse pointer to given screen coordinates.
0N/A * @param x X position
0N/A * @param y Y position
0N/A */
0N/A public synchronized void mouseMove(int x, int y) {
0N/A peer.mouseMove(gdLoc.x + x, gdLoc.y + y);
0N/A afterEvent();
0N/A }
0N/A
0N/A /**
0N/A * Presses one or more mouse buttons. The mouse buttons should
870N/A * be released using the {@link #mouseRelease(int)} method.
0N/A *
870N/A * @param buttons the Button mask; a combination of one or more
870N/A * mouse button masks.
870N/A * <p>
870N/A * It is allowed to use only a combination of valid values as a {@code buttons} parameter.
870N/A * A valid combination consists of {@code InputEvent.BUTTON1_DOWN_MASK},
870N/A * {@code InputEvent.BUTTON2_DOWN_MASK}, {@code InputEvent.BUTTON3_DOWN_MASK}
870N/A * and values returned by the
870N/A * {@link InputEvent#getMaskForButton(int) InputEvent.getMaskForButton(button)} method.
870N/A *
870N/A * The valid combination also depends on a
870N/A * {@link Toolkit#areExtraMouseButtonsEnabled() Toolkit.areExtraMouseButtonsEnabled()} value as follows:
0N/A * <ul>
870N/A * <li> If support for extended mouse buttons is
870N/A * {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java
870N/A * then it is allowed to use only the following standard button masks:
870N/A * {@code InputEvent.BUTTON1_DOWN_MASK}, {@code InputEvent.BUTTON2_DOWN_MASK},
870N/A * {@code InputEvent.BUTTON3_DOWN_MASK}.
870N/A * <li> If support for extended mouse buttons is
870N/A * {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java
870N/A * then it is allowed to use the standard button masks
870N/A * and masks for existing extended mouse buttons, if the mouse has more then three buttons.
870N/A * In that way, it is allowed to use the button masks corresponding to the buttons
870N/A * in the range from 1 to {@link java.awt.MouseInfo#getNumberOfButtons() MouseInfo.getNumberOfButtons()}.
870N/A * <br>
870N/A * It is recommended to use the {@link InputEvent#getMaskForButton(int) InputEvent.getMaskForButton(button)}
870N/A * method to obtain the mask for any mouse button by its number.
0N/A * </ul>
870N/A * <p>
870N/A * The following standard button masks are also accepted:
870N/A * <ul>
870N/A * <li>{@code InputEvent.BUTTON1_MASK}
870N/A * <li>{@code InputEvent.BUTTON2_MASK}
870N/A * <li>{@code InputEvent.BUTTON3_MASK}
870N/A * </ul>
870N/A * However, it is recommended to use {@code InputEvent.BUTTON1_DOWN_MASK},
870N/A * {@code InputEvent.BUTTON2_DOWN_MASK}, {@code InputEvent.BUTTON3_DOWN_MASK} instead.
870N/A * Either extended {@code _DOWN_MASK} or old {@code _MASK} values
870N/A * should be used, but both those models should not be mixed.
870N/A * @throws IllegalArgumentException if the {@code buttons} mask contains the mask for extra mouse button
870N/A * and support for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java
870N/A * @throws IllegalArgumentException if the {@code buttons} mask contains the mask for extra mouse button
870N/A * that does not exist on the mouse and support for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java
0N/A * @see #mouseRelease(int)
870N/A * @see InputEvent#getMaskForButton(int)
870N/A * @see Toolkit#areExtraMouseButtonsEnabled()
870N/A * @see java.awt.MouseInfo#getNumberOfButtons()
870N/A * @see java.awt.event.MouseEvent
0N/A */
0N/A public synchronized void mousePress(int buttons) {
0N/A checkButtonsArgument(buttons);
0N/A peer.mousePress(buttons);
0N/A afterEvent();
0N/A }
0N/A
0N/A /**
0N/A * Releases one or more mouse buttons.
0N/A *
870N/A * @param buttons the Button mask; a combination of one or more
870N/A * mouse button masks.
870N/A * <p>
870N/A * It is allowed to use only a combination of valid values as a {@code buttons} parameter.
870N/A * A valid combination consists of {@code InputEvent.BUTTON1_DOWN_MASK},
870N/A * {@code InputEvent.BUTTON2_DOWN_MASK}, {@code InputEvent.BUTTON3_DOWN_MASK}
870N/A * and values returned by the
870N/A * {@link InputEvent#getMaskForButton(int) InputEvent.getMaskForButton(button)} method.
870N/A *
870N/A * The valid combination also depends on a
870N/A * {@link Toolkit#areExtraMouseButtonsEnabled() Toolkit.areExtraMouseButtonsEnabled()} value as follows:
0N/A * <ul>
870N/A * <li> If the support for extended mouse buttons is
870N/A * {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java
870N/A * then it is allowed to use only the following standard button masks:
870N/A * {@code InputEvent.BUTTON1_DOWN_MASK}, {@code InputEvent.BUTTON2_DOWN_MASK},
870N/A * {@code InputEvent.BUTTON3_DOWN_MASK}.
870N/A * <li> If the support for extended mouse buttons is
870N/A * {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java
870N/A * then it is allowed to use the standard button masks
870N/A * and masks for existing extended mouse buttons, if the mouse has more then three buttons.
870N/A * In that way, it is allowed to use the button masks corresponding to the buttons
870N/A * in the range from 1 to {@link java.awt.MouseInfo#getNumberOfButtons() MouseInfo.getNumberOfButtons()}.
870N/A * <br>
870N/A * It is recommended to use the {@link InputEvent#getMaskForButton(int) InputEvent.getMaskForButton(button)}
870N/A * method to obtain the mask for any mouse button by its number.
0N/A * </ul>
870N/A * <p>
870N/A * The following standard button masks are also accepted:
870N/A * <ul>
870N/A * <li>{@code InputEvent.BUTTON1_MASK}
870N/A * <li>{@code InputEvent.BUTTON2_MASK}
870N/A * <li>{@code InputEvent.BUTTON3_MASK}
870N/A * </ul>
870N/A * However, it is recommended to use {@code InputEvent.BUTTON1_DOWN_MASK},
870N/A * {@code InputEvent.BUTTON2_DOWN_MASK}, {@code InputEvent.BUTTON3_DOWN_MASK} instead.
870N/A * Either extended {@code _DOWN_MASK} or old {@code _MASK} values
870N/A * should be used, but both those models should not be mixed.
870N/A * @throws IllegalArgumentException if the {@code buttons} mask contains the mask for extra mouse button
870N/A * and support for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java
870N/A * @throws IllegalArgumentException if the {@code buttons} mask contains the mask for extra mouse button
870N/A * that does not exist on the mouse and support for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java
0N/A * @see #mousePress(int)
870N/A * @see InputEvent#getMaskForButton(int)
870N/A * @see Toolkit#areExtraMouseButtonsEnabled()
870N/A * @see java.awt.MouseInfo#getNumberOfButtons()
870N/A * @see java.awt.event.MouseEvent
0N/A */
0N/A public synchronized void mouseRelease(int buttons) {
0N/A checkButtonsArgument(buttons);
0N/A peer.mouseRelease(buttons);
0N/A afterEvent();
0N/A }
0N/A
0N/A private void checkButtonsArgument(int buttons) {
0N/A if ( (buttons|LEGAL_BUTTON_MASK) != LEGAL_BUTTON_MASK ) {
0N/A throw new IllegalArgumentException("Invalid combination of button flags");
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Rotates the scroll wheel on wheel-equipped mice.
0N/A *
0N/A * @param wheelAmt number of "notches" to move the mouse wheel
0N/A * Negative values indicate movement up/away from the user,
0N/A * positive values indicate movement down/towards the user.
0N/A *
0N/A * @since 1.4
0N/A */
0N/A public synchronized void mouseWheel(int wheelAmt) {
0N/A peer.mouseWheel(wheelAmt);
0N/A afterEvent();
0N/A }
0N/A
0N/A /**
0N/A * Presses a given key. The key should be released using the
0N/A * <code>keyRelease</code> method.
0N/A * <p>
0N/A * Key codes that have more than one physical key associated with them
0N/A * (e.g. <code>KeyEvent.VK_SHIFT</code> could mean either the
0N/A * left or right shift key) will map to the left key.
0N/A *
0N/A * @param keycode Key to press (e.g. <code>KeyEvent.VK_A</code>)
0N/A * @throws IllegalArgumentException if <code>keycode</code> is not
0N/A * a valid key
0N/A * @see #keyRelease(int)
0N/A * @see java.awt.event.KeyEvent
0N/A */
0N/A public synchronized void keyPress(int keycode) {
0N/A checkKeycodeArgument(keycode);
0N/A peer.keyPress(keycode);
0N/A afterEvent();
0N/A }
0N/A
0N/A /**
0N/A * Releases a given key.
0N/A * <p>
0N/A * Key codes that have more than one physical key associated with them
0N/A * (e.g. <code>KeyEvent.VK_SHIFT</code> could mean either the
0N/A * left or right shift key) will map to the left key.
0N/A *
0N/A * @param keycode Key to release (e.g. <code>KeyEvent.VK_A</code>)
0N/A * @throws IllegalArgumentException if <code>keycode</code> is not a
0N/A * valid key
0N/A * @see #keyPress(int)
0N/A * @see java.awt.event.KeyEvent
0N/A */
0N/A public synchronized void keyRelease(int keycode) {
0N/A checkKeycodeArgument(keycode);
0N/A peer.keyRelease(keycode);
0N/A afterEvent();
0N/A }
0N/A
0N/A private void checkKeycodeArgument(int keycode) {
0N/A // rather than build a big table or switch statement here, we'll
0N/A // just check that the key isn't VK_UNDEFINED and assume that the
0N/A // peer implementations will throw an exception for other bogus
0N/A // values e.g. -1, 999999
0N/A if (keycode == KeyEvent.VK_UNDEFINED) {
0N/A throw new IllegalArgumentException("Invalid key code");
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returns the color of a pixel at the given screen coordinates.
0N/A * @param x X position of pixel
0N/A * @param y Y position of pixel
0N/A * @return Color of the pixel
0N/A */
0N/A public synchronized Color getPixelColor(int x, int y) {
0N/A Color color = new Color(peer.getRGBPixel(gdLoc.x + x, gdLoc.y + y));
0N/A return color;
0N/A }
0N/A
0N/A /**
0N/A * Creates an image containing pixels read from the screen. This image does
0N/A * not include the mouse cursor.
0N/A * @param screenRect Rect to capture in screen coordinates
0N/A * @return The captured image
0N/A * @throws IllegalArgumentException if <code>screenRect</code> width and height are not greater than zero
0N/A * @throws SecurityException if <code>readDisplayPixels</code> permission is not granted
0N/A * @see SecurityManager#checkPermission
0N/A * @see AWTPermission
0N/A */
0N/A public synchronized BufferedImage createScreenCapture(Rectangle screenRect) {
0N/A checkScreenCaptureAllowed();
0N/A
0N/A // according to the spec, screenRect is relative to robot's GD
0N/A Rectangle translatedRect = new Rectangle(screenRect);
0N/A translatedRect.translate(gdLoc.x, gdLoc.y);
0N/A checkValidRect(translatedRect);
0N/A
0N/A BufferedImage image;
0N/A DataBufferInt buffer;
0N/A WritableRaster raster;
0N/A
0N/A if (screenCapCM == null) {
0N/A /*
0N/A * Fix for 4285201
0N/A * Create a DirectColorModel equivalent to the default RGB ColorModel,
0N/A * except with no Alpha component.
0N/A */
0N/A
0N/A screenCapCM = new DirectColorModel(24,
0N/A /* red mask */ 0x00FF0000,
0N/A /* green mask */ 0x0000FF00,
0N/A /* blue mask */ 0x000000FF);
0N/A }
0N/A
430N/A // need to sync the toolkit prior to grabbing the pixels since in some
430N/A // cases rendering to the screen may be delayed
430N/A Toolkit.getDefaultToolkit().sync();
430N/A
0N/A int pixels[];
0N/A int[] bandmasks = new int[3];
0N/A
0N/A pixels = peer.getRGBPixels(translatedRect);
0N/A buffer = new DataBufferInt(pixels, pixels.length);
0N/A
0N/A bandmasks[0] = screenCapCM.getRedMask();
0N/A bandmasks[1] = screenCapCM.getGreenMask();
0N/A bandmasks[2] = screenCapCM.getBlueMask();
0N/A
0N/A raster = Raster.createPackedRaster(buffer, translatedRect.width, translatedRect.height, translatedRect.width, bandmasks, null);
430N/A SunWritableRaster.makeTrackable(buffer);
0N/A
0N/A image = new BufferedImage(screenCapCM, raster, false, null);
0N/A
0N/A return image;
0N/A }
0N/A
0N/A private static void checkValidRect(Rectangle rect) {
0N/A if (rect.width <= 0 || rect.height <= 0) {
0N/A throw new IllegalArgumentException("Rectangle width and height must be > 0");
0N/A }
0N/A }
0N/A
0N/A private static void checkScreenCaptureAllowed() {
0N/A SecurityManager security = System.getSecurityManager();
0N/A if (security != null) {
0N/A security.checkPermission(
1714N/A SecurityConstants.AWT.READ_DISPLAY_PIXELS_PERMISSION);
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Called after an event is generated
0N/A */
0N/A private void afterEvent() {
0N/A autoWaitForIdle();
0N/A autoDelay();
0N/A }
0N/A
0N/A /**
0N/A * Returns whether this Robot automatically invokes <code>waitForIdle</code>
0N/A * after generating an event.
0N/A * @return Whether <code>waitForIdle</code> is automatically called
0N/A */
0N/A public synchronized boolean isAutoWaitForIdle() {
0N/A return isAutoWaitForIdle;
0N/A }
0N/A
0N/A /**
0N/A * Sets whether this Robot automatically invokes <code>waitForIdle</code>
0N/A * after generating an event.
0N/A * @param isOn Whether <code>waitForIdle</code> is automatically invoked
0N/A */
0N/A public synchronized void setAutoWaitForIdle(boolean isOn) {
0N/A isAutoWaitForIdle = isOn;
0N/A }
0N/A
0N/A /*
0N/A * Calls waitForIdle after every event if so desired.
0N/A */
0N/A private void autoWaitForIdle() {
0N/A if (isAutoWaitForIdle) {
0N/A waitForIdle();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returns the number of milliseconds this Robot sleeps after generating an event.
0N/A */
0N/A public synchronized int getAutoDelay() {
0N/A return autoDelay;
0N/A }
0N/A
0N/A /**
0N/A * Sets the number of milliseconds this Robot sleeps after generating an event.
0N/A * @throws IllegalArgumentException If <code>ms</code> is not between 0 and 60,000 milliseconds inclusive
0N/A */
0N/A public synchronized void setAutoDelay(int ms) {
0N/A checkDelayArgument(ms);
0N/A autoDelay = ms;
0N/A }
0N/A
0N/A /*
0N/A * Automatically sleeps for the specified interval after event generated.
0N/A */
0N/A private void autoDelay() {
0N/A delay(autoDelay);
0N/A }
0N/A
0N/A /**
0N/A * Sleeps for the specified time.
0N/A * To catch any <code>InterruptedException</code>s that occur,
0N/A * <code>Thread.sleep()</code> may be used instead.
0N/A * @param ms time to sleep in milliseconds
0N/A * @throws IllegalArgumentException if <code>ms</code> is not between 0 and 60,000 milliseconds inclusive
0N/A * @see java.lang.Thread#sleep
0N/A */
0N/A public synchronized void delay(int ms) {
0N/A checkDelayArgument(ms);
0N/A try {
0N/A Thread.sleep(ms);
0N/A } catch(InterruptedException ite) {
0N/A ite.printStackTrace();
0N/A }
0N/A }
0N/A
0N/A private void checkDelayArgument(int ms) {
0N/A if (ms < 0 || ms > MAX_DELAY) {
0N/A throw new IllegalArgumentException("Delay must be to 0 to 60,000ms");
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Waits until all events currently on the event queue have been processed.
0N/A * @throws IllegalThreadStateException if called on the AWT event dispatching thread
0N/A */
0N/A public synchronized void waitForIdle() {
0N/A checkNotDispatchThread();
0N/A // post a dummy event to the queue so we know when
0N/A // all the events before it have been processed
0N/A try {
0N/A SunToolkit.flushPendingEvents();
0N/A EventQueue.invokeAndWait( new Runnable() {
0N/A public void run() {
0N/A // dummy implementation
0N/A }
0N/A } );
0N/A } catch(InterruptedException ite) {
0N/A System.err.println("Robot.waitForIdle, non-fatal exception caught:");
0N/A ite.printStackTrace();
0N/A } catch(InvocationTargetException ine) {
0N/A System.err.println("Robot.waitForIdle, non-fatal exception caught:");
0N/A ine.printStackTrace();
0N/A }
0N/A }
0N/A
0N/A private void checkNotDispatchThread() {
0N/A if (EventQueue.isDispatchThread()) {
0N/A throw new IllegalThreadStateException("Cannot call method from the event dispatcher thread");
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returns a string representation of this Robot.
0N/A *
0N/A * @return the string representation.
0N/A */
0N/A public synchronized String toString() {
0N/A String params = "autoDelay = "+getAutoDelay()+", "+"autoWaitForIdle = "+isAutoWaitForIdle();
0N/A return getClass().getName() + "[ " + params + " ]";
0N/A }
0N/A}