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 }
|