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

Print this page




  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.awt;
  27 
  28 import java.awt.event.InputEvent;
  29 import java.awt.event.KeyEvent;
  30 import java.awt.image.BufferedImage;
  31 import java.awt.image.DataBufferInt;
  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 import java.lang.reflect.InvocationTargetException;

  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());


 183         public void dispose() {
 184             if (peer != null) {
 185                 peer.dispose();
 186             }
 187         }
 188     }
 189 
 190     private transient RobotDisposer disposer;
 191 
 192     /**
 193      * Moves mouse pointer to given screen coordinates.
 194      * @param x         X position
 195      * @param y         Y position
 196      */
 197     public synchronized void mouseMove(int x, int y) {
 198         peer.mouseMove(x, y);
 199         afterEvent();
 200     }
 201 
 202     /**






























































































































 203      * Presses one or more mouse buttons.  The mouse buttons should
 204      * be released using the {@link #mouseRelease(int)} method.
 205      *
 206      * @param buttons the Button mask; a combination of one or more
 207      * mouse button masks.
 208      * <p>
 209      * It is allowed to use only a combination of valid values as a {@code buttons} parameter.
 210      * A valid combination consists of {@code InputEvent.BUTTON1_DOWN_MASK},
 211      * {@code InputEvent.BUTTON2_DOWN_MASK}, {@code InputEvent.BUTTON3_DOWN_MASK}
 212      * and values returned by the
 213      * {@link InputEvent#getMaskForButton(int) InputEvent.getMaskForButton(button)} method.
 214      *
 215      * The valid combination also depends on a
 216      * {@link Toolkit#areExtraMouseButtonsEnabled() Toolkit.areExtraMouseButtonsEnabled()} value as follows:
 217      * <ul>
 218      * <li> If support for extended mouse buttons is
 219      * {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java
 220      * then it is allowed to use only the following standard button masks:
 221      * {@code InputEvent.BUTTON1_DOWN_MASK}, {@code InputEvent.BUTTON2_DOWN_MASK},
 222      * {@code InputEvent.BUTTON3_DOWN_MASK}.


 297      * However, it is recommended to use {@code InputEvent.BUTTON1_DOWN_MASK},
 298      * {@code InputEvent.BUTTON2_DOWN_MASK},  {@code InputEvent.BUTTON3_DOWN_MASK} instead.
 299      * Either extended {@code _DOWN_MASK} or old {@code _MASK} values
 300      * should be used, but both those models should not be mixed.
 301      * @throws IllegalArgumentException if the {@code buttons} mask contains the mask for extra mouse button
 302      *         and support for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java
 303      * @throws IllegalArgumentException if the {@code buttons} mask contains the mask for extra mouse button
 304      *         that does not exist on the mouse and support for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java
 305      * @see #mousePress(int)
 306      * @see InputEvent#getMaskForButton(int)
 307      * @see Toolkit#areExtraMouseButtonsEnabled()
 308      * @see java.awt.MouseInfo#getNumberOfButtons()
 309      * @see java.awt.event.MouseEvent
 310      */
 311     public synchronized void mouseRelease(int buttons) {
 312         checkButtonsArgument(buttons);
 313         peer.mouseRelease(buttons);
 314         afterEvent();
 315     }
 316 





















































































 317     private void checkButtonsArgument(int buttons) {
 318         if ( (buttons|LEGAL_BUTTON_MASK) != LEGAL_BUTTON_MASK ) {
 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 


 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     }


 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() {
 505         return autoDelay;
 506     }
 507 
 508     /**
 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 


 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     }
 551 
 552     /**
 553      * Waits until all events currently on the event queue have been processed.
 554      * @throws  IllegalThreadStateException if called on the AWT event dispatching thread





 555      */
 556     public synchronized void waitForIdle() {
 557         checkNotDispatchThread();
 558         // post a dummy event to the queue so we know when
 559         // all the events before it have been processed
 560         try {
 561             SunToolkit.flushPendingEvents();
 562             EventQueue.invokeAndWait( new Runnable() {
 563                                             public void run() {
 564                                                 // dummy implementation
 565                                             }
 566                                         } );
 567         } catch(InterruptedException ite) {
 568             System.err.println("Robot.waitForIdle, non-fatal exception caught:");












 569             ite.printStackTrace();
 570         } catch(InvocationTargetException ine) {
 571             System.err.println("Robot.waitForIdle, non-fatal exception caught:");
 572             ine.printStackTrace();
 573         }













 574     }
 575 
 576     private void checkNotDispatchThread() {
 577         if (EventQueue.isDispatchThread()) {
 578             throw new IllegalThreadStateException("Cannot call method from the event dispatcher thread");
 579         }
 580     }
 581 
 582     /**
 583      * Returns a string representation of this Robot.
 584      *
 585      * @return  the string representation.
 586      */
 587     public synchronized String toString() {
 588         String params = "autoDelay = "+getAutoDelay()+", "+"autoWaitForIdle = "+isAutoWaitForIdle();
 589         return getClass().getName() + "[ " + params + " ]";
 590     }
 591 }


  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.awt;
  27 
  28 import java.awt.event.InputEvent;
  29 import java.awt.event.KeyEvent;
  30 import java.awt.image.BufferedImage;
  31 import java.awt.image.DataBufferInt;
  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 import java.security.AccessController;
  37 
  38 import sun.awt.AWTPermissions;
  39 import sun.awt.ComponentFactory;
  40 import sun.awt.ExtendedKeyCodes;
  41 import sun.awt.SunToolkit;
  42 import sun.awt.image.SunWritableRaster;
  43 import sun.security.action.GetIntegerAction;
  44 
  45 /**
  46  * This class is used to generate native system input events
  47  * for the purposes of test automation, self-running demos, and
  48  * other applications where control of the mouse and keyboard
  49  * is needed. The primary purpose of Robot is to facilitate
  50  * automated testing of Java platform implementations.
  51  * <p>
  52  * Using the class to generate input events differs from posting
  53  * events to the AWT event queue or AWT components in that the
  54  * events are generated in the platform's native input
  55  * queue. For example, <code>Robot.mouseMove</code> will actually move
  56  * the mouse cursor instead of just generating mouse move events.
  57  * <p>
  58  * Robot uses delay {@link #getSyncDelay()} to make syncing threads
  59  * with {@link #waitForIdle()} more stable. This delay can be set once
  60  * on creating object and could not be changed throughout object lifecycle.
  61  * Constructor reads vm integer property {@code java.awt.robotdelay} and
  62  * sets the delay value equal to the property value. If the property was
  63  * not set 500 milliseconds default value is used.
  64  * <p>
  65  * Note that some platforms require special privileges or extensions
  66  * to access low-level input control. If the current platform configuration
  67  * does not allow input control, an <code>AWTException</code> will be thrown
  68  * when trying to construct Robot objects. For example, X-Window systems
  69  * will throw the exception if the XTEST 2.2 standard extension is not supported
  70  * (or not enabled) by the X server.
  71  * <p>
  72  * Applications that use Robot for purposes other than self-testing should
  73  * handle these error conditions gracefully.
  74  *
  75  * @author      Robi Khan
  76  * @since       1.3
  77  */
  78 public class Robot {
  79     private static final int MAX_DELAY = 60000;
  80     private RobotPeer peer;
  81     private boolean isAutoWaitForIdle = false;
  82     private int autoDelay = 0;
  83     private static int LEGAL_BUTTON_MASK = 0;
  84     private static int DEFAULT_SPEED = 20;       // Speed for mouse glide and click
  85     private static int DEFAULT_SYNC_DELAY = 500; // Default Additional delay for waitForIdle()
  86     private static int DEFAULT_STEP_LENGTH = 2;  // Step length (in pixels) for mouse glide
  87 
  88     private final int syncDelay;
  89     {
  90         syncDelay = AccessController.doPrivileged(
  91                 new GetIntegerAction("java.awt.robotdelay", DEFAULT_SYNC_DELAY));
  92     }
  93 
  94 
  95     private DirectColorModel screenCapCM = null;
  96 
  97     /**
  98      * Constructs a Robot object in the coordinate system of the primary screen.
  99      *
 100      * @throws AWTException if the platform configuration does not allow
 101      * low-level input control.  This exception is always thrown when
 102      * GraphicsEnvironment.isHeadless() returns true
 103      * @throws  SecurityException if <code>createRobot</code> permission is not granted
 104      * @see     java.awt.GraphicsEnvironment#isHeadless
 105      * @see     SecurityManager#checkPermission
 106      * @see     AWTPermission
 107      */
 108     public Robot() throws AWTException {
 109         if (GraphicsEnvironment.isHeadless()) {
 110             throw new AWTException("headless environment");
 111         }
 112         init(GraphicsEnvironment.getLocalGraphicsEnvironment()
 113             .getDefaultScreenDevice());


 203         public void dispose() {
 204             if (peer != null) {
 205                 peer.dispose();
 206             }
 207         }
 208     }
 209 
 210     private transient RobotDisposer disposer;
 211 
 212     /**
 213      * Moves mouse pointer to given screen coordinates.
 214      * @param x         X position
 215      * @param y         Y position
 216      */
 217     public synchronized void mouseMove(int x, int y) {
 218         peer.mouseMove(x, y);
 219         afterEvent();
 220     }
 221 
 222     /**
 223      * Moves mouse pointer to given screen coordinates.
 224      *
 225      * @param   position    Target position
 226      *
 227      * @see     #mouseMove(int, int)
 228      */
 229     public synchronized void mouseMove(Point position) {
 230         mouseMove(position.x, position.y);
 231     }
 232 
 233     /**
 234      * Move mouse cursor to the center of the Component.
 235      *
 236      * @param   c   Component the mouse is placed over
 237      *
 238      * @see     #mouseMove(int, int)
 239      */
 240     public synchronized void mouseMove(Component c) {
 241         Point p = c.getLocationOnScreen();
 242         Dimension size = c.getSize();
 243         p.x += size.width / 2;
 244         p.y += size.height / 2;
 245         mouseMove(p.x, p.y);
 246     }
 247 
 248     /**
 249      * Move the mouse in multiple steps from where it is
 250      * now to the destination coordinates.
 251      *
 252      * @param   x   Destination point x coordinate
 253      * @param   y   Destination point y coordinate
 254      *
 255      * @see     #glide(int, int, int, int)
 256      */
 257     public void glide(int x, int y) {
 258         Point p = MouseInfo.getPointerInfo().getLocation();
 259         glide(p.x, p.y, x, y);
 260     }
 261 
 262     /**
 263      * Move the mouse in multiple steps from where it is
 264      * now to the destination point.
 265      *
 266      * @param   dest    Destination point
 267      *
 268      * @see     #glide(int, int)
 269      */
 270     public void glide(Point dest) {
 271         glide(dest.x, dest.y);
 272     }
 273 
 274     /**
 275      * Move the mouse in multiple steps from source coordinates
 276      * to the destination coordinates.
 277      *
 278      * @param   fromX   Source point x coordinate
 279      * @param   fromY   Source point y coordinate
 280      * @param   toX     Destination point x coordinate
 281      * @param   toY     Destination point y coordinate
 282      *
 283      * @see     #glide(int, int, int, int, int, int)
 284      */
 285     public void glide(int fromX, int fromY, int toX, int toY) {
 286         glide(fromX, fromY, toX, toY, DEFAULT_STEP_LENGTH, DEFAULT_SPEED);
 287     }
 288 
 289     /**
 290      * Move the mouse in multiple steps from source point to the
 291      * destination point with default speed and step length.
 292      *
 293      * @param   src     Source point
 294      * @param   dest    Destination point
 295      *
 296      * @see     #glide(int, int, int, int, int, int)
 297      */
 298     public void glide(Point src, Point dest) {
 299         glide(src.x, src.y, dest.x, dest.y, DEFAULT_STEP_LENGTH, DEFAULT_SPEED);
 300     }
 301 
 302     /**
 303      * Move the mouse in multiple steps from source point to the
 304      * destination point with given speed and step length.
 305      *
 306      * @param   srcX        Source point x cordinate
 307      * @param   srcY        Source point y cordinate
 308      * @param   destX       Destination point x cordinate
 309      * @param   destY       Destination point y cordinate
 310      * @param   stepLength  Approximate length of one step
 311      * @param   speed       Delay between steps.
 312      *
 313      * @see     #mouseMove(int, int)
 314      * @see     #delay(int)
 315      */
 316     public void glide(int srcX, int srcY, int destX, int destY, int stepLength, int speed) {
 317         int stepNum;
 318         double tDx, tDy;
 319         double dx, dy, ds;
 320         double x, y;
 321 
 322         dx = (destX - srcX);
 323         dy = (destY - srcY);
 324         ds = Math.sqrt(dx*dx + dy*dy);
 325 
 326         tDx = dx / ds * stepLength;
 327         tDy = dy / ds * stepLength;
 328 
 329         int stepsCount = (int) ds / stepLength;
 330 
 331         // Walk the mouse to the destination one step at a time
 332         mouseMove(srcX, srcY);
 333 
 334         for (x = srcX, y = srcY, stepNum = 0;
 335              stepNum < stepsCount;
 336              stepNum++) {
 337             x += tDx;
 338             y += tDy;
 339             mouseMove((int)x, (int)y);
 340             delay(speed);
 341         }
 342 
 343         // Ensure the mouse moves to the right destination.
 344         // The steps may have led the mouse to a slightly wrong place.
 345         mouseMove(destX, destY);
 346     }
 347 
 348     /**
 349      * Presses one or more mouse buttons.  The mouse buttons should
 350      * be released using the {@link #mouseRelease(int)} method.
 351      *
 352      * @param buttons the Button mask; a combination of one or more
 353      * mouse button masks.
 354      * <p>
 355      * It is allowed to use only a combination of valid values as a {@code buttons} parameter.
 356      * A valid combination consists of {@code InputEvent.BUTTON1_DOWN_MASK},
 357      * {@code InputEvent.BUTTON2_DOWN_MASK}, {@code InputEvent.BUTTON3_DOWN_MASK}
 358      * and values returned by the
 359      * {@link InputEvent#getMaskForButton(int) InputEvent.getMaskForButton(button)} method.
 360      *
 361      * The valid combination also depends on a
 362      * {@link Toolkit#areExtraMouseButtonsEnabled() Toolkit.areExtraMouseButtonsEnabled()} value as follows:
 363      * <ul>
 364      * <li> If support for extended mouse buttons is
 365      * {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java
 366      * then it is allowed to use only the following standard button masks:
 367      * {@code InputEvent.BUTTON1_DOWN_MASK}, {@code InputEvent.BUTTON2_DOWN_MASK},
 368      * {@code InputEvent.BUTTON3_DOWN_MASK}.


 443      * However, it is recommended to use {@code InputEvent.BUTTON1_DOWN_MASK},
 444      * {@code InputEvent.BUTTON2_DOWN_MASK},  {@code InputEvent.BUTTON3_DOWN_MASK} instead.
 445      * Either extended {@code _DOWN_MASK} or old {@code _MASK} values
 446      * should be used, but both those models should not be mixed.
 447      * @throws IllegalArgumentException if the {@code buttons} mask contains the mask for extra mouse button
 448      *         and support for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java
 449      * @throws IllegalArgumentException if the {@code buttons} mask contains the mask for extra mouse button
 450      *         that does not exist on the mouse and support for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java
 451      * @see #mousePress(int)
 452      * @see InputEvent#getMaskForButton(int)
 453      * @see Toolkit#areExtraMouseButtonsEnabled()
 454      * @see java.awt.MouseInfo#getNumberOfButtons()
 455      * @see java.awt.event.MouseEvent
 456      */
 457     public synchronized void mouseRelease(int buttons) {
 458         checkButtonsArgument(buttons);
 459         peer.mouseRelease(buttons);
 460         afterEvent();
 461     }
 462 
 463     /**
 464      * Clicks mouse button(s) by calling {@link #mousePress(int)} and
 465      * {@link #mouseRelease(int)} methods
 466      *
 467      *
 468      * @param   buttons The button mask; a combination of one or more mouse button masks.
 469      * @throws  IllegalArgumentException if the {@code buttons} mask contains the mask for
 470      *          extra mouse button and support for extended mouse buttons is
 471      *          {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java
 472      * @throws  IllegalArgumentException if the {@code buttons} mask contains the mask for
 473      *          extra mouse button that does not exist on the mouse and support for extended
 474      *          mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() enabled}
 475      *          by Java
 476      *
 477      * @see     #mousePress(int)
 478      * @see     #mouseRelease(int)
 479      * @see     InputEvent#getMaskForButton(int)
 480      * @see     Toolkit#areExtraMouseButtonsEnabled()
 481      * @see     java.awt.event.MouseEvent
 482      */
 483     public void click(int buttons) {
 484         mousePress(buttons);
 485         waitForIdle(DEFAULT_SPEED);
 486         mouseRelease(buttons);
 487         waitForIdle();
 488     }
 489 
 490     /**
 491      * Clicks mouse button 1
 492      *
 493      * @throws  IllegalArgumentException if the {@code buttons} mask contains the mask for
 494      *          extra mouse button and support for extended mouse buttons is
 495      *          {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java
 496      * @throws  IllegalArgumentException if the {@code buttons} mask contains the mask for
 497      *          extra mouse button that does not exist on the mouse and support for extended
 498      *          mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() enabled}
 499      *          by Java
 500      *
 501      * @see     #click(int)
 502      */
 503     public void click() {
 504         click(InputEvent.BUTTON1_DOWN_MASK);
 505     }
 506 
 507     /**
 508      * Emulate native drag and drop process using {@code InputEvent.BUTTON1_DOWN_MASK}.
 509      * The method successively moves mouse cursor to point with coordinates
 510      * ({@code fromX}, {@code fromY}), presses mouse button 1, drag mouse to
 511      * point with coordinates ({@code toX}, {@code toY}) and releases mouse
 512      * button 1 at last.
 513      *
 514      * @param   fromX   Source point x coordinate
 515      * @param   fromY   Source point y coordinate
 516      * @param   toX     Destination point x coordinate
 517      * @param   toY     Destination point y coordinate
 518      *
 519      * @see     #mousePress(int)
 520      * @see     #glide(int, int, int, int)
 521      */
 522     public void dragAndDrop(int fromX, int fromY, int toX, int toY) {
 523         mouseMove(fromX, fromY);
 524         mousePress(InputEvent.BUTTON1_DOWN_MASK);
 525         waitForIdle();
 526         glide(toX, toY);
 527         mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
 528         waitForIdle();
 529     }
 530 
 531     /**
 532      * Emulate native drag and drop process using {@code InputEvent.BUTTON1_DOWN_MASK}.
 533      * The method successively moves mouse cursor to point {@code from},
 534      * presses mouse button 1, drag mouse to point {@code to} and releases
 535      * mouse button 1 at last.
 536      *
 537      * @param   from    Source point
 538      * @param   to      Destination point
 539      *
 540      * @see     #mousePress(int)
 541      * @see     #glide(int, int, int, int)
 542      * @see     #dragAndDrop(int, int, int, int)
 543      */
 544     public void dragAndDrop(Point from, Point to) {
 545         dragAndDrop(from.x, from.y, to.x, to.y);
 546     }
 547 
 548     private void checkButtonsArgument(int buttons) {
 549         if ( (buttons|LEGAL_BUTTON_MASK) != LEGAL_BUTTON_MASK ) {
 550             throw new IllegalArgumentException("Invalid combination of button flags");
 551         }
 552     }
 553 
 554     /**
 555      * Rotates the scroll wheel on wheel-equipped mice.
 556      *
 557      * @param wheelAmt  number of "notches" to move the mouse wheel
 558      *                  Negative values indicate movement up/away from the user,
 559      *                  positive values indicate movement down/towards the user.
 560      *
 561      * @since 1.4
 562      */
 563     public synchronized void mouseWheel(int wheelAmt) {
 564         peer.mouseWheel(wheelAmt);
 565         afterEvent();
 566     }
 567 


 587 
 588     /**
 589      * Releases a given key.
 590      * <p>
 591      * Key codes that have more than one physical key associated with them
 592      * (e.g. <code>KeyEvent.VK_SHIFT</code> could mean either the
 593      * left or right shift key) will map to the left key.
 594      *
 595      * @param   keycode Key to release (e.g. <code>KeyEvent.VK_A</code>)
 596      * @throws  IllegalArgumentException if <code>keycode</code> is not a
 597      *          valid key
 598      * @see  #keyPress(int)
 599      * @see     java.awt.event.KeyEvent
 600      */
 601     public synchronized void keyRelease(int keycode) {
 602         checkKeycodeArgument(keycode);
 603         peer.keyRelease(keycode);
 604         afterEvent();
 605     }
 606 
 607     /**
 608      * Successively presses and releases a given key.
 609      * <p>
 610      * Key codes that have more than one physical key associated with them
 611      * (e.g. {@code KeyEvent.VK_SHIFT} could mean either the
 612      * left or right shift key) will map to the left key.
 613      *
 614      * @param   keycode Key to press (e.g. {@code KeyEvent.VK_A})
 615      * @throws  IllegalArgumentException if {@code keycode} is not
 616      *          a valid key
 617      *
 618      * @see     #keyPress(int)
 619      * @see     #keyRelease(int)
 620      * @see     java.awt.event.KeyEvent
 621      */
 622     public void type(int keycode) {
 623         keyPress(keycode);
 624         waitForIdle(DEFAULT_SPEED);
 625         keyRelease(keycode);
 626         waitForIdle();
 627     }
 628 
 629     /**
 630      * Types given character
 631      *
 632      * @param   c   Character to be typed (e.g. {@code 'a'})
 633      *
 634      * @see     #type(int)
 635      * @see     java.awt.event.KeyEvent
 636      */
 637     public void type(char c) {
 638         type(ExtendedKeyCodes.getExtendedKeyCodeForChar(c));
 639     }
 640 
 641     /**
 642      * Types given array of characters one by one
 643      *
 644      * @param   symbols Array of characters to be typed
 645      *
 646      * @see     #type(char)
 647      */
 648     public void type(char[] symbols) {
 649         for (int i = 0; i < symbols.length; i++) {
 650             type(symbols[i]);
 651         }
 652     }
 653 
 654     /**
 655      * Types given string
 656      *
 657      * @param   s   String to be typed
 658      *
 659      * @see     #type(char[])
 660      */
 661     public void type(String s) {
 662         type(s.toCharArray());
 663     }
 664 
 665     private void checkKeycodeArgument(int keycode) {
 666         // rather than build a big table or switch statement here, we'll
 667         // just check that the key isn't VK_UNDEFINED and assume that the
 668         // peer implementations will throw an exception for other bogus
 669         // values e.g. -1, 999999
 670         if (keycode == KeyEvent.VK_UNDEFINED) {
 671             throw new IllegalArgumentException("Invalid key code");
 672         }
 673     }
 674 
 675     /**
 676      * Returns the color of a pixel at the given screen coordinates.
 677      * @param   x       X position of pixel
 678      * @param   y       Y position of pixel
 679      * @return  Color of the pixel
 680      */
 681     public synchronized Color getPixelColor(int x, int y) {
 682         Color color = new Color(peer.getRGBPixel(x, y));
 683         return color;
 684     }


 769 
 770     /**
 771      * Sets whether this Robot automatically invokes <code>waitForIdle</code>
 772      * after generating an event.
 773      * @param   isOn    Whether <code>waitForIdle</code> is automatically invoked
 774      */
 775     public synchronized void setAutoWaitForIdle(boolean isOn) {
 776         isAutoWaitForIdle = isOn;
 777     }
 778 
 779     /*
 780      * Calls waitForIdle after every event if so desired.
 781      */
 782     private void autoWaitForIdle() {
 783         if (isAutoWaitForIdle) {
 784             waitForIdle();
 785         }
 786     }
 787 
 788     /**
 789      * Returns delay length for {@link #waitForIdle()} method
 790      *
 791      * @return  Current delay value
 792      *
 793      * @see     #waitForIdle()
 794      */
 795     public int getSyncDelay() {
 796         return this.syncDelay;
 797     }
 798 
 799     /**
 800      * Returns the number of milliseconds this Robot sleeps after generating an event.
 801      *
 802      * @return the delay duration in milliseconds
 803      */
 804     public synchronized int getAutoDelay() {
 805         return autoDelay;
 806     }
 807 
 808     /**
 809      * Sets the number of milliseconds this Robot sleeps after generating an event.
 810      *
 811      * @param  ms the delay duration in milliseconds
 812      * @throws IllegalArgumentException If {@code ms}
 813      *         is not between 0 and 60,000 milliseconds inclusive
 814      */
 815     public synchronized void setAutoDelay(int ms) {
 816         checkDelayArgument(ms);
 817         autoDelay = ms;
 818     }
 819 


 833      * @throws IllegalArgumentException if {@code ms}
 834      *         is not between 0 and 60,000 milliseconds inclusive
 835      * @see java.lang.Thread#sleep
 836      */
 837     public synchronized void delay(int ms) {
 838         checkDelayArgument(ms);
 839         try {
 840             Thread.sleep(ms);
 841         } catch(InterruptedException ite) {
 842             ite.printStackTrace();
 843         }
 844     }
 845 
 846     private void checkDelayArgument(int ms) {
 847         if (ms < 0 || ms > MAX_DELAY) {
 848             throw new IllegalArgumentException("Delay must be to 0 to 60,000ms");
 849         }
 850     }
 851 
 852     /**
 853      * Waits until all events currently on the event queue have been processed with given
 854      * delay after syncing threads.
 855      *
 856      * @param   delayValue  Additional delay length in milliseconds to wait until thread
 857      *                      sync been completed
 858      * @throws  sun.awt.SunToolkit.IllegalThreadException if called on the AWT event
 859      *          dispatching thread
 860      */
 861     public synchronized void waitForIdle(int delayValue) {




 862         SunToolkit.flushPendingEvents();
 863         ((SunToolkit) Toolkit.getDefaultToolkit()).realSync();
 864         delay(delayValue);

 865     }
 866 
 867     /**
 868      * Static method for synchronizing event queue with current thread. Waits until
 869      * all events currently on the event queue have been processed with a small delay
 870      * of 500 ms after syncing threads.
 871      *
 872      * @throws  sun.awt.SunToolkit.IllegalThreadException if called on the AWT event
 873      *          dispatching thread
 874      */
 875     public static synchronized void syncEventQueue() {
 876         SunToolkit.flushPendingEvents();
 877         ((SunToolkit) Toolkit.getDefaultToolkit()).realSync();
 878         try {
 879             Thread.sleep(DEFAULT_SYNC_DELAY);
 880         } catch (InterruptedException ite) {
 881             ite.printStackTrace();



 882         }
 883     }
 884 
 885     /**
 886      * Waits until all events currently on the event queue have been processed with delay
 887      * {@link #getSyncDelay()} after syncing threads.
 888      *
 889      * @throws  sun.awt.SunToolkit.IllegalThreadException if called on the AWT event
 890      *          dispatching thread
 891      *
 892      * @see     #waitForIdle(int)
 893      */
 894     public synchronized void waitForIdle() {
 895         waitForIdle(syncDelay);
 896     }
 897 
 898     private void checkNotDispatchThread() {
 899         if (EventQueue.isDispatchThread()) {
 900             throw new IllegalThreadStateException("Cannot call method from the event dispatcher thread");
 901         }
 902     }
 903 
 904     /**
 905      * Returns a string representation of this Robot.
 906      *
 907      * @return  the string representation.
 908      */
 909     public synchronized String toString() {
 910         String params = "autoDelay = "+getAutoDelay()+", "+"autoWaitForIdle = "+isAutoWaitForIdle();
 911         return getClass().getName() + "[ " + params + " ]";
 912     }
 913 }