Source for java.awt.Robot

   1: /* Robot.java -- a native input event generator
   2:    Copyright (C) 2004, 2005  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package java.awt;
  40: 
  41: import gnu.java.awt.ClasspathToolkit;
  42: 
  43: import java.lang.reflect.InvocationTargetException;
  44: import java.awt.event.InputEvent;
  45: import java.awt.image.BufferedImage;
  46: import java.awt.peer.RobotPeer;
  47: 
  48: /**
  49:  * The Robot class is used to simulate user interaction with graphical
  50:  * programs.  It can generate native windowing system input events and
  51:  * retrieve image data from the current screen.  Robot is used to test
  52:  * the AWT and Swing library implementations; it can also be used to
  53:  * create self-running demo programs.
  54:  *
  55:  * Since Robot generates native windowing system events, rather than
  56:  * simply inserting {@link AWTEvent}s on the AWT event queue, its use
  57:  * is not restricted to Java programs.  It can be used to
  58:  * programatically drive any graphical application.
  59:  *
  60:  * This implementation requires an X server that supports the XTest
  61:  * extension.
  62:  *
  63:  * @author Thomas Fitzsimmons (fitzsim@redhat.com)
  64:  *
  65:  * @since 1.3
  66:  */
  67: public class Robot
  68: {
  69:   private boolean waitForIdle;
  70:   private int autoDelay;
  71:   private RobotPeer peer;
  72: 
  73:   /**
  74:    * Construct a Robot object that operates on the default screen.
  75:    *
  76:    * @exception AWTException if GraphicsEnvironment.isHeadless()
  77:    * returns true or if the X server does not support the XTest
  78:    * extension
  79:    * @exception SecurityException if createRobot permission is not
  80:    * granted
  81:    */
  82:   public Robot () throws AWTException
  83:   {
  84:     if (GraphicsEnvironment.isHeadless ())
  85:       throw new AWTException ("Robot: headless graphics environment");
  86: 
  87:     SecurityManager sm = System.getSecurityManager ();
  88:     if (sm != null)
  89:       sm.checkPermission (new AWTPermission ("createRobot"));
  90: 
  91:     ClasspathToolkit tk = (ClasspathToolkit) Toolkit.getDefaultToolkit ();
  92: 
  93:     // createRobot will throw AWTException if XTest is not supported.
  94:     peer = tk.createRobot (GraphicsEnvironment.getLocalGraphicsEnvironment ()
  95:                            .getDefaultScreenDevice ());
  96:   }
  97: 
  98:   /**
  99:    * Construct a Robot object that operates on the specified screen.
 100:    *
 101:    * @exception AWTException if GraphicsEnvironment.isHeadless()
 102:    * returns true or if the X server does not support the XTest
 103:    * extension
 104:    * @exception IllegalArgumentException if screen is not a screen
 105:    * GraphicsDevice
 106:    * @exception SecurityException if createRobot permission is not
 107:    * granted
 108:    */
 109:   public Robot (GraphicsDevice screen) throws AWTException
 110:   {
 111:     if (GraphicsEnvironment.isHeadless ())
 112:       throw new AWTException ("Robot: headless graphics environment");
 113: 
 114:     if (screen.getType () != GraphicsDevice.TYPE_RASTER_SCREEN)
 115:       throw new IllegalArgumentException ("Robot: graphics"
 116:                                           + " device is not a screen");
 117: 
 118:     SecurityManager sm = System.getSecurityManager ();
 119:     if (sm != null)
 120:       sm.checkPermission (new AWTPermission ("createRobot"));
 121: 
 122:     ClasspathToolkit tk = (ClasspathToolkit) Toolkit.getDefaultToolkit ();
 123: 
 124:     // createRobot will throw AWTException if XTest is not supported.
 125:     peer = tk.createRobot (screen);
 126:   }
 127: 
 128:   /**
 129:    * Move the mouse pointer to absolute coordinates (x, y).
 130:    *
 131:    * @param x the destination x coordinate
 132:    * @param y the destination y coordinate
 133:    */
 134:   public void mouseMove(int x, int y)
 135:   {
 136:     peer.mouseMove (x, y);
 137: 
 138:     if (waitForIdle)
 139:       waitForIdle ();
 140: 
 141:     if (autoDelay > 0)
 142:       delay (autoDelay);
 143:   }
 144: 
 145:   /**
 146:    * Press one or more mouse buttons.
 147:    *
 148:    * @param buttons the buttons to press; a bitmask of one or more of
 149:    * these {@link InputEvent} fields:
 150:    *
 151:    * <ul>
 152:    *   <li>BUTTON1_MASK</li>
 153:    *   <li>BUTTON2_MASK</li>
 154:    *   <li>BUTTON3_MASK</li>
 155:    * </ul>
 156:    *
 157:    * @exception IllegalArgumentException if the button mask is invalid
 158:    */
 159:   public void mousePress (int buttons)
 160:   {
 161:     if ((buttons & InputEvent.BUTTON1_MASK) == 0
 162:         && (buttons & InputEvent.BUTTON2_MASK) == 0
 163:         && (buttons & InputEvent.BUTTON3_MASK) == 0)
 164:       throw new IllegalArgumentException ("Robot: mousePress:"
 165:                                           + " invalid button mask");
 166: 
 167:     peer.mousePress (buttons);
 168: 
 169:     if (waitForIdle)
 170:       waitForIdle ();
 171: 
 172:     if (autoDelay > 0)
 173:       delay (autoDelay);
 174:   }
 175: 
 176:   /**
 177:    * Release one or more mouse buttons.
 178:    *
 179:    * @param buttons the buttons to release; a bitmask of one or more
 180:    * of these {@link InputEvent} fields:
 181:    *
 182:    * <ul>
 183:    *   <li>BUTTON1_MASK</li>
 184:    *   <li>BUTTON2_MASK</li>
 185:    *   <li>BUTTON3_MASK</li>
 186:    * </ul>
 187:    *
 188:    * @exception IllegalArgumentException if the button mask is invalid
 189:    */
 190:   public void mouseRelease(int buttons)
 191:   {
 192:     if ((buttons & InputEvent.BUTTON1_MASK) == 0
 193:         && (buttons & InputEvent.BUTTON2_MASK) == 0
 194:         && (buttons & InputEvent.BUTTON3_MASK) == 0)
 195:       throw new IllegalArgumentException ("Robot: mouseRelease:"
 196:                                           + " invalid button mask");
 197: 
 198:     peer.mouseRelease (buttons);
 199: 
 200:     if (waitForIdle)
 201:       waitForIdle ();
 202: 
 203:     if (autoDelay > 0)
 204:       delay (autoDelay);
 205:   }
 206: 
 207:   /**
 208:    * Rotate the mouse scroll wheel.
 209:    *
 210:    * @param wheelAmt number of steps to rotate mouse wheel.  negative
 211:    * to rotate wheel up (away from the user), positive to rotate wheel
 212:    * down (toward the user).
 213:    *
 214:    * @since 1.4
 215:    */
 216:   public void mouseWheel (int wheelAmt)
 217:   {
 218:     peer.mouseWheel (wheelAmt);
 219: 
 220:     if (waitForIdle)
 221:       waitForIdle ();
 222: 
 223:     if (autoDelay > 0)
 224:       delay (autoDelay);
 225:   }
 226: 
 227:   /**
 228:    * Press a key.
 229:    *
 230:    * @param keycode key to press, a {@link java.awt.event.KeyEvent} VK_ constant
 231:    *
 232:    * @exception IllegalArgumentException if keycode is not a valid key
 233:    */
 234:   public void keyPress (int keycode)
 235:   {
 236:     peer.keyPress (keycode);
 237: 
 238:     if (waitForIdle)
 239:       waitForIdle ();
 240: 
 241:     if (autoDelay > 0)
 242:       delay (autoDelay);
 243:   }
 244: 
 245:   /**
 246:    * Release a key.
 247:    *
 248:    * @param keycode key to release, a {@link java.awt.event.KeyEvent} VK_
 249:    *                constant
 250:    *
 251:    * @exception IllegalArgumentException if keycode is not a valid key
 252:    */
 253:   public void keyRelease (int keycode)
 254:   {
 255:     peer.keyRelease (keycode);
 256: 
 257:     if (waitForIdle)
 258:       waitForIdle ();
 259: 
 260:     if (autoDelay > 0)
 261:       delay (autoDelay);
 262:   }
 263: 
 264:   /**
 265:    * Return the color of the pixel at the given screen coordinates.
 266:    *
 267:    * @param x the x coordinate of the pixel
 268:    * @param y the y coordinate of the pixel
 269:    *
 270:    * @return the Color of the pixel at screen coodinates <code>(x, y)</code>
 271:    */
 272:   public Color getPixelColor (int x, int y)
 273:   {
 274:     return new Color (peer.getRGBPixel (x, y));
 275:   }
 276: 
 277:   /**
 278:    * Create an image containing pixels read from the screen.  The
 279:    * image does not include the mouse pointer.
 280:    *
 281:    * @param screenRect the rectangle of pixels to capture, in screen
 282:    * coordinates
 283:    *
 284:    * @return a BufferedImage containing the requested pixels
 285:    *
 286:    * @exception IllegalArgumentException if requested width and height
 287:    * are not both greater than zero
 288:    * @exception SecurityException if readDisplayPixels permission is
 289:    * not granted
 290:    */
 291:   public BufferedImage createScreenCapture (Rectangle screenRect)
 292:   {
 293:     if (screenRect.width <= 0)
 294:       throw new IllegalArgumentException ("Robot: capture width is <= 0");
 295: 
 296:     if (screenRect.height <= 0)
 297:       throw new IllegalArgumentException ("Robot: capture height is <= 0");
 298: 
 299:     SecurityManager sm = System.getSecurityManager ();
 300:     if (sm != null)
 301:       sm.checkPermission (new AWTPermission ("readDisplayPixels"));
 302: 
 303:     int[] pixels = peer.getRGBPixels (screenRect);
 304: 
 305:     BufferedImage bufferedImage =
 306:       new BufferedImage (screenRect.width, screenRect.height,
 307:                          BufferedImage.TYPE_INT_ARGB);
 308: 
 309:     bufferedImage.setRGB (0, 0, screenRect.width, screenRect.height,
 310:                           pixels, 0, screenRect.width);
 311: 
 312:     return bufferedImage;
 313:   }
 314: 
 315:   /**
 316:    * Check if this Robot automatically calls {@link #waitForIdle()} after
 317:    * generating an event.
 318:    *
 319:    * @return true if waitForIdle is automatically called
 320:    */
 321:   public boolean isAutoWaitForIdle ()
 322:   {
 323:     return waitForIdle;
 324:   }
 325: 
 326:   /**
 327:    * Set whether or not this Robot automatically calls {@link
 328:    * #waitForIdle()} after generating an event.
 329:    *
 330:    * @param isOn true if waitForIdle should be called automatically
 331:    */
 332:   public void setAutoWaitForIdle (boolean isOn)
 333:   {
 334:     waitForIdle = isOn;
 335:   }
 336: 
 337:   /**
 338:    * Retrieve the length of time this Robot sleeps after generating an
 339:    * event.
 340:    *
 341:    * @return the length of time in milliseconds
 342:    */
 343:   public int getAutoDelay ()
 344:   {
 345:     return autoDelay;
 346:   }
 347: 
 348:   /**
 349:    * Set the length of time this Robot sleeps after generating an
 350:    * event.
 351:    *
 352:    * @param ms the length of time in milliseconds
 353:    *
 354:    * @exception IllegalArgumentException if ms is not between 0 and
 355:    * 60,000 milliseconds inclusive
 356:    */
 357:   public void setAutoDelay (int ms)
 358:   {
 359:     if (ms <= 0 || ms >= 60000)
 360:       throw new IllegalArgumentException ("Robot: delay length out-of-bounds");
 361: 
 362:     autoDelay = ms;
 363:   }
 364: 
 365:   /**
 366:    * Sleep for a specified length of time.
 367:    *
 368:    * @param ms the length of time in milliseconds
 369:    *
 370:    * @exception IllegalArgumentException if ms is not between 0 and
 371:    * 60,000 milliseconds inclusive
 372:    */
 373:   public void delay (int ms)
 374:   {
 375:     if (ms < 0 || ms > 60000)
 376:       throw new IllegalArgumentException ("Robot: delay length out-of-bounds");
 377: 
 378:     try
 379:       {
 380:         Thread.sleep (ms);
 381:       }
 382:     catch (InterruptedException e)
 383:       {
 384:         System.err.println ("Robot: delay interrupted");
 385:       }
 386:   }
 387: 
 388:   /**
 389:    * Wait until all events currently on the event queue have been
 390:    * dispatched.
 391:    */
 392:   public void waitForIdle ()
 393:   {
 394:     if (EventQueue.isDispatchThread ())
 395:       throw new IllegalThreadStateException ("Robot: waitForIdle called from "
 396:                                              + "the event dispatch thread");
 397: 
 398:     try
 399:       {
 400:         EventQueue.invokeAndWait (new Runnable () { public void run () { } });
 401:       }
 402:     catch (InterruptedException e)
 403:       {
 404:         System.err.println ("Robot: waitForIdle interrupted");
 405:       }
 406:     catch (InvocationTargetException e)
 407:       {
 408:         System.err.println ("Robot: waitForIdle cannot invoke target");
 409:       }
 410:   }
 411: 
 412:   /**
 413:    * Return a string representation of this Robot.
 414:    *
 415:    * @return a string representation
 416:    */
 417:   public String toString ()
 418:   {
 419:     return getClass ().getName ()
 420:         + "[ autoDelay = " + autoDelay + ", autoWaitForIdle = "
 421:         + waitForIdle + " ]";
 422:   }
 423: }