JOGL v2.6.0-rc-20250712
JOGL, High-Performance Graphics Binding for Java™ (public API).
AWTRobotUtil.java
Go to the documentation of this file.
1/**
2 * Copyright 2010 JogAmp Community. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification, are
5 * permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * The views and conclusions contained in the software and documentation are those of the
25 * authors and should not be interpreted as representing official policies, either expressed
26 * or implied, of JogAmp Community.
27 */
28
29package com.jogamp.opengl.test.junit.util;
30
31import jogamp.newt.awt.event.AWTNewtEventFactory;
32
33import java.lang.Thread.UncaughtExceptionHandler;
34import java.lang.reflect.InvocationTargetException;
35import java.util.concurrent.atomic.AtomicInteger;
36import java.awt.AWTException;
37import java.awt.EventQueue;
38import java.awt.MouseInfo;
39import java.awt.Point;
40import java.awt.Robot;
41
42import com.jogamp.nativewindow.NativeWindow;
43import com.jogamp.nativewindow.NativeWindowFactory;
44import com.jogamp.opengl.GLAutoDrawable;
45
46import org.junit.Assert;
47
48import com.jogamp.common.ExceptionUtils;
49import com.jogamp.common.util.awt.AWTEDTExecutor;
50
51public class AWTRobotUtil extends TestUtil {
52
53 static final boolean DEBUG = false;
54
55 public static final int ROBOT_DELAY = 100; // ms
56 public static Integer AWT_CLICK_TO = null;
57
58 static class OurUncaughtExceptionHandler implements UncaughtExceptionHandler {
59 @Override
60 public void uncaughtException(final Thread t, final Throwable e) {
61 System.err.println("*** AWTRobotUtil: UncaughtException (this Thread "+Thread.currentThread().getName()+") : Thread <"+t.getName()+">, "+e.getClass().getName()+": "+e.getMessage());
62 e.printStackTrace();
63 }
64 }
65
66 static {
67 Thread.setDefaultUncaughtExceptionHandler( new OurUncaughtExceptionHandler() );
68 // System.err.println("AWT EDT alive: "+isAWTEDTAlive());
69 }
70
71 /** Probes whether AWT's EDT is alive or not. */
72 public static boolean isAWTEDTAlive() {
73 if( EventQueue.isDispatchThread() ) {
74 return true;
75 }
76 synchronized ( awtEDTAliveSync ) {
77 awtEDTAliveFlag = false;
78 EventQueue.invokeLater(aliveRun);
79 for (int wait=0; wait<POLL_DIVIDER && !awtEDTAliveFlag; wait++) {
80 try {
81 Thread.sleep(TIME_SLICE);
82 } catch (final InterruptedException e) {
83 e.printStackTrace();
84 }
85 }
86 return awtEDTAliveFlag;
87 }
88 }
89 private static Runnable aliveRun = new Runnable() {
90 @Override
91 public void run() {
92 awtEDTAliveFlag = true;
93 } };
94 private static Object awtEDTAliveSync = new Object();
95 private static volatile boolean awtEDTAliveFlag = false;
96
97 /** Throws Error if {@link #isAWTEDTAlive()} returns false. */
98 public static void validateAWTEDTIsAlive() {
99 if( !isAWTEDTAlive() ) {
100 throw new Error("AWT EDT not alive");
101 }
102 }
103
104 /** Issuing {@link #validateAWTEDTIsAlive()} before calling {@link Robot#waitForIdle()}. */
105 public static void waitForIdle(final Robot robot) {
107 robot.waitForIdle();
108 }
109
110 public static void clearAWTFocus(Robot robot) throws InterruptedException, InvocationTargetException, AWTException {
111 if(null == robot) {
112 robot = new Robot();
113 robot.setAutoWaitForIdle(true);
114 }
115 javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
116 @Override
117 public void run() {
118 System.err.println("******** clearAWTFocus.0");
119 java.awt.KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
120 }});
121 robot.delay(ROBOT_DELAY);
122 System.err.println("******** clearAWTFocus.X");
123 }
124
125 // FIXME: AWTRobotUtil Cleanup: Use specific type for argument object
126 public static int[] getCenterLocation(final Object obj, final boolean onTitleBarIfWindow)
127 throws InterruptedException, InvocationTargetException {
128 if(obj instanceof com.jogamp.newt.Window) {
129 return getCenterLocationNEWT((com.jogamp.newt.Window)obj, onTitleBarIfWindow);
130 } else if(NativeWindowFactory.isAWTAvailable() && obj instanceof java.awt.Component) {
131 return getCenterLocationAWT((java.awt.Component)obj, onTitleBarIfWindow);
132 } else {
133 throw new RuntimeException("Neither AWT nor NEWT: "+obj);
134 }
135 }
136 private static int[] getCenterLocationNEWT(final com.jogamp.newt.Window win, final boolean onTitleBarIfWindow)
137 throws InterruptedException, InvocationTargetException {
138
139 final com.jogamp.nativewindow.util.Point p0 = win.getLocationOnScreen(null);
140 if( onTitleBarIfWindow ) {
141 final com.jogamp.nativewindow.util.InsetsImmutable insets = win.getInsets();
142 p0.translate(win.getWidth()/2, insets.getTopHeight()/2);
143 } else {
144 p0.translate(win.getWidth()/2, win.getHeight()/2);
145 }
146 return new int[] { p0.getX(), p0.getY() };
147 }
148 private static int[] getCenterLocationAWT(final java.awt.Component comp, final boolean onTitleBarIfWindow)
149 throws InterruptedException, InvocationTargetException {
150 int x0, y0;
151 final java.awt.Point p0 = comp.getLocationOnScreen();
152 final java.awt.Rectangle r0 = comp.getBounds();
153 if( onTitleBarIfWindow && comp instanceof java.awt.Window) {
154 final java.awt.Window window = (java.awt.Window) comp;
155 final java.awt.Insets insets = window.getInsets();
156 y0 = (int) ( p0.getY() + insets.top / 2.0 + .5 ) ;
157 } else {
158 y0 = (int) ( p0.getY() + r0.getHeight() / 2.0 + .5 ) ;
159 }
160 x0 = (int) ( p0.getX() + r0.getWidth() / 2.0 + .5 ) ;
161 return new int[] { x0, y0 };
162 }
163
164 // FIXME: AWTRobotUtil Cleanup: Use specific type for argument object
165 public static int[] getClientLocation(final Object obj, final int x, final int y)
166 throws InterruptedException, InvocationTargetException {
167 if(obj instanceof com.jogamp.newt.Window) {
168 return getClientLocationNEWT((com.jogamp.newt.Window)obj, x, y);
169 } else if(NativeWindowFactory.isAWTAvailable() && obj instanceof java.awt.Component) {
170 return getClientLocationAWT((java.awt.Component)obj, x, y);
171 } else {
172 throw new RuntimeException("Neither AWT nor NEWT: "+obj);
173 }
174 }
175 private static int[] getClientLocationNEWT(final com.jogamp.newt.Window win, final int x, final int y)
176 throws InterruptedException, InvocationTargetException {
177 final com.jogamp.nativewindow.util.Point p0 = win.getLocationOnScreen(null);
178 return new int[] { p0.getX(), p0.getY() };
179 }
180 private static int[] getClientLocationAWT(final java.awt.Component comp, final int x, final int y)
181 throws InterruptedException, InvocationTargetException {
182 final java.awt.Point p0 = comp.getLocationOnScreen();
183 return new int[] { (int)p0.getX(), (int)p0.getY() };
184 }
185
186 public static void awtRobotMouseMove(final Robot robot, final int x, final int y) {
187 robot.mouseMove( x, y );
188 robot.delay(ROBOT_DELAY);
189 }
190
191 /**
192 * toFront, call setVisible(true) and toFront(),
193 * after positioning the mouse in the middle of the window via robot.
194 * If the given robot is null, a new one is created (waitForIdle=true).
195 *
196 * @return True if the Window became the global focused Window within TIME_OUT
197 */
198 public static boolean toFrontAndRequestFocus(Robot robot, final java.awt.Window window)
199 throws AWTException, InterruptedException, InvocationTargetException {
200
201 // just for event tracing ..
202 final AWTWindowFocusAdapter winFA = new AWTWindowFocusAdapter("window");
203 window.addWindowFocusListener(winFA);
204
205 if(null == robot) {
206 robot = new Robot();
207 robot.setAutoWaitForIdle(true);
208 }
209 final int[] p0 = getCenterLocation(window, false);
210 System.err.println("toFront: robot pos: "+p0[0]+"/"+p0[1]);
211 awtRobotMouseMove(robot, p0[0], p0[1] );
212
213 int wait=0;
214 do {
215 final int _wait = wait;
216 javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
217 @Override
218 public void run() {
219 if(0==_wait) {
220 window.setVisible(true);
221 window.toFront();
222 }
223 window.requestFocus();
224 }});
225 Thread.sleep(TIME_SLICE);
226 wait++;
227 } while (wait<POLL_DIVIDER && !window.hasFocus());
228 final boolean success = wait<POLL_DIVIDER;
229
230 window.removeWindowFocusListener(winFA);
231 if(!success) {
232 System.err.println("*** AWTRobotUtil.toFrontAndRequestFocus() UI failure");
233 System.err.println("*** window: "+window);
234 System.err.println("*** window.hasFocus(): "+window.hasFocus());
235 ExceptionUtils.dumpStack(System.err);
236 }
237 return success;
238 }
239
240 /**
241 * centerMouse
242 * FIXME: AWTRobotUtil Cleanup: Use specific type for argument object
243 * @param onTitleBarIfWindow TODO
244 */
245 public static void centerMouse(Robot robot, final Object obj, final boolean onTitleBarIfWindow)
246 throws AWTException, InterruptedException, InvocationTargetException {
247
248 if(null == robot) {
249 robot = new Robot();
250 robot.setAutoWaitForIdle(true);
251 }
252
253 final int[] p0 = getCenterLocation(obj, onTitleBarIfWindow);
254 System.err.println("centerMouse: robot pos: "+p0[0]+"x"+p0[1]+", onTitleBarIfWindow: "+onTitleBarIfWindow);
255 awtRobotMouseMove(robot, p0[0], p0[1] );
256 }
257
258 // FIXME: AWTRobotUtil Cleanup: Use specific type for argument object
259 public static void setMouseToClientLocation(Robot robot, final Object obj, final int x, final int y)
260 throws AWTException, InterruptedException, InvocationTargetException {
261
262 if(null == robot) {
263 robot = new Robot();
264 robot.setAutoWaitForIdle(true);
265 }
266
267 final int[] p0 = getClientLocation(obj, x, y);
268 awtRobotMouseMove(robot, p0[0], p0[1] );
269 }
270
271 private static int getAWTClickTimeout() {
272 if(null == AWT_CLICK_TO) {
274 (Integer) java.awt.Toolkit.getDefaultToolkit().getDesktopProperty("awt.multiClickInterval");
275 if(null == AWT_CLICK_TO) {
276 AWT_CLICK_TO = new Integer(500);
277 }
278 }
279 return AWT_CLICK_TO.intValue();
280 }
281 // FIXME: AWTRobotUtil Cleanup: Use specific type for argument object
282 public static int getClickTimeout(final Object obj) {
283 if(obj instanceof com.jogamp.newt.Window) {
284 final int newt_to = com.jogamp.newt.event.MouseEvent.getClickTimeout();
285 final int awt_to = getAWTClickTimeout();
286 return Math.max(awt_to, newt_to);
287 } else if(NativeWindowFactory.isAWTAvailable() && obj instanceof java.awt.Component) {
288 return getAWTClickTimeout();
289 } else {
290 throw new RuntimeException("Neither AWT nor NEWT: "+obj);
291 }
292 }
293
294 /**
295 * FIXME: AWTRobotUtil Cleanup: Use specific type for argument object
296 *
297 * requestFocus, if robot is valid, use mouse operation,
298 * otherwise programmatic, ie call requestFocus
299 */
300 public static void requestFocus(final Robot robot, final Object obj)
301 throws AWTException, InterruptedException, InvocationTargetException {
302 requestFocus(robot, obj, true);
303 }
304
305 /**
306 * FIXME: AWTRobotUtil Cleanup: Use specific type for argument object
307 *
308 * requestFocus, if robot is valid, use mouse operation,
309 * otherwise programmatic, ie call requestFocus
310 */
311 public static void requestFocus(final Robot robot, final Object obj, final boolean onTitleBarIfWindow)
312 throws AWTException, InterruptedException, InvocationTargetException {
313 if(null != robot) {
314 final int mouseButton = java.awt.event.InputEvent.BUTTON1_MASK;
315 centerMouse(robot, obj, onTitleBarIfWindow);
316
317 waitForIdle(robot);
318 robot.mousePress(mouseButton);
319 robot.mouseRelease(mouseButton);
320 final int d = getClickTimeout(obj) + 1;
321 robot.delay( d );
322 System.err.println("requestFocus: click, d: "+d+" ms");
323 } else {
324 if(obj instanceof com.jogamp.newt.Window) {
325 requestFocusNEWT((com.jogamp.newt.Window) obj, onTitleBarIfWindow);
326 } else if(NativeWindowFactory.isAWTAvailable() && obj instanceof java.awt.Component) {
327 requestFocusAWT((java.awt.Component) obj, onTitleBarIfWindow);
328 } else {
329 throw new RuntimeException("Neither AWT nor NEWT: "+obj);
330 }
331 }
332 }
333 private static void requestFocusNEWT(final com.jogamp.newt.Window win, final boolean onTitleBarIfWindow)
334 throws AWTException, InterruptedException, InvocationTargetException {
335 win.requestFocus();
336 System.err.println("requestFocus: NEWT Component");
337 }
338 private static void requestFocusAWT(final java.awt.Component comp, final boolean onTitleBarIfWindow)
339 throws AWTException, InterruptedException, InvocationTargetException {
340 javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
341 @Override
342 public void run() {
343 comp.requestFocus();
344 System.err.println("requestFocus: AWT Component");
345 }});
346 }
347
348 // FIXME: AWTRobotUtil Cleanup: Use specific type for argument object
349 public static void requestFocus(final Robot robot, final Object obj, final int x, final int y)
350 throws AWTException, InterruptedException, InvocationTargetException {
352
353 final boolean idling = robot.isAutoWaitForIdle();
354 final int mouseButton = java.awt.event.InputEvent.BUTTON1_MASK;
355 robot.mouseMove( x, y );
356 if( idling ) {
357 robot.waitForIdle();
358 } else {
359 try { Thread.sleep(50); } catch (final InterruptedException e) { }
360 }
361 robot.mousePress(mouseButton);
362 robot.mouseRelease(mouseButton);
363 final int d = getClickTimeout(obj) + 1;
364 robot.delay( d );
365 }
366
367 // FIXME: AWTRobotUtil Cleanup: Use specific type for argument object
368 public static boolean hasFocus(final Object obj) {
369 if(obj instanceof com.jogamp.newt.Window) {
370 return ((com.jogamp.newt.Window) obj).hasFocus();
371 } else if(NativeWindowFactory.isAWTAvailable() && obj instanceof java.awt.Component) {
372 final java.awt.Component comp = (java.awt.Component) obj;
373 final java.awt.KeyboardFocusManager kfm = java.awt.KeyboardFocusManager.getCurrentKeyboardFocusManager();
374 return comp == kfm.getPermanentFocusOwner();
375 } else {
376 throw new RuntimeException("Neither AWT nor NEWT: "+obj);
377 }
378 }
379
380 /**
381 *
382 * @param waitAction if not null, Runnable shall wait {@link #TIME_SLICE} ms, if appropriate
383 * @return True if the Window became the global focused Window within TIME_OUT
384 */
385 public static boolean waitForFocus(final java.awt.Component comp, final Runnable waitAction) throws InterruptedException {
386 int wait;
387 final java.awt.KeyboardFocusManager kfm = java.awt.KeyboardFocusManager.getCurrentKeyboardFocusManager();
388 for (wait=0; wait<POLL_DIVIDER && comp != kfm.getPermanentFocusOwner(); wait++) {
389 if( null != waitAction ) {
390 waitAction.run();
391 } else {
392 Thread.sleep(TIME_SLICE);
393 }
394 }
395 return wait<POLL_DIVIDER;
396 }
397
398 /**
399 *
400 * @param waitAction if not null, Runnable shall wait {@link #TIME_SLICE} ms, if appropriate
401 * @return True if the Window became the global focused Window within TIME_OUT
402 */
403 public static boolean waitForFocus(final java.awt.Component comp, final FocusEventCountAdapter gain,
404 final FocusEventCountAdapter lost, final Runnable waitAction) throws InterruptedException {
405 if(!waitForFocus(comp, waitAction)) {
406 return false;
407 }
408 return TestUtil.waitForFocus(gain, lost, waitAction);
409 }
410
411 // FIXME: AWTRobotUtil Cleanup: Use specific type for argument object
412 public static void assertRequestFocusAndWait(final Robot robot, final Object requestFocus, final Object waitForFocus,
413 final FocusEventCountAdapter gain, final FocusEventCountAdapter lost)
414 throws AWTException, InterruptedException, InvocationTargetException {
415
416 int i = 0;
417 boolean hasFocus = false;
418
419 for(i=0; i < RETRY_NUMBER && !hasFocus; i++) {
421 if(waitForFocus instanceof com.jogamp.newt.Window) {
422 hasFocus = NewtTestUtil.waitForFocus((com.jogamp.newt.Window)waitForFocus, gain, lost, null);
423 } else if(NativeWindowFactory.isAWTAvailable() && waitForFocus instanceof java.awt.Component) {
424 hasFocus = waitForFocus((java.awt.Component)waitForFocus, gain, lost, null);
425 } else {
426 throw new RuntimeException("Neither AWT nor NEWT: "+waitForFocus);
427 }
428 }
429 if(!hasFocus) {
430 System.err.print("*** AWTRobotUtil.assertRequestFocusAndWait() ");
431 if( ( null == gain || gain.focusGained() ) && ( null == lost || !lost.focusLost() ) ) {
432 // be error tolerant here, some impl. may lack focus-lost events (OS X)
433 System.err.println("minor UI failure");
434 hasFocus = true;
435 } else {
436 System.err.println("major UI failure");
437 }
438 if(requestFocus instanceof NativeWindow) {
439 System.err.println("*** requestFocus.hasFocus() - NW: "+((NativeWindow)requestFocus).hasFocus());
440 } else if(NativeWindowFactory.isAWTAvailable() && requestFocus instanceof java.awt.Component) {
441 System.err.println("*** requestFocus.hasFocus() - AWT: "+((java.awt.Component)requestFocus).hasFocus());
442 }
443 if(waitForFocus instanceof NativeWindow) {
444 System.err.println("*** waitForFocus.hasFocus() - NW: "+((NativeWindow)waitForFocus).hasFocus());
445 } else if(NativeWindowFactory.isAWTAvailable() && waitForFocus instanceof java.awt.Component) {
446 System.err.println("*** waitForFocus.hasFocus() - AWT: "+((java.awt.Component)waitForFocus).hasFocus());
447 }
448 System.err.println("*** gain: "+gain);
449 System.err.println("*** lost: "+lost);
450 ExceptionUtils.dumpStack(System.err);
451 }
452 Assert.assertTrue("Did not gain focus", hasFocus);
453 }
454
455 private static void awtRobotKeyPress(final Robot robot, final int keyCode, final int msDelay) {
456 robot.keyPress(keyCode);
457 robot.delay(msDelay);
458 }
459 private static void awtRobotKeyRelease(final Robot robot, final int keyCode, final int msDelay) {
460 robot.keyRelease(keyCode);
461 robot.delay(msDelay);
462 }
463
464 // FIXME: AWTRobotUtil Cleanup: Use specific type for argument object
465 public static int keyType(final int i, final Robot robot, final int keyCode,
466 final Object obj, final KeyEventCountAdapter counter) throws InterruptedException, AWTException, InvocationTargetException
467 {
468 int tc = 0;
469 int j;
470 final long t0 = System.currentTimeMillis();
471 final int c0 = null!=counter ? counter.getCount() : 0;
472
473 for(j=0; 1 > tc && j<RETRY_NUMBER; j++) {
474 if(!hasFocus(obj)) {
475 // focus lost for some reason, regain it programmatic
476 if(DEBUG) { System.err.println(i+":"+j+" KC1.0: "+counter+" - regain focus on thread "+Thread.currentThread().getName()); }
477 requestFocus(null, obj);
478 }
479 waitForIdle(robot);
480 if(DEBUG) { System.err.println(i+":"+j+" KC1.1: "+counter+" on thread "+Thread.currentThread().getName()); }
481 awtRobotKeyPress(robot, keyCode, 50);
482 if(DEBUG) { System.err.println(i+":"+j+" KC1.2: "+counter+" on thread "+Thread.currentThread().getName()); }
483 awtRobotKeyRelease(robot, keyCode, 100);
484 waitForIdle(robot);
485 if(DEBUG) { System.err.println(i+":"+j+" KC1.3: "+counter); }
486 tc = ( null!=counter ? counter.getCount() : 1 ) - c0;
487 for (int wait=0; wait<POLL_DIVIDER && 1 > tc; wait++) {
488 if(DEBUG) { System.err.println(i+":"+j+" KC1.4."+wait+": "+counter+", sleep for "+TIME_OUT+"ms"); }
489 robot.delay(TIME_SLICE);
490 tc = counter.getCount() - c0;
491 }
492 if(DEBUG) { System.err.println(i+":"+j+" KC1.X: tc "+tc+", "+counter+" on thread "+Thread.currentThread().getName()); }
493 }
494 Assert.assertEquals("Key ("+i+":"+j+") not typed one time on thread "+Thread.currentThread().getName(), 1, tc);
495 return (int) ( System.currentTimeMillis() - t0 ) ;
496 }
497
498 /** No validation is performed .. */
499 public static int keyPress(final int i, final Robot robot, final boolean press, final int keyCode, final int msDelay) {
500 final long t0 = System.currentTimeMillis();
501 if(press) {
502 awtRobotKeyPress(robot, keyCode, msDelay);
503 } else {
504 awtRobotKeyRelease(robot, keyCode, msDelay);
505 }
506
507 return (int) ( System.currentTimeMillis() - t0 ) ;
508 }
509
510 /** No validation is performed .. */
511 public static int newtKeyPress(final int i, final Robot robot, final boolean press, final short newtKeyCode, final int msDelay) {
512 final int keyCode = AWTNewtEventFactory.newtKeyCode2AWTKeyCode(newtKeyCode);
513 final long t0 = System.currentTimeMillis();
514 if(press) {
515 awtRobotKeyPress(robot, keyCode, msDelay);
516 } else {
517 awtRobotKeyRelease(robot, keyCode, msDelay);
518 }
519
520 return (int) ( System.currentTimeMillis() - t0 ) ;
521 }
522
523 /**
524 * FIXME: AWTRobotUtil Cleanup: Use specific type for argument object
525 *
526 * @param keyCode TODO
527 * @param counter shall return the number of keys typed (press + release)
528 */
529 public static void assertKeyType(Robot robot, final int keyCode, final int typeCount,
530 final Object obj, final KeyEventCountAdapter counter)
531 throws AWTException, InterruptedException, InvocationTargetException {
532
533 if(null == robot) {
534 robot = new Robot();
535 robot.setAutoWaitForIdle(true);
536 }
537
538 centerMouse(robot, obj, false);
539
540 Assert.assertEquals("Key already pressed", false, counter.isPressed());
541
542 if(DEBUG) {
543 System.err.println("**************************************");
544 System.err.println("KC0: "+counter);
545 }
546
547 final int c0 = counter.getCount();
548
549 for(int i=0; i<typeCount; i++) {
550 keyType(i, robot, keyCode, obj, counter);
551 }
552
553 if(DEBUG) { System.err.println("KC3.0: "+counter); }
554 Assert.assertEquals("Wrong key count", typeCount, counter.getCount()-c0);
555 }
556
557 /**
558 * FIXME: AWTRobotUtil Cleanup: Use specific type for argument object
559 *
560 * @param keyCode TODO
561 * @param counter shall return the number of keys typed (press + release)
562 */
563 public static void assertKeyPress(Robot robot, final int keyCode, final int typeCount,
564 final Object obj, final KeyEventCountAdapter counter)
565 throws AWTException, InterruptedException, InvocationTargetException {
566
567 if(null == robot) {
568 robot = new Robot();
569 robot.setAutoWaitForIdle(true);
570 }
571
572 centerMouse(robot, obj, false);
573
574 Assert.assertEquals("Key already pressed", false, counter.isPressed());
575
576 if(DEBUG) {
577 System.err.println("**************************************");
578 System.err.println("KC0: "+counter);
579 }
580
581 final int c0 = counter.getCount();
582
583 for(int i=0; i<typeCount; i++) {
584 keyType(i, robot, keyCode, obj, counter);
585 }
586
587 if(DEBUG) { System.err.println("KC3.0: "+counter); }
588 Assert.assertEquals("Wrong key count", typeCount, counter.getCount()-c0);
589 }
590
591 public static void mouseMove(final Robot robot, final Point destination, final int iter, final int delay) {
592 final Point origin = MouseInfo.getPointerInfo().getLocation();
593 for (int i = 1; i <= iter; i++) {
594 final float alpha = i / (float) iter;
595 robot.mouseMove((int) (origin.x * (1 - alpha) + destination.x * alpha),
596 (int) (origin.y * (1 - alpha) + destination.y * alpha));
597 robot.delay(delay);
598 }
599 }
600 public static void mouseClick(final Robot robot, final Point pos, final int moveIter, final int moveDelay, final int actionDelay) {
601 robot.delay(actionDelay);
602 mouseMove(robot, pos, moveIter, moveDelay);
603
604 robot.delay(actionDelay);
605 robot.mousePress(java.awt.event.InputEvent.BUTTON1_MASK);
606 robot.mouseRelease(java.awt.event.InputEvent.BUTTON1_MASK);
607 robot.delay(actionDelay);
608 }
609
610 // FIXME: AWTRobotUtil Cleanup: Use specific type for argument object
611 static int mouseClick(final int i, final Robot robot, final int mouseButton,
612 final Object obj, final InputEventCountAdapter counter) throws InterruptedException, AWTException, InvocationTargetException
613 {
614 int j;
615 int tc = 0;
616 final long t0 = System.currentTimeMillis();
617
618 for(j=0; 1 > tc && j<RETRY_NUMBER; j++) {
619 if(!hasFocus(obj)) {
620 // focus lost for some reason, regain it programmatic
621 if(DEBUG) { System.err.println(i+":"+j+" MC1.0: "+counter+" - regain focus"); }
622 requestFocus(null, obj);
623 }
624 final int c0 = null != counter ? counter.getCount() : 0;
625 if(DEBUG) { System.err.println(i+":"+j+" MC1.1: "+counter); }
626 waitForIdle(robot);
627 robot.mousePress(mouseButton);
628 robot.mouseRelease(mouseButton);
629 if(DEBUG) { System.err.println(i+":"+j+" MC1.2: "+counter); }
630 tc = ( null != counter ? counter.getCount() : 1 ) - c0;
631 for (int wait=0; wait<POLL_DIVIDER && 1 > tc; wait++) {
632 robot.delay(TIME_SLICE);
633 tc = counter.getCount() - c0;
634 }
635 if(DEBUG) { System.err.println(i+":"+j+" MC1.X: tc "+tc+", "+counter); }
636 }
637 Assert.assertEquals("Mouse ("+i+":"+j+") not clicked one time", 1, tc);
638 return (int) ( System.currentTimeMillis() - t0 ) ;
639 }
640
641 /**
642 * FIXME: AWTRobotUtil Cleanup: Use specific type for argument object
643 *
644 * @param mouseButton ie InputEvent.BUTTON1_MASK
645 * @param clickCount ie 1, or 2
646 */
647 public static void assertMouseClick(Robot robot, final int mouseButton, final int clickCount,
648 final Object obj, final InputEventCountAdapter counter)
649 throws AWTException, InterruptedException, InvocationTargetException {
650
651 if(null == robot) {
652 robot = new Robot();
653 robot.setAutoWaitForIdle(true);
654 }
655
656 final int clickTO = getClickTimeout(obj);
657
658 centerMouse(robot, obj, false);
659
660 Assert.assertEquals("Mouse already pressed", false, counter.isPressed());
661
662 if(DEBUG) {
663 System.err.println("**************************************");
664 System.err.println("MC0: "+counter);
665 }
666
667 final int c0 = counter.getCount();
668
669 for(int i=0; i<clickCount; i++) {
670 final int waited = mouseClick(i, robot, mouseButton, obj, counter);
671 if(DEBUG) { System.err.println(i+": MC2.X: "+counter+", consumed: "+waited); }
672 robot.delay( clickTO + 1 );
673 }
674
675 if(DEBUG) { System.err.println("MC3.0: "+counter); }
676 Assert.assertEquals("Wrong mouse click count", clickCount, counter.getCount() - c0);
677 }
678
679 /**
680 *
681 * @param waitAction if not null, Runnable shall wait {@link #TIME_SLICE} ms, if appropriate
682 * @return True if the Component becomes <code>visible</code> within TIME_OUT
683 */
684 public static boolean waitForVisible(final java.awt.Component comp, final boolean visible, final Runnable waitAction) throws InterruptedException {
685 int wait;
686 for (wait=0; wait<POLL_DIVIDER && visible != comp.isShowing(); wait++) {
687 if( null != waitAction ) {
688 waitAction.run();
689 } else {
690 Thread.sleep(TIME_SLICE);
691 }
692 }
693 return wait<POLL_DIVIDER;
694 }
695
696 /**
697 * @param obj the component to wait for
698 * @param realized true if waiting for component to become realized, otherwise false
699 * @param waitAction if not null, Runnable shall wait {@link #TIME_SLICE} ms, if appropriate
700 * @return True if the Component becomes realized (not displayable, native invalid) within TIME_OUT
701 * @throws InterruptedException
702 */
703 public static boolean waitForRealized(final java.awt.Component comp, final boolean realized, final Runnable waitAction) throws InterruptedException {
704 long t0 = System.currentTimeMillis();
705 long t1 = t0;
706 while( (t1-t0) < TIME_OUT && realized != comp.isShowing() ) {
707 if( null != waitAction ) {
708 waitAction.run();
709 } else {
710 Thread.sleep(TIME_SLICE);
711 }
712 t1 = System.currentTimeMillis();
713 }
714 // if GLCanvas, ensure it got also painted -> drawable.setRealized(true);
715 if( (t1-t0) < TIME_OUT && comp instanceof GLAutoDrawable) {
716 final GLAutoDrawable glad = (GLAutoDrawable) comp;
717 t0 = System.currentTimeMillis();
718 while( (t1-t0) < TIME_OUT && realized != glad.isRealized() ) {
719 if( null != waitAction ) {
720 waitAction.run();
721 } else {
722 Thread.sleep(TIME_SLICE);
723 }
724 t1 = System.currentTimeMillis();
725 }
726 if( (t1-t0) >= TIME_OUT ) {
727 // for some reason GLCanvas hasn't been painted yet, force it!
728 System.err.println("XXX: FORCE REPAINT PRE - glad: "+glad);
729 comp.repaint();
730 t0 = System.currentTimeMillis();
731 while( (t1-t0) < TIME_OUT && realized != glad.isRealized() ) {
732 if( null != waitAction ) {
733 waitAction.run();
734 } else {
735 Thread.sleep(TIME_SLICE);
736 }
737 t1 = System.currentTimeMillis();
738 }
739 System.err.println("XXX: FORCE REPAINT POST - glad: "+glad);
740 }
741 }
742 return (t1-t0) < TIME_OUT;
743 }
744
745 /**
746 * Programmatically issue windowClosing on AWT or NEWT.
747 * Wait until the window is closing within TIME_OUT.
748 *
749 * @param obj either an AWT Window (Frame, JFrame) or NEWT Window
750 * @param willClose indicating that the window will close, hence this method waits for the window to be closed
751 * @param waitAction if not null, Runnable shall wait {@link #TIME_SLICE} ms, if appropriate
752 * @param wcl the WindowClosingListener to determine whether the AWT or NEWT widget has been closed. It should be attached
753 * to the widget ASAP before any other listener, e.g. via {@link #addClosingListener(Object)}.
754 * The WindowClosingListener will be reset before attempting to close the widget.
755 * @return True if the Window is closing and closed (if willClose is true), each within TIME_OUT
756 * @throws InterruptedException
757 */
758 public static boolean closeWindow(final java.awt.Window win, final boolean willClose, final TestUtil.WindowClosingListener closingListener, final Runnable waitAction) throws InterruptedException {
759 closingListener.reset();
760 final java.awt.Toolkit tk = java.awt.Toolkit.getDefaultToolkit();
761 final java.awt.EventQueue evtQ = tk.getSystemEventQueue();
762 AWTEDTExecutor.singleton.invoke(true, new Runnable() {
763 @Override
764 public void run() {
765 evtQ.postEvent(new java.awt.event.WindowEvent(win, java.awt.event.WindowEvent.WINDOW_CLOSING));
766 } });
767 return waitUntilClosed(willClose, closingListener, waitAction);
768 }
769
770 public static TestUtil.WindowClosingListener addClosingListener(final java.awt.Window win) {
771 final AWTWindowClosingAdapter acl = new AWTWindowClosingAdapter();
772 AWTEDTExecutor.singleton.invoke(true, new Runnable() {
773 @Override
774 public void run() {
775 win.addWindowListener(acl);
776 } } );
777 return acl;
778 }
779 static class AWTWindowClosingAdapter
780 extends java.awt.event.WindowAdapter implements TestUtil.WindowClosingListener
781 {
782 AtomicInteger closing = new AtomicInteger(0);
783 AtomicInteger closed = new AtomicInteger(0);
784
785 @Override
786 public void reset() {
787 closing.set(0);
788 closed.set(0);
789 }
790 @Override
791 public int getWindowClosingCount() {
792 return closing.get();
793 }
794 @Override
795 public int getWindowClosedCount() {
796 return closed.get();
797 }
798 @Override
799 public boolean isWindowClosing() {
800 return 0 < closing.get();
801 }
802 @Override
803 public boolean isWindowClosed() {
804 return 0 < closed.get();
805 }
806 @Override
807 public void windowClosing(final java.awt.event.WindowEvent e) {
808 closing.incrementAndGet();
809 System.err.println("AWTWindowClosingAdapter.windowClosing: "+this);
810 }
811 @Override
812 public void windowClosed(final java.awt.event.WindowEvent e) {
813 closed.incrementAndGet();
814 System.err.println("AWTWindowClosingAdapter.windowClosed: "+this);
815 }
816 @Override
817 public String toString() {
818 return "AWTWindowClosingAdapter[closing "+closing+", closed "+closed+"]";
819 }
820 }
821
822}
823
Provides a pluggable mechanism for arbitrary window toolkits to adapt their components to the NativeW...
final Point translate(final Point pd)
Translate this instance's x- and y-components, i.e.
Definition: Point.java:131
static void centerMouse(Robot robot, final Object obj, final boolean onTitleBarIfWindow)
centerMouse FIXME: AWTRobotUtil Cleanup: Use specific type for argument object
static void requestFocus(final Robot robot, final Object obj, final int x, final int y)
static int keyType(final int i, final Robot robot, final int keyCode, final Object obj, final KeyEventCountAdapter counter)
static void setMouseToClientLocation(Robot robot, final Object obj, final int x, final int y)
static boolean hasFocus(final Object obj)
static void assertKeyType(Robot robot, final int keyCode, final int typeCount, final Object obj, final KeyEventCountAdapter counter)
FIXME: AWTRobotUtil Cleanup: Use specific type for argument object.
static void awtRobotMouseMove(final Robot robot, final int x, final int y)
static boolean waitForFocus(final java.awt.Component comp, final Runnable waitAction)
static void validateAWTEDTIsAlive()
Throws Error if isAWTEDTAlive() returns false.
static int newtKeyPress(final int i, final Robot robot, final boolean press, final short newtKeyCode, final int msDelay)
No validation is performed .
static void assertMouseClick(Robot robot, final int mouseButton, final int clickCount, final Object obj, final InputEventCountAdapter counter)
FIXME: AWTRobotUtil Cleanup: Use specific type for argument object.
static void requestFocus(final Robot robot, final Object obj)
FIXME: AWTRobotUtil Cleanup: Use specific type for argument object.
static boolean toFrontAndRequestFocus(Robot robot, final java.awt.Window window)
toFront, call setVisible(true) and toFront(), after positioning the mouse in the middle of the window...
static int[] getCenterLocation(final Object obj, final boolean onTitleBarIfWindow)
static void mouseMove(final Robot robot, final Point destination, final int iter, final int delay)
static TestUtil.WindowClosingListener addClosingListener(final java.awt.Window win)
static int getClickTimeout(final Object obj)
static boolean isAWTEDTAlive()
Probes whether AWT's EDT is alive or not.
static boolean waitForRealized(final java.awt.Component comp, final boolean realized, final Runnable waitAction)
static boolean closeWindow(final java.awt.Window win, final boolean willClose, final TestUtil.WindowClosingListener closingListener, final Runnable waitAction)
Programmatically issue windowClosing on AWT or NEWT.
static void assertKeyPress(Robot robot, final int keyCode, final int typeCount, final Object obj, final KeyEventCountAdapter counter)
FIXME: AWTRobotUtil Cleanup: Use specific type for argument object.
static boolean waitForVisible(final java.awt.Component comp, final boolean visible, final Runnable waitAction)
static void mouseClick(final Robot robot, final Point pos, final int moveIter, final int moveDelay, final int actionDelay)
static boolean waitForFocus(final java.awt.Component comp, final FocusEventCountAdapter gain, final FocusEventCountAdapter lost, final Runnable waitAction)
static int keyPress(final int i, final Robot robot, final boolean press, final int keyCode, final int msDelay)
No validation is performed .
static int[] getClientLocation(final Object obj, final int x, final int y)
static void assertRequestFocusAndWait(final Robot robot, final Object requestFocus, final Object waitForFocus, final FocusEventCountAdapter gain, final FocusEventCountAdapter lost)
static void waitForIdle(final Robot robot)
Issuing validateAWTEDTIsAlive() before calling Robot#waitForIdle().
static void requestFocus(final Robot robot, final Object obj, final boolean onTitleBarIfWindow)
FIXME: AWTRobotUtil Cleanup: Use specific type for argument object.
static boolean waitForFocus(final Window win, final Runnable waitAction)
static boolean waitForFocus(final FocusEventCountAdapter gain, final FocusEventCountAdapter lost, final Runnable waitAction)
Definition: TestUtil.java:50
static boolean waitUntilClosed(final boolean willClose, final TestUtil.WindowClosingListener closingListener, final Runnable waitAction)
Wait until the window is closing within TIME_OUT.
Definition: TestUtil.java:77
Extend the NativeSurface interface with windowing information such as window-handle,...
Immutable insets representing rectangular window decoration insets on all four edges in window units.
A higher-level abstraction than GLDrawable which supplies an event based mechanism (GLEventListener) ...
boolean isRealized()
Returns true if this drawable is realized, otherwise false.