d5d74adf8a
2005-02-22 Thomas Fitzsimmons <fitzsim@redhat.com> * java/awt/Robot.java (waitForIdle): Call invokeAndWait on an empty Runnable. From-SVN: r95384
424 lines
12 KiB
Java
424 lines
12 KiB
Java
/* 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., 59 Temple Place, Suite 330, Boston, MA
|
|
02111-1307 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 AWTEvents} 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 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 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");
|
|
|
|
EventQueue q = Toolkit.getDefaultToolkit ().getSystemEventQueue ();
|
|
try
|
|
{
|
|
q.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 + " ]";
|
|
}
|
|
}
|