| /* Robot.java -- a native input event generator | |
| Copyright (C) 2004, 2005 Free Software Foundation, Inc. | |
| This file is part of GNU Classpath. | |
| GNU Classpath is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 2, or (at your option) | |
| any later version. | |
| GNU Classpath is distributed in the hope that it will be useful, but | |
| WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with GNU Classpath; see the file COPYING. If not, write to the | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
| 02110-1301 USA. | |
| Linking this library statically or dynamically with other modules is | |
| making a combined work based on this library. Thus, the terms and | |
| conditions of the GNU General Public License cover the whole | |
| combination. | |
| As a special exception, the copyright holders of this library give you | |
| permission to link this library with independent modules to produce an | |
| executable, regardless of the license terms of these independent | |
| modules, and to copy and distribute the resulting executable under | |
| terms of your choice, provided that you also meet, for each linked | |
| independent module, the terms and conditions of the license of that | |
| module. An independent module is a module which is not derived from | |
| or based on this library. If you modify this library, you may extend | |
| this exception to your version of the library, but you are not | |
| obligated to do so. If you do not wish to do so, delete this | |
| exception statement from your version. */ | |
| package java.awt; | |
| import gnu.java.awt.ClasspathToolkit; | |
| import java.lang.reflect.InvocationTargetException; | |
| import java.awt.event.InputEvent; | |
| import java.awt.image.BufferedImage; | |
| import java.awt.peer.RobotPeer; | |
| /** | |
| * The Robot class is used to simulate user interaction with graphical | |
| * programs. It can generate native windowing system input events and | |
| * retrieve image data from the current screen. Robot is used to test | |
| * the AWT and Swing library implementations; it can also be used to | |
| * create self-running demo programs. | |
| * | |
| * Since Robot generates native windowing system events, rather than | |
| * simply inserting {@link AWTEvent}s on the AWT event queue, its use | |
| * is not restricted to Java programs. It can be used to | |
| * programatically drive any graphical application. | |
| * | |
| * This implementation requires an X server that supports the XTest | |
| * extension. | |
| * | |
| * @author Thomas Fitzsimmons (fitzsim@redhat.com) | |
| * | |
| * @since 1.3 | |
| */ | |
| public class Robot | |
| { | |
| private boolean waitForIdle; | |
| private int autoDelay; | |
| private RobotPeer peer; | |
| /** | |
| * Construct a Robot object that operates on the default screen. | |
| * | |
| * @exception AWTException if GraphicsEnvironment.isHeadless() | |
| * returns true or if the X server does not support the XTest | |
| * extension | |
| * @exception SecurityException if createRobot permission is not | |
| * granted | |
| */ | |
| public Robot () throws AWTException | |
| { | |
| if (GraphicsEnvironment.isHeadless ()) | |
| throw new AWTException ("Robot: headless graphics environment"); | |
| SecurityManager sm = System.getSecurityManager (); | |
| if (sm != null) | |
| sm.checkPermission (new AWTPermission ("createRobot")); | |
| ClasspathToolkit tk = (ClasspathToolkit) Toolkit.getDefaultToolkit (); | |
| // createRobot will throw AWTException if XTest is not supported. | |
| peer = tk.createRobot (GraphicsEnvironment.getLocalGraphicsEnvironment () | |
| .getDefaultScreenDevice ()); | |
| } | |
| /** | |
| * Construct a Robot object that operates on the specified screen. | |
| * | |
| * @exception AWTException if GraphicsEnvironment.isHeadless() | |
| * returns true or if the X server does not support the XTest | |
| * extension | |
| * @exception IllegalArgumentException if screen is not a screen | |
| * GraphicsDevice | |
| * @exception SecurityException if createRobot permission is not | |
| * granted | |
| */ | |
| public Robot (GraphicsDevice screen) throws AWTException | |
| { | |
| if (GraphicsEnvironment.isHeadless ()) | |
| throw new AWTException ("Robot: headless graphics environment"); | |
| if (screen.getType () != GraphicsDevice.TYPE_RASTER_SCREEN) | |
| throw new IllegalArgumentException ("Robot: graphics" | |
| + " device is not a screen"); | |
| SecurityManager sm = System.getSecurityManager (); | |
| if (sm != null) | |
| sm.checkPermission (new AWTPermission ("createRobot")); | |
| ClasspathToolkit tk = (ClasspathToolkit) Toolkit.getDefaultToolkit (); | |
| // createRobot will throw AWTException if XTest is not supported. | |
| peer = tk.createRobot (screen); | |
| } | |
| /** | |
| * Move the mouse pointer to absolute coordinates (x, y). | |
| * | |
| * @param x the destination x coordinate | |
| * @param y the destination y coordinate | |
| */ | |
| public void mouseMove(int x, int y) | |
| { | |
| peer.mouseMove (x, y); | |
| if (waitForIdle) | |
| waitForIdle (); | |
| if (autoDelay > 0) | |
| delay (autoDelay); | |
| } | |
| /** | |
| * Press one or more mouse buttons. | |
| * | |
| * @param buttons the buttons to press; a bitmask of one or more of | |
| * these {@link InputEvent} fields: | |
| * | |
| * <ul> | |
| * <li>BUTTON1_MASK</li> | |
| * <li>BUTTON2_MASK</li> | |
| * <li>BUTTON3_MASK</li> | |
| * </ul> | |
| * | |
| * @exception IllegalArgumentException if the button mask is invalid | |
| */ | |
| public void mousePress (int buttons) | |
| { | |
| if ((buttons & InputEvent.BUTTON1_MASK) == 0 | |
| && (buttons & InputEvent.BUTTON2_MASK) == 0 | |
| && (buttons & InputEvent.BUTTON3_MASK) == 0) | |
| throw new IllegalArgumentException ("Robot: mousePress:" | |
| + " invalid button mask"); | |
| peer.mousePress (buttons); | |
| if (waitForIdle) | |
| waitForIdle (); | |
| if (autoDelay > 0) | |
| delay (autoDelay); | |
| } | |
| /** | |
| * Release one or more mouse buttons. | |
| * | |
| * @param buttons the buttons to release; a bitmask of one or more | |
| * of these {@link InputEvent} fields: | |
| * | |
| * <ul> | |
| * <li>BUTTON1_MASK</li> | |
| * <li>BUTTON2_MASK</li> | |
| * <li>BUTTON3_MASK</li> | |
| * </ul> | |
| * | |
| * @exception IllegalArgumentException if the button mask is invalid | |
| */ | |
| public void mouseRelease(int buttons) | |
| { | |
| if ((buttons & InputEvent.BUTTON1_MASK) == 0 | |
| && (buttons & InputEvent.BUTTON2_MASK) == 0 | |
| && (buttons & InputEvent.BUTTON3_MASK) == 0) | |
| throw new IllegalArgumentException ("Robot: mouseRelease:" | |
| + " invalid button mask"); | |
| peer.mouseRelease (buttons); | |
| if (waitForIdle) | |
| waitForIdle (); | |
| if (autoDelay > 0) | |
| delay (autoDelay); | |
| } | |
| /** | |
| * Rotate the mouse scroll wheel. | |
| * | |
| * @param wheelAmt number of steps to rotate mouse wheel. negative | |
| * to rotate wheel up (away from the user), positive to rotate wheel | |
| * down (toward the user). | |
| * | |
| * @since 1.4 | |
| */ | |
| public void mouseWheel (int wheelAmt) | |
| { | |
| peer.mouseWheel (wheelAmt); | |
| if (waitForIdle) | |
| waitForIdle (); | |
| if (autoDelay > 0) | |
| delay (autoDelay); | |
| } | |
| /** | |
| * Press a key. | |
| * | |
| * @param keycode key to press, a {@link java.awt.event.KeyEvent} VK_ constant | |
| * | |
| * @exception IllegalArgumentException if keycode is not a valid key | |
| */ | |
| public void keyPress (int keycode) | |
| { | |
| peer.keyPress (keycode); | |
| if (waitForIdle) | |
| waitForIdle (); | |
| if (autoDelay > 0) | |
| delay (autoDelay); | |
| } | |
| /** | |
| * Release a key. | |
| * | |
| * @param keycode key to release, a {@link java.awt.event.KeyEvent} VK_ | |
| * constant | |
| * | |
| * @exception IllegalArgumentException if keycode is not a valid key | |
| */ | |
| public void keyRelease (int keycode) | |
| { | |
| peer.keyRelease (keycode); | |
| if (waitForIdle) | |
| waitForIdle (); | |
| if (autoDelay > 0) | |
| delay (autoDelay); | |
| } | |
| /** | |
| * Return the color of the pixel at the given screen coordinates. | |
| * | |
| * @param x the x coordinate of the pixel | |
| * @param y the y coordinate of the pixel | |
| * | |
| * @return the Color of the pixel at screen coodinates <code>(x, y)</code> | |
| */ | |
| public Color getPixelColor (int x, int y) | |
| { | |
| return new Color (peer.getRGBPixel (x, y)); | |
| } | |
| /** | |
| * Create an image containing pixels read from the screen. The | |
| * image does not include the mouse pointer. | |
| * | |
| * @param screenRect the rectangle of pixels to capture, in screen | |
| * coordinates | |
| * | |
| * @return a BufferedImage containing the requested pixels | |
| * | |
| * @exception IllegalArgumentException if requested width and height | |
| * are not both greater than zero | |
| * @exception SecurityException if readDisplayPixels permission is | |
| * not granted | |
| */ | |
| public BufferedImage createScreenCapture (Rectangle screenRect) | |
| { | |
| if (screenRect.width <= 0) | |
| throw new IllegalArgumentException ("Robot: capture width is <= 0"); | |
| if (screenRect.height <= 0) | |
| throw new IllegalArgumentException ("Robot: capture height is <= 0"); | |
| SecurityManager sm = System.getSecurityManager (); | |
| if (sm != null) | |
| sm.checkPermission (new AWTPermission ("readDisplayPixels")); | |
| int[] pixels = peer.getRGBPixels (screenRect); | |
| BufferedImage bufferedImage = | |
| new BufferedImage (screenRect.width, screenRect.height, | |
| BufferedImage.TYPE_INT_ARGB); | |
| bufferedImage.setRGB (0, 0, screenRect.width, screenRect.height, | |
| pixels, 0, screenRect.width); | |
| return bufferedImage; | |
| } | |
| /** | |
| * Check if this Robot automatically calls {@link #waitForIdle()} after | |
| * generating an event. | |
| * | |
| * @return true if waitForIdle is automatically called | |
| */ | |
| public boolean isAutoWaitForIdle () | |
| { | |
| return waitForIdle; | |
| } | |
| /** | |
| * Set whether or not this Robot automatically calls {@link | |
| * #waitForIdle()} after generating an event. | |
| * | |
| * @param isOn true if waitForIdle should be called automatically | |
| */ | |
| public void setAutoWaitForIdle (boolean isOn) | |
| { | |
| waitForIdle = isOn; | |
| } | |
| /** | |
| * Retrieve the length of time this Robot sleeps after generating an | |
| * event. | |
| * | |
| * @return the length of time in milliseconds | |
| */ | |
| public int getAutoDelay () | |
| { | |
| return autoDelay; | |
| } | |
| /** | |
| * Set the length of time this Robot sleeps after generating an | |
| * event. | |
| * | |
| * @param ms the length of time in milliseconds | |
| * | |
| * @exception IllegalArgumentException if ms is not between 0 and | |
| * 60,000 milliseconds inclusive | |
| */ | |
| public void setAutoDelay (int ms) | |
| { | |
| if (ms <= 0 || ms >= 60000) | |
| throw new IllegalArgumentException ("Robot: delay length out-of-bounds"); | |
| autoDelay = ms; | |
| } | |
| /** | |
| * Sleep for a specified length of time. | |
| * | |
| * @param ms the length of time in milliseconds | |
| * | |
| * @exception IllegalArgumentException if ms is not between 0 and | |
| * 60,000 milliseconds inclusive | |
| */ | |
| public void delay (int ms) | |
| { | |
| if (ms < 0 || ms > 60000) | |
| throw new IllegalArgumentException ("Robot: delay length out-of-bounds"); | |
| try | |
| { | |
| Thread.sleep (ms); | |
| } | |
| catch (InterruptedException e) | |
| { | |
| System.err.println ("Robot: delay interrupted"); | |
| } | |
| } | |
| /** | |
| * Wait until all events currently on the event queue have been | |
| * dispatched. | |
| */ | |
| public void waitForIdle () | |
| { | |
| if (EventQueue.isDispatchThread ()) | |
| throw new IllegalThreadStateException ("Robot: waitForIdle called from " | |
| + "the event dispatch thread"); | |
| try | |
| { | |
| EventQueue.invokeAndWait (new Runnable () { public void run () { } }); | |
| } | |
| catch (InterruptedException e) | |
| { | |
| System.err.println ("Robot: waitForIdle interrupted"); | |
| } | |
| catch (InvocationTargetException e) | |
| { | |
| System.err.println ("Robot: waitForIdle cannot invoke target"); | |
| } | |
| } | |
| /** | |
| * Return a string representation of this Robot. | |
| * | |
| * @return a string representation | |
| */ | |
| public String toString () | |
| { | |
| return getClass ().getName () | |
| + "[ autoDelay = " + autoDelay + ", autoWaitForIdle = " | |
| + waitForIdle + " ]"; | |
| } | |
| } |