| /* 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 + " ]"; |
| } |
| } |