< prev index next >

src/java.desktop/share/classes/java/awt/Robot.java

Print this page




  32 import java.awt.image.DirectColorModel;
  33 import java.awt.image.Raster;
  34 import java.awt.image.WritableRaster;
  35 import java.awt.peer.RobotPeer;
  36 
  37 import sun.awt.AWTPermissions;
  38 import sun.awt.ComponentFactory;
  39 import sun.awt.SunToolkit;
  40 import sun.awt.image.SunWritableRaster;
  41 
  42 /**
  43  * This class is used to generate native system input events
  44  * for the purposes of test automation, self-running demos, and
  45  * other applications where control of the mouse and keyboard
  46  * is needed. The primary purpose of Robot is to facilitate
  47  * automated testing of Java platform implementations.
  48  * <p>
  49  * Using the class to generate input events differs from posting
  50  * events to the AWT event queue or AWT components in that the
  51  * events are generated in the platform's native input
  52  * queue. For example, <code>Robot.mouseMove</code> will actually move
  53  * the mouse cursor instead of just generating mouse move events.
  54  * <p>
  55  * Note that some platforms require special privileges or extensions
  56  * to access low-level input control. If the current platform configuration
  57  * does not allow input control, an <code>AWTException</code> will be thrown
  58  * when trying to construct Robot objects. For example, X-Window systems
  59  * will throw the exception if the XTEST 2.2 standard extension is not supported
  60  * (or not enabled) by the X server.
  61  * <p>
  62  * Applications that use Robot for purposes other than self-testing should
  63  * handle these error conditions gracefully.
  64  *
  65  * @author      Robi Khan
  66  * @since       1.3
  67  */
  68 public class Robot {
  69     private static final int MAX_DELAY = 60000;
  70     private RobotPeer peer;
  71     private boolean isAutoWaitForIdle = false;
  72     private int autoDelay = 0;
  73     private static int LEGAL_BUTTON_MASK = 0;
  74 
  75     private DirectColorModel screenCapCM = null;
  76 
  77     /**
  78      * Constructs a Robot object in the coordinate system of the primary screen.
  79      *
  80      * @throws  AWTException if the platform configuration does not allow
  81      * low-level input control.  This exception is always thrown when
  82      * GraphicsEnvironment.isHeadless() returns true
  83      * @throws  SecurityException if <code>createRobot</code> permission is not granted
  84      * @see     java.awt.GraphicsEnvironment#isHeadless
  85      * @see     SecurityManager#checkPermission
  86      * @see     AWTPermission
  87      */
  88     public Robot() throws AWTException {
  89         if (GraphicsEnvironment.isHeadless()) {
  90             throw new AWTException("headless environment");
  91         }
  92         init(GraphicsEnvironment.getLocalGraphicsEnvironment()
  93             .getDefaultScreenDevice());
  94     }
  95 
  96     /**
  97      * Creates a Robot for the given screen device. Coordinates passed
  98      * to Robot method calls like mouseMove and createScreenCapture will
  99      * be interpreted as being in the same coordinate system as the
 100      * specified screen. Note that depending on the platform configuration,
 101      * multiple screens may either:
 102      * <ul>
 103      * <li>share the same coordinate system to form a combined virtual screen</li>
 104      * <li>use different coordinate systems to act as independent screens</li>
 105      * </ul>
 106      * This constructor is meant for the latter case.
 107      * <p>
 108      * If screen devices are reconfigured such that the coordinate system is
 109      * affected, the behavior of existing Robot objects is undefined.
 110      *
 111      * @param screen    A screen GraphicsDevice indicating the coordinate
 112      *                  system the Robot will operate in.
 113      * @throws  AWTException if the platform configuration does not allow
 114      * low-level input control.  This exception is always thrown when
 115      * GraphicsEnvironment.isHeadless() returns true.
 116      * @throws  IllegalArgumentException if <code>screen</code> is not a screen
 117      *          GraphicsDevice.
 118      * @throws  SecurityException if <code>createRobot</code> permission is not granted
 119      * @see     java.awt.GraphicsEnvironment#isHeadless
 120      * @see     GraphicsDevice
 121      * @see     SecurityManager#checkPermission
 122      * @see     AWTPermission
 123      */
 124     public Robot(GraphicsDevice screen) throws AWTException {
 125         checkIsScreenDevice(screen);
 126         init(screen);
 127     }
 128 
 129     private void init(GraphicsDevice screen) throws AWTException {
 130         checkRobotAllowed();
 131         Toolkit toolkit = Toolkit.getDefaultToolkit();
 132         if (toolkit instanceof ComponentFactory) {
 133             peer = ((ComponentFactory)toolkit).createRobot(this, screen);
 134             disposer = new RobotDisposer(peer);
 135             sun.java2d.Disposer.addRecord(anchor, disposer);
 136         }
 137         initLegalButtonMask();
 138     }


 319             throw new IllegalArgumentException("Invalid combination of button flags");
 320         }
 321     }
 322 
 323     /**
 324      * Rotates the scroll wheel on wheel-equipped mice.
 325      *
 326      * @param wheelAmt  number of "notches" to move the mouse wheel
 327      *                  Negative values indicate movement up/away from the user,
 328      *                  positive values indicate movement down/towards the user.
 329      *
 330      * @since 1.4
 331      */
 332     public synchronized void mouseWheel(int wheelAmt) {
 333         peer.mouseWheel(wheelAmt);
 334         afterEvent();
 335     }
 336 
 337     /**
 338      * Presses a given key.  The key should be released using the
 339      * <code>keyRelease</code> method.
 340      * <p>
 341      * Key codes that have more than one physical key associated with them
 342      * (e.g. <code>KeyEvent.VK_SHIFT</code> could mean either the
 343      * left or right shift key) will map to the left key.
 344      *
 345      * @param   keycode Key to press (e.g. <code>KeyEvent.VK_A</code>)
 346      * @throws  IllegalArgumentException if <code>keycode</code> is not
 347      *          a valid key
 348      * @see     #keyRelease(int)
 349      * @see     java.awt.event.KeyEvent
 350      */
 351     public synchronized void keyPress(int keycode) {
 352         checkKeycodeArgument(keycode);
 353         peer.keyPress(keycode);
 354         afterEvent();
 355     }
 356 
 357     /**
 358      * Releases a given key.
 359      * <p>
 360      * Key codes that have more than one physical key associated with them
 361      * (e.g. <code>KeyEvent.VK_SHIFT</code> could mean either the
 362      * left or right shift key) will map to the left key.
 363      *
 364      * @param   keycode Key to release (e.g. <code>KeyEvent.VK_A</code>)
 365      * @throws  IllegalArgumentException if <code>keycode</code> is not a
 366      *          valid key
 367      * @see  #keyPress(int)
 368      * @see     java.awt.event.KeyEvent
 369      */
 370     public synchronized void keyRelease(int keycode) {
 371         checkKeycodeArgument(keycode);
 372         peer.keyRelease(keycode);
 373         afterEvent();
 374     }
 375 
 376     private void checkKeycodeArgument(int keycode) {
 377         // rather than build a big table or switch statement here, we'll
 378         // just check that the key isn't VK_UNDEFINED and assume that the
 379         // peer implementations will throw an exception for other bogus
 380         // values e.g. -1, 999999
 381         if (keycode == KeyEvent.VK_UNDEFINED) {
 382             throw new IllegalArgumentException("Invalid key code");
 383         }
 384     }
 385 
 386     /**
 387      * Returns the color of a pixel at the given screen coordinates.
 388      * @param   x       X position of pixel
 389      * @param   y       Y position of pixel
 390      * @return  Color of the pixel
 391      */
 392     public synchronized Color getPixelColor(int x, int y) {
 393         Color color = new Color(peer.getRGBPixel(x, y));
 394         return color;
 395     }
 396 
 397     /**
 398      * Creates an image containing pixels read from the screen.  This image does
 399      * not include the mouse cursor.
 400      * @param   screenRect      Rect to capture in screen coordinates
 401      * @return  The captured image
 402      * @throws  IllegalArgumentException if <code>screenRect</code> width and height are not greater than zero
 403      * @throws  SecurityException if <code>readDisplayPixels</code> permission is not granted
 404      * @see     SecurityManager#checkPermission
 405      * @see     AWTPermission
 406      */
 407     public synchronized BufferedImage createScreenCapture(Rectangle screenRect) {
 408         checkScreenCaptureAllowed();
 409 
 410         checkValidRect(screenRect);
 411 
 412         BufferedImage image;
 413         DataBufferInt buffer;
 414         WritableRaster raster;
 415 
 416         if (screenCapCM == null) {
 417             /*
 418              * Fix for 4285201
 419              * Create a DirectColorModel equivalent to the default RGB ColorModel,
 420              * except with no Alpha component.
 421              */
 422 
 423             screenCapCM = new DirectColorModel(24,


 453             throw new IllegalArgumentException("Rectangle width and height must be > 0");
 454         }
 455     }
 456 
 457     private static void checkScreenCaptureAllowed() {
 458         SecurityManager security = System.getSecurityManager();
 459         if (security != null) {
 460             security.checkPermission(AWTPermissions.READ_DISPLAY_PIXELS_PERMISSION);
 461         }
 462     }
 463 
 464     /*
 465      * Called after an event is generated
 466      */
 467     private void afterEvent() {
 468         autoWaitForIdle();
 469         autoDelay();
 470     }
 471 
 472     /**
 473      * Returns whether this Robot automatically invokes <code>waitForIdle</code>
 474      * after generating an event.
 475      * @return Whether <code>waitForIdle</code> is automatically called
 476      */
 477     public synchronized boolean isAutoWaitForIdle() {
 478         return isAutoWaitForIdle;
 479     }
 480 
 481     /**
 482      * Sets whether this Robot automatically invokes <code>waitForIdle</code>
 483      * after generating an event.
 484      * @param   isOn    Whether <code>waitForIdle</code> is automatically invoked
 485      */
 486     public synchronized void setAutoWaitForIdle(boolean isOn) {
 487         isAutoWaitForIdle = isOn;
 488     }
 489 
 490     /*
 491      * Calls waitForIdle after every event if so desired.
 492      */
 493     private void autoWaitForIdle() {
 494         if (isAutoWaitForIdle) {
 495             waitForIdle();
 496         }
 497     }
 498 
 499     /**
 500      * Returns the number of milliseconds this Robot sleeps after generating an event.
 501      *
 502      * @return the delay duration in milliseconds
 503      */
 504     public synchronized int getAutoDelay() {


 509      * Sets the number of milliseconds this Robot sleeps after generating an event.
 510      *
 511      * @param  ms the delay duration in milliseconds
 512      * @throws IllegalArgumentException If {@code ms}
 513      *         is not between 0 and 60,000 milliseconds inclusive
 514      */
 515     public synchronized void setAutoDelay(int ms) {
 516         checkDelayArgument(ms);
 517         autoDelay = ms;
 518     }
 519 
 520     /*
 521      * Automatically sleeps for the specified interval after event generated.
 522      */
 523     private void autoDelay() {
 524         delay(autoDelay);
 525     }
 526 
 527     /**
 528      * Sleeps for the specified time.
 529      * To catch any <code>InterruptedException</code>s that occur,
 530      * <code>Thread.sleep()</code> may be used instead.
 531      *
 532      * @param  ms time to sleep in milliseconds
 533      * @throws IllegalArgumentException if {@code ms}
 534      *         is not between 0 and 60,000 milliseconds inclusive
 535      * @see java.lang.Thread#sleep
 536      */
 537     public synchronized void delay(int ms) {
 538         checkDelayArgument(ms);
 539         try {
 540             Thread.sleep(ms);
 541         } catch(InterruptedException ite) {
 542             ite.printStackTrace();
 543         }
 544     }
 545 
 546     private void checkDelayArgument(int ms) {
 547         if (ms < 0 || ms > MAX_DELAY) {
 548             throw new IllegalArgumentException("Delay must be to 0 to 60,000ms");
 549         }
 550     }




  32 import java.awt.image.DirectColorModel;
  33 import java.awt.image.Raster;
  34 import java.awt.image.WritableRaster;
  35 import java.awt.peer.RobotPeer;
  36 
  37 import sun.awt.AWTPermissions;
  38 import sun.awt.ComponentFactory;
  39 import sun.awt.SunToolkit;
  40 import sun.awt.image.SunWritableRaster;
  41 
  42 /**
  43  * This class is used to generate native system input events
  44  * for the purposes of test automation, self-running demos, and
  45  * other applications where control of the mouse and keyboard
  46  * is needed. The primary purpose of Robot is to facilitate
  47  * automated testing of Java platform implementations.
  48  * <p>
  49  * Using the class to generate input events differs from posting
  50  * events to the AWT event queue or AWT components in that the
  51  * events are generated in the platform's native input
  52  * queue. For example, {@code Robot.mouseMove} will actually move
  53  * the mouse cursor instead of just generating mouse move events.
  54  * <p>
  55  * Note that some platforms require special privileges or extensions
  56  * to access low-level input control. If the current platform configuration
  57  * does not allow input control, an {@code AWTException} will be thrown
  58  * when trying to construct Robot objects. For example, X-Window systems
  59  * will throw the exception if the XTEST 2.2 standard extension is not supported
  60  * (or not enabled) by the X server.
  61  * <p>
  62  * Applications that use Robot for purposes other than self-testing should
  63  * handle these error conditions gracefully.
  64  *
  65  * @author      Robi Khan
  66  * @since       1.3
  67  */
  68 public class Robot {
  69     private static final int MAX_DELAY = 60000;
  70     private RobotPeer peer;
  71     private boolean isAutoWaitForIdle = false;
  72     private int autoDelay = 0;
  73     private static int LEGAL_BUTTON_MASK = 0;
  74 
  75     private DirectColorModel screenCapCM = null;
  76 
  77     /**
  78      * Constructs a Robot object in the coordinate system of the primary screen.
  79      *
  80      * @throws  AWTException if the platform configuration does not allow
  81      * low-level input control.  This exception is always thrown when
  82      * GraphicsEnvironment.isHeadless() returns true
  83      * @throws  SecurityException if {@code createRobot} permission is not granted
  84      * @see     java.awt.GraphicsEnvironment#isHeadless
  85      * @see     SecurityManager#checkPermission
  86      * @see     AWTPermission
  87      */
  88     public Robot() throws AWTException {
  89         if (GraphicsEnvironment.isHeadless()) {
  90             throw new AWTException("headless environment");
  91         }
  92         init(GraphicsEnvironment.getLocalGraphicsEnvironment()
  93             .getDefaultScreenDevice());
  94     }
  95 
  96     /**
  97      * Creates a Robot for the given screen device. Coordinates passed
  98      * to Robot method calls like mouseMove and createScreenCapture will
  99      * be interpreted as being in the same coordinate system as the
 100      * specified screen. Note that depending on the platform configuration,
 101      * multiple screens may either:
 102      * <ul>
 103      * <li>share the same coordinate system to form a combined virtual screen</li>
 104      * <li>use different coordinate systems to act as independent screens</li>
 105      * </ul>
 106      * This constructor is meant for the latter case.
 107      * <p>
 108      * If screen devices are reconfigured such that the coordinate system is
 109      * affected, the behavior of existing Robot objects is undefined.
 110      *
 111      * @param screen    A screen GraphicsDevice indicating the coordinate
 112      *                  system the Robot will operate in.
 113      * @throws  AWTException if the platform configuration does not allow
 114      * low-level input control.  This exception is always thrown when
 115      * GraphicsEnvironment.isHeadless() returns true.
 116      * @throws  IllegalArgumentException if {@code screen} is not a screen
 117      *          GraphicsDevice.
 118      * @throws  SecurityException if {@code createRobot} permission is not granted
 119      * @see     java.awt.GraphicsEnvironment#isHeadless
 120      * @see     GraphicsDevice
 121      * @see     SecurityManager#checkPermission
 122      * @see     AWTPermission
 123      */
 124     public Robot(GraphicsDevice screen) throws AWTException {
 125         checkIsScreenDevice(screen);
 126         init(screen);
 127     }
 128 
 129     private void init(GraphicsDevice screen) throws AWTException {
 130         checkRobotAllowed();
 131         Toolkit toolkit = Toolkit.getDefaultToolkit();
 132         if (toolkit instanceof ComponentFactory) {
 133             peer = ((ComponentFactory)toolkit).createRobot(this, screen);
 134             disposer = new RobotDisposer(peer);
 135             sun.java2d.Disposer.addRecord(anchor, disposer);
 136         }
 137         initLegalButtonMask();
 138     }


 319             throw new IllegalArgumentException("Invalid combination of button flags");
 320         }
 321     }
 322 
 323     /**
 324      * Rotates the scroll wheel on wheel-equipped mice.
 325      *
 326      * @param wheelAmt  number of "notches" to move the mouse wheel
 327      *                  Negative values indicate movement up/away from the user,
 328      *                  positive values indicate movement down/towards the user.
 329      *
 330      * @since 1.4
 331      */
 332     public synchronized void mouseWheel(int wheelAmt) {
 333         peer.mouseWheel(wheelAmt);
 334         afterEvent();
 335     }
 336 
 337     /**
 338      * Presses a given key.  The key should be released using the
 339      * {@code keyRelease} method.
 340      * <p>
 341      * Key codes that have more than one physical key associated with them
 342      * (e.g. {@code KeyEvent.VK_SHIFT} could mean either the
 343      * left or right shift key) will map to the left key.
 344      *
 345      * @param   keycode Key to press (e.g. {@code KeyEvent.VK_A})
 346      * @throws  IllegalArgumentException if {@code keycode} is not
 347      *          a valid key
 348      * @see     #keyRelease(int)
 349      * @see     java.awt.event.KeyEvent
 350      */
 351     public synchronized void keyPress(int keycode) {
 352         checkKeycodeArgument(keycode);
 353         peer.keyPress(keycode);
 354         afterEvent();
 355     }
 356 
 357     /**
 358      * Releases a given key.
 359      * <p>
 360      * Key codes that have more than one physical key associated with them
 361      * (e.g. {@code KeyEvent.VK_SHIFT} could mean either the
 362      * left or right shift key) will map to the left key.
 363      *
 364      * @param   keycode Key to release (e.g. {@code KeyEvent.VK_A})
 365      * @throws  IllegalArgumentException if {@code keycode} is not a
 366      *          valid key
 367      * @see  #keyPress(int)
 368      * @see     java.awt.event.KeyEvent
 369      */
 370     public synchronized void keyRelease(int keycode) {
 371         checkKeycodeArgument(keycode);
 372         peer.keyRelease(keycode);
 373         afterEvent();
 374     }
 375 
 376     private void checkKeycodeArgument(int keycode) {
 377         // rather than build a big table or switch statement here, we'll
 378         // just check that the key isn't VK_UNDEFINED and assume that the
 379         // peer implementations will throw an exception for other bogus
 380         // values e.g. -1, 999999
 381         if (keycode == KeyEvent.VK_UNDEFINED) {
 382             throw new IllegalArgumentException("Invalid key code");
 383         }
 384     }
 385 
 386     /**
 387      * Returns the color of a pixel at the given screen coordinates.
 388      * @param   x       X position of pixel
 389      * @param   y       Y position of pixel
 390      * @return  Color of the pixel
 391      */
 392     public synchronized Color getPixelColor(int x, int y) {
 393         Color color = new Color(peer.getRGBPixel(x, y));
 394         return color;
 395     }
 396 
 397     /**
 398      * Creates an image containing pixels read from the screen.  This image does
 399      * not include the mouse cursor.
 400      * @param   screenRect      Rect to capture in screen coordinates
 401      * @return  The captured image
 402      * @throws  IllegalArgumentException if {@code screenRect} width and height are not greater than zero
 403      * @throws  SecurityException if {@code readDisplayPixels} permission is not granted
 404      * @see     SecurityManager#checkPermission
 405      * @see     AWTPermission
 406      */
 407     public synchronized BufferedImage createScreenCapture(Rectangle screenRect) {
 408         checkScreenCaptureAllowed();
 409 
 410         checkValidRect(screenRect);
 411 
 412         BufferedImage image;
 413         DataBufferInt buffer;
 414         WritableRaster raster;
 415 
 416         if (screenCapCM == null) {
 417             /*
 418              * Fix for 4285201
 419              * Create a DirectColorModel equivalent to the default RGB ColorModel,
 420              * except with no Alpha component.
 421              */
 422 
 423             screenCapCM = new DirectColorModel(24,


 453             throw new IllegalArgumentException("Rectangle width and height must be > 0");
 454         }
 455     }
 456 
 457     private static void checkScreenCaptureAllowed() {
 458         SecurityManager security = System.getSecurityManager();
 459         if (security != null) {
 460             security.checkPermission(AWTPermissions.READ_DISPLAY_PIXELS_PERMISSION);
 461         }
 462     }
 463 
 464     /*
 465      * Called after an event is generated
 466      */
 467     private void afterEvent() {
 468         autoWaitForIdle();
 469         autoDelay();
 470     }
 471 
 472     /**
 473      * Returns whether this Robot automatically invokes {@code waitForIdle}
 474      * after generating an event.
 475      * @return Whether {@code waitForIdle} is automatically called
 476      */
 477     public synchronized boolean isAutoWaitForIdle() {
 478         return isAutoWaitForIdle;
 479     }
 480 
 481     /**
 482      * Sets whether this Robot automatically invokes {@code waitForIdle}
 483      * after generating an event.
 484      * @param   isOn    Whether {@code waitForIdle} is automatically invoked
 485      */
 486     public synchronized void setAutoWaitForIdle(boolean isOn) {
 487         isAutoWaitForIdle = isOn;
 488     }
 489 
 490     /*
 491      * Calls waitForIdle after every event if so desired.
 492      */
 493     private void autoWaitForIdle() {
 494         if (isAutoWaitForIdle) {
 495             waitForIdle();
 496         }
 497     }
 498 
 499     /**
 500      * Returns the number of milliseconds this Robot sleeps after generating an event.
 501      *
 502      * @return the delay duration in milliseconds
 503      */
 504     public synchronized int getAutoDelay() {


 509      * Sets the number of milliseconds this Robot sleeps after generating an event.
 510      *
 511      * @param  ms the delay duration in milliseconds
 512      * @throws IllegalArgumentException If {@code ms}
 513      *         is not between 0 and 60,000 milliseconds inclusive
 514      */
 515     public synchronized void setAutoDelay(int ms) {
 516         checkDelayArgument(ms);
 517         autoDelay = ms;
 518     }
 519 
 520     /*
 521      * Automatically sleeps for the specified interval after event generated.
 522      */
 523     private void autoDelay() {
 524         delay(autoDelay);
 525     }
 526 
 527     /**
 528      * Sleeps for the specified time.
 529      * To catch any {@code InterruptedException}s that occur,
 530      * {@code Thread.sleep()} may be used instead.
 531      *
 532      * @param  ms time to sleep in milliseconds
 533      * @throws IllegalArgumentException if {@code ms}
 534      *         is not between 0 and 60,000 milliseconds inclusive
 535      * @see java.lang.Thread#sleep
 536      */
 537     public synchronized void delay(int ms) {
 538         checkDelayArgument(ms);
 539         try {
 540             Thread.sleep(ms);
 541         } catch(InterruptedException ite) {
 542             ite.printStackTrace();
 543         }
 544     }
 545 
 546     private void checkDelayArgument(int ms) {
 547         if (ms < 0 || ms > MAX_DELAY) {
 548             throw new IllegalArgumentException("Delay must be to 0 to 60,000ms");
 549         }
 550     }


< prev index next >