History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/awt/Robot.java (1 of 18352 files). Show all

Unified · Split

java/pkg/java/awt/Robot.java+593−0
@@ -0,0 +1,593 @@
1+/*
2+ * Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
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.ComponentFactory;
38+import sun.awt.SunToolkit;
39+import sun.awt.image.SunWritableRaster;
40+import sun.security.util.SecurityConstants;
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+ // location of robot's GC, used in mouseMove(), getPixelColor() and captureScreenImage()
76+ private Point gdLoc;
77+
78+ private DirectColorModel screenCapCM = null;
79+
80+ /**
81+ * Constructs a Robot object in the coordinate system of the primary screen.
82+ * <p>
83+ *
84+ * @throws AWTException if the platform configuration does not allow
85+ * low-level input control. This exception is always thrown when
86+ * GraphicsEnvironment.isHeadless() returns true
87+ * @throws SecurityException if <code>createRobot</code> permission is not granted
88+ * @see java.awt.GraphicsEnvironment#isHeadless
89+ * @see SecurityManager#checkPermission
90+ * @see AWTPermission
91+ */
92+ public Robot() throws AWTException {
93+ if (GraphicsEnvironment.isHeadless()) {
94+ throw new AWTException("headless environment");
95+ }
96+ init(GraphicsEnvironment.getLocalGraphicsEnvironment()
97+ .getDefaultScreenDevice());
98+ }
99+
100+ /**
101+ * Creates a Robot for the given screen device. Coordinates passed
102+ * to Robot method calls like mouseMove and createScreenCapture will
103+ * be interpreted as being in the same coordinate system as the
104+ * specified screen. Note that depending on the platform configuration,
105+ * multiple screens may either:
106+ * <ul>
107+ * <li>share the same coordinate system to form a combined virtual screen</li>
108+ * <li>use different coordinate systems to act as independent screens</li>
109+ * </ul>
110+ * This constructor is meant for the latter case.
111+ * <p>
112+ * If screen devices are reconfigured such that the coordinate system is
113+ * affected, the behavior of existing Robot objects is undefined.
114+ *
115+ * @param screen A screen GraphicsDevice indicating the coordinate
116+ * system the Robot will operate in.
117+ * @throws AWTException if the platform configuration does not allow
118+ * low-level input control. This exception is always thrown when
119+ * GraphicsEnvironment.isHeadless() returns true.
120+ * @throws IllegalArgumentException if <code>screen</code> is not a screen
121+ * GraphicsDevice.
122+ * @throws SecurityException if <code>createRobot</code> permission is not granted
123+ * @see java.awt.GraphicsEnvironment#isHeadless
124+ * @see GraphicsDevice
125+ * @see SecurityManager#checkPermission
126+ * @see AWTPermission
127+ */
128+ public Robot(GraphicsDevice screen) throws AWTException {
129+ checkIsScreenDevice(screen);
130+ init(screen);
131+ }
132+
133+ private void init(GraphicsDevice screen) throws AWTException {
134+ checkRobotAllowed();
135+ gdLoc = screen.getDefaultConfiguration().getBounds().getLocation();
136+ Toolkit toolkit = Toolkit.getDefaultToolkit();
137+ if (toolkit instanceof ComponentFactory) {
138+ peer = ((ComponentFactory)toolkit).createRobot(this, screen);
139+ disposer = new RobotDisposer(peer);
140+ sun.java2d.Disposer.addRecord(anchor, disposer);
141+ }
142+ initLegalButtonMask();
143+ }
144+
145+ private static synchronized void initLegalButtonMask() {
146+ if (LEGAL_BUTTON_MASK != 0) return;
147+
148+ int tmpMask = 0;
149+ if (Toolkit.getDefaultToolkit().areExtraMouseButtonsEnabled()){
150+ if (Toolkit.getDefaultToolkit() instanceof SunToolkit) {
151+ final int buttonsNumber = ((SunToolkit)(Toolkit.getDefaultToolkit())).getNumberOfButtons();
152+ for (int i = 0; i < buttonsNumber; i++){
153+ tmpMask |= InputEvent.getMaskForButton(i+1);
154+ }
155+ }
156+ }
157+ tmpMask |= InputEvent.BUTTON1_MASK|
158+ InputEvent.BUTTON2_MASK|
159+ InputEvent.BUTTON3_MASK|
160+ InputEvent.BUTTON1_DOWN_MASK|
161+ InputEvent.BUTTON2_DOWN_MASK|
162+ InputEvent.BUTTON3_DOWN_MASK;
163+ LEGAL_BUTTON_MASK = tmpMask;
164+ }
165+
166+ /* determine if the security policy allows Robot's to be created */
167+ private void checkRobotAllowed() {
168+ SecurityManager security = System.getSecurityManager();
169+ if (security != null) {
170+ security.checkPermission(SecurityConstants.AWT.CREATE_ROBOT_PERMISSION);
171+ }
172+ }
173+
174+ /* check if the given device is a screen device */
175+ private void checkIsScreenDevice(GraphicsDevice device) {
176+ if (device == null || device.getType() != GraphicsDevice.TYPE_RASTER_SCREEN) {
177+ throw new IllegalArgumentException("not a valid screen device");
178+ }
179+ }
180+
181+ private transient Object anchor = new Object();
182+
183+ static class RobotDisposer implements sun.java2d.DisposerRecord {
184+ private final RobotPeer peer;
185+ public RobotDisposer(RobotPeer peer) {
186+ this.peer = peer;
187+ }
188+ public void dispose() {
189+ if (peer != null) {
190+ peer.dispose();
191+ }
192+ }
193+ }
194+
195+ private transient RobotDisposer disposer;
196+
197+ /**
198+ * Moves mouse pointer to given screen coordinates.
199+ * @param x X position
200+ * @param y Y position
201+ */
202+ public synchronized void mouseMove(int x, int y) {
203+ peer.mouseMove(gdLoc.x + x, gdLoc.y + y);
204+ afterEvent();
205+ }
206+
207+ /**
208+ * Presses one or more mouse buttons. The mouse buttons should
209+ * be released using the {@link #mouseRelease(int)} method.
210+ *
211+ * @param buttons the Button mask; a combination of one or more
212+ * mouse button masks.
213+ * <p>
214+ * It is allowed to use only a combination of valid values as a {@code buttons} parameter.
215+ * A valid combination consists of {@code InputEvent.BUTTON1_DOWN_MASK},
216+ * {@code InputEvent.BUTTON2_DOWN_MASK}, {@code InputEvent.BUTTON3_DOWN_MASK}
217+ * and values returned by the
218+ * {@link InputEvent#getMaskForButton(int) InputEvent.getMaskForButton(button)} method.
219+ *
220+ * The valid combination also depends on a
221+ * {@link Toolkit#areExtraMouseButtonsEnabled() Toolkit.areExtraMouseButtonsEnabled()} value as follows:
222+ * <ul>
223+ * <li> If support for extended mouse buttons is
224+ * {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java
225+ * then it is allowed to use only the following standard button masks:
226+ * {@code InputEvent.BUTTON1_DOWN_MASK}, {@code InputEvent.BUTTON2_DOWN_MASK},
227+ * {@code InputEvent.BUTTON3_DOWN_MASK}.
228+ * <li> If support for extended mouse buttons is
229+ * {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java
230+ * then it is allowed to use the standard button masks
231+ * and masks for existing extended mouse buttons, if the mouse has more then three buttons.
232+ * In that way, it is allowed to use the button masks corresponding to the buttons
233+ * in the range from 1 to {@link java.awt.MouseInfo#getNumberOfButtons() MouseInfo.getNumberOfButtons()}.
234+ * <br>
235+ * It is recommended to use the {@link InputEvent#getMaskForButton(int) InputEvent.getMaskForButton(button)}
236+ * method to obtain the mask for any mouse button by its number.
237+ * </ul>
238+ * <p>
239+ * The following standard button masks are also accepted:
240+ * <ul>
241+ * <li>{@code InputEvent.BUTTON1_MASK}
242+ * <li>{@code InputEvent.BUTTON2_MASK}
243+ * <li>{@code InputEvent.BUTTON3_MASK}
244+ * </ul>
245+ * However, it is recommended to use {@code InputEvent.BUTTON1_DOWN_MASK},
246+ * {@code InputEvent.BUTTON2_DOWN_MASK}, {@code InputEvent.BUTTON3_DOWN_MASK} instead.
247+ * Either extended {@code _DOWN_MASK} or old {@code _MASK} values
248+ * should be used, but both those models should not be mixed.
249+ * @throws IllegalArgumentException if the {@code buttons} mask contains the mask for extra mouse button
250+ * and support for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java
251+ * @throws IllegalArgumentException if the {@code buttons} mask contains the mask for extra mouse button
252+ * that does not exist on the mouse and support for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java
253+ * @see #mouseRelease(int)
254+ * @see InputEvent#getMaskForButton(int)
255+ * @see Toolkit#areExtraMouseButtonsEnabled()
256+ * @see java.awt.MouseInfo#getNumberOfButtons()
257+ * @see java.awt.event.MouseEvent
258+ */
259+ public synchronized void mousePress(int buttons) {
260+ checkButtonsArgument(buttons);
261+ peer.mousePress(buttons);
262+ afterEvent();
263+ }
264+
265+ /**
266+ * Releases one or more mouse buttons.
267+ *
268+ * @param buttons the Button mask; a combination of one or more
269+ * mouse button masks.
270+ * <p>
271+ * It is allowed to use only a combination of valid values as a {@code buttons} parameter.
272+ * A valid combination consists of {@code InputEvent.BUTTON1_DOWN_MASK},
273+ * {@code InputEvent.BUTTON2_DOWN_MASK}, {@code InputEvent.BUTTON3_DOWN_MASK}
274+ * and values returned by the
275+ * {@link InputEvent#getMaskForButton(int) InputEvent.getMaskForButton(button)} method.
276+ *
277+ * The valid combination also depends on a
278+ * {@link Toolkit#areExtraMouseButtonsEnabled() Toolkit.areExtraMouseButtonsEnabled()} value as follows:
279+ * <ul>
280+ * <li> If the support for extended mouse buttons is
281+ * {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java
282+ * then it is allowed to use only the following standard button masks:
283+ * {@code InputEvent.BUTTON1_DOWN_MASK}, {@code InputEvent.BUTTON2_DOWN_MASK},
284+ * {@code InputEvent.BUTTON3_DOWN_MASK}.
285+ * <li> If the support for extended mouse buttons is
286+ * {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java
287+ * then it is allowed to use the standard button masks
288+ * and masks for existing extended mouse buttons, if the mouse has more then three buttons.
289+ * In that way, it is allowed to use the button masks corresponding to the buttons
290+ * in the range from 1 to {@link java.awt.MouseInfo#getNumberOfButtons() MouseInfo.getNumberOfButtons()}.
291+ * <br>
292+ * It is recommended to use the {@link InputEvent#getMaskForButton(int) InputEvent.getMaskForButton(button)}
293+ * method to obtain the mask for any mouse button by its number.
294+ * </ul>
295+ * <p>
296+ * The following standard button masks are also accepted:
297+ * <ul>
298+ * <li>{@code InputEvent.BUTTON1_MASK}
299+ * <li>{@code InputEvent.BUTTON2_MASK}
300+ * <li>{@code InputEvent.BUTTON3_MASK}
301+ * </ul>
302+ * However, it is recommended to use {@code InputEvent.BUTTON1_DOWN_MASK},
303+ * {@code InputEvent.BUTTON2_DOWN_MASK}, {@code InputEvent.BUTTON3_DOWN_MASK} instead.
304+ * Either extended {@code _DOWN_MASK} or old {@code _MASK} values
305+ * should be used, but both those models should not be mixed.
306+ * @throws IllegalArgumentException if the {@code buttons} mask contains the mask for extra mouse button
307+ * and support for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() disabled} by Java
308+ * @throws IllegalArgumentException if the {@code buttons} mask contains the mask for extra mouse button
309+ * that does not exist on the mouse and support for extended mouse buttons is {@link Toolkit#areExtraMouseButtonsEnabled() enabled} by Java
310+ * @see #mousePress(int)
311+ * @see InputEvent#getMaskForButton(int)
312+ * @see Toolkit#areExtraMouseButtonsEnabled()
313+ * @see java.awt.MouseInfo#getNumberOfButtons()
314+ * @see java.awt.event.MouseEvent
315+ */
316+ public synchronized void mouseRelease(int buttons) {
317+ checkButtonsArgument(buttons);
318+ peer.mouseRelease(buttons);
319+ afterEvent();
320+ }
321+
322+ private void checkButtonsArgument(int buttons) {
323+ if ( (buttons|LEGAL_BUTTON_MASK) != LEGAL_BUTTON_MASK ) {
324+ throw new IllegalArgumentException("Invalid combination of button flags");
325+ }
326+ }
327+
328+ /**
329+ * Rotates the scroll wheel on wheel-equipped mice.
330+ *
331+ * @param wheelAmt number of "notches" to move the mouse wheel
332+ * Negative values indicate movement up/away from the user,
333+ * positive values indicate movement down/towards the user.
334+ *
335+ * @since 1.4
336+ */
337+ public synchronized void mouseWheel(int wheelAmt) {
338+ peer.mouseWheel(wheelAmt);
339+ afterEvent();
340+ }
341+
342+ /**
343+ * Presses a given key. The key should be released using the
344+ * <code>keyRelease</code> method.
345+ * <p>
346+ * Key codes that have more than one physical key associated with them
347+ * (e.g. <code>KeyEvent.VK_SHIFT</code> could mean either the
348+ * left or right shift key) will map to the left key.
349+ *
350+ * @param keycode Key to press (e.g. <code>KeyEvent.VK_A</code>)
351+ * @throws IllegalArgumentException if <code>keycode</code> is not
352+ * a valid key
353+ * @see #keyRelease(int)
354+ * @see java.awt.event.KeyEvent
355+ */
356+ public synchronized void keyPress(int keycode) {
357+ checkKeycodeArgument(keycode);
358+ peer.keyPress(keycode);
359+ afterEvent();
360+ }
361+
362+ /**
363+ * Releases a given key.
364+ * <p>
365+ * Key codes that have more than one physical key associated with them
366+ * (e.g. <code>KeyEvent.VK_SHIFT</code> could mean either the
367+ * left or right shift key) will map to the left key.
368+ *
369+ * @param keycode Key to release (e.g. <code>KeyEvent.VK_A</code>)
370+ * @throws IllegalArgumentException if <code>keycode</code> is not a
371+ * valid key
372+ * @see #keyPress(int)
373+ * @see java.awt.event.KeyEvent
374+ */
375+ public synchronized void keyRelease(int keycode) {
376+ checkKeycodeArgument(keycode);
377+ peer.keyRelease(keycode);
378+ afterEvent();
379+ }
380+
381+ private void checkKeycodeArgument(int keycode) {
382+ // rather than build a big table or switch statement here, we'll
383+ // just check that the key isn't VK_UNDEFINED and assume that the
384+ // peer implementations will throw an exception for other bogus
385+ // values e.g. -1, 999999
386+ if (keycode == KeyEvent.VK_UNDEFINED) {
387+ throw new IllegalArgumentException("Invalid key code");
388+ }
389+ }
390+
391+ /**
392+ * Returns the color of a pixel at the given screen coordinates.
393+ * @param x X position of pixel
394+ * @param y Y position of pixel
395+ * @return Color of the pixel
396+ */
397+ public synchronized Color getPixelColor(int x, int y) {
398+ Color color = new Color(peer.getRGBPixel(gdLoc.x + x, gdLoc.y + y));
399+ return color;
400+ }
401+
402+ /**
403+ * Creates an image containing pixels read from the screen. This image does
404+ * not include the mouse cursor.
405+ * @param screenRect Rect to capture in screen coordinates
406+ * @return The captured image
407+ * @throws IllegalArgumentException if <code>screenRect</code> width and height are not greater than zero
408+ * @throws SecurityException if <code>readDisplayPixels</code> permission is not granted
409+ * @see SecurityManager#checkPermission
410+ * @see AWTPermission
411+ */
412+ public synchronized BufferedImage createScreenCapture(Rectangle screenRect) {
413+ checkScreenCaptureAllowed();
414+
415+ // according to the spec, screenRect is relative to robot's GD
416+ Rectangle translatedRect = new Rectangle(screenRect);
417+ translatedRect.translate(gdLoc.x, gdLoc.y);
418+ checkValidRect(translatedRect);
419+
420+ BufferedImage image;
421+ DataBufferInt buffer;
422+ WritableRaster raster;
423+
424+ if (screenCapCM == null) {
425+ /*
426+ * Fix for 4285201
427+ * Create a DirectColorModel equivalent to the default RGB ColorModel,
428+ * except with no Alpha component.
429+ */
430+
431+ screenCapCM = new DirectColorModel(24,
432+ /* red mask */ 0x00FF0000,
433+ /* green mask */ 0x0000FF00,
434+ /* blue mask */ 0x000000FF);
435+ }
436+
437+ // need to sync the toolkit prior to grabbing the pixels since in some
438+ // cases rendering to the screen may be delayed
439+ Toolkit.getDefaultToolkit().sync();
440+
441+ int pixels[];
442+ int[] bandmasks = new int[3];
443+
444+ pixels = peer.getRGBPixels(translatedRect);
445+ buffer = new DataBufferInt(pixels, pixels.length);
446+
447+ bandmasks[0] = screenCapCM.getRedMask();
448+ bandmasks[1] = screenCapCM.getGreenMask();
449+ bandmasks[2] = screenCapCM.getBlueMask();
450+
451+ raster = Raster.createPackedRaster(buffer, translatedRect.width, translatedRect.height, translatedRect.width, bandmasks, null);
452+ SunWritableRaster.makeTrackable(buffer);
453+
454+ image = new BufferedImage(screenCapCM, raster, false, null);
455+
456+ return image;
457+ }
458+
459+ private static void checkValidRect(Rectangle rect) {
460+ if (rect.width <= 0 || rect.height <= 0) {
461+ throw new IllegalArgumentException("Rectangle width and height must be > 0");
462+ }
463+ }
464+
465+ private static void checkScreenCaptureAllowed() {
466+ SecurityManager security = System.getSecurityManager();
467+ if (security != null) {
468+ security.checkPermission(
469+ SecurityConstants.AWT.READ_DISPLAY_PIXELS_PERMISSION);
470+ }
471+ }
472+
473+ /*
474+ * Called after an event is generated
475+ */
476+ private void afterEvent() {
477+ autoWaitForIdle();
478+ autoDelay();
479+ }
480+
481+ /**
482+ * Returns whether this Robot automatically invokes <code>waitForIdle</code>
483+ * after generating an event.
484+ * @return Whether <code>waitForIdle</code> is automatically called
485+ */
486+ public synchronized boolean isAutoWaitForIdle() {
487+ return isAutoWaitForIdle;
488+ }
489+
490+ /**
491+ * Sets whether this Robot automatically invokes <code>waitForIdle</code>
492+ * after generating an event.
493+ * @param isOn Whether <code>waitForIdle</code> is automatically invoked
494+ */
495+ public synchronized void setAutoWaitForIdle(boolean isOn) {
496+ isAutoWaitForIdle = isOn;
497+ }
498+
499+ /*
500+ * Calls waitForIdle after every event if so desired.
501+ */
502+ private void autoWaitForIdle() {
503+ if (isAutoWaitForIdle) {
504+ waitForIdle();
505+ }
506+ }
507+
508+ /**
509+ * Returns the number of milliseconds this Robot sleeps after generating an event.
510+ */
511+ public synchronized int getAutoDelay() {
512+ return autoDelay;
513+ }
514+
515+ /**
516+ * Sets the number of milliseconds this Robot sleeps after generating an event.
517+ * @throws IllegalArgumentException If <code>ms</code> is not between 0 and 60,000 milliseconds inclusive
518+ */
519+ public synchronized void setAutoDelay(int ms) {
520+ checkDelayArgument(ms);
521+ autoDelay = ms;
522+ }
523+
524+ /*
525+ * Automatically sleeps for the specified interval after event generated.
526+ */
527+ private void autoDelay() {
528+ delay(autoDelay);
529+ }
530+
531+ /**
532+ * Sleeps for the specified time.
533+ * To catch any <code>InterruptedException</code>s that occur,
534+ * <code>Thread.sleep()</code> may be used instead.
535+ * @param ms time to sleep in milliseconds
536+ * @throws IllegalArgumentException if <code>ms</code> is not between 0 and 60,000 milliseconds inclusive
537+ * @see java.lang.Thread#sleep
538+ */
539+ public synchronized void delay(int ms) {
540+ checkDelayArgument(ms);
541+ try {
542+ Thread.sleep(ms);
543+ } catch(InterruptedException ite) {
544+ ite.printStackTrace();
545+ }
546+ }
547+
548+ private void checkDelayArgument(int ms) {
549+ if (ms < 0 || ms > MAX_DELAY) {
550+ throw new IllegalArgumentException("Delay must be to 0 to 60,000ms");
551+ }
552+ }
553+
554+ /**
555+ * Waits until all events currently on the event queue have been processed.
556+ * @throws IllegalThreadStateException if called on the AWT event dispatching thread
557+ */
558+ public synchronized void waitForIdle() {
559+ checkNotDispatchThread();
560+ // post a dummy event to the queue so we know when
561+ // all the events before it have been processed
562+ try {
563+ SunToolkit.flushPendingEvents();
564+ EventQueue.invokeAndWait( new Runnable() {
565+ public void run() {
566+ // dummy implementation
567+ }
568+ } );
569+ } catch(InterruptedException ite) {
570+ System.err.println("Robot.waitForIdle, non-fatal exception caught:");
571+ ite.printStackTrace();
572+ } catch(InvocationTargetException ine) {
573+ System.err.println("Robot.waitForIdle, non-fatal exception caught:");
574+ ine.printStackTrace();
575+ }
576+ }
577+
578+ private void checkNotDispatchThread() {
579+ if (EventQueue.isDispatchThread()) {
580+ throw new IllegalThreadStateException("Cannot call method from the event dispatcher thread");
581+ }
582+ }
583+
584+ /**
585+ * Returns a string representation of this Robot.
586+ *
587+ * @return the string representation.
588+ */
589+ public synchronized String toString() {
590+ String params = "autoDelay = "+getAutoDelay()+", "+"autoWaitForIdle = "+isAutoWaitForIdle();
591+ return getClass().getName() + "[ " + params + " ]";
592+ }
593+}