1 /* 2 * Copyright (c) 2007, 2017, 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 package org.jemmy.input.awt; 26 27 28 import java.awt.AWTException; 29 import java.awt.BorderLayout; 30 import java.awt.Button; 31 import java.awt.EventQueue; 32 import java.awt.Frame; 33 import java.awt.Robot; 34 import java.awt.event.InputEvent; 35 import java.awt.event.KeyAdapter; 36 import java.awt.event.KeyEvent; 37 import java.awt.event.MouseAdapter; 38 import java.awt.event.MouseEvent; 39 import java.io.File; 40 import java.lang.reflect.InvocationTargetException; 41 import java.util.HashMap; 42 import java.util.HashSet; 43 import java.util.Queue; 44 import java.util.Random; 45 import java.util.concurrent.ConcurrentLinkedQueue; 46 import org.jemmy.Point; 47 import org.jemmy.control.Wrap; 48 import org.jemmy.env.Environment; 49 import org.jemmy.env.Timeout; 50 import org.jemmy.image.awt.AWTImage; 51 import org.jemmy.input.awt.AWTMap; 52 import org.jemmy.input.awt.RobotDriver; 53 import org.jemmy.input.awt.RobotExecutor; 54 import org.jemmy.interfaces.Keyboard.KeyboardButton; 55 import org.jemmy.interfaces.Modifier; 56 import org.jemmy.interfaces.Mouse.MouseButton; 57 import org.jemmy.interfaces.Mouse.MouseButtons; 58 import org.jemmy.timing.State; 59 import org.jemmy.timing.Waiter; 60 import org.testng.annotations.AfterClass; 61 import org.testng.annotations.AfterMethod; 62 import org.testng.annotations.BeforeClass; 63 import org.testng.annotations.BeforeMethod; 64 import org.testng.annotations.Test; 65 66 67 /** 68 * 69 * @author Alexander Kouznetsov <mrkam@mail.ru> 70 */ 71 public class RobotDriver2Test { 72 73 final static Timeout TIMEOUT = new Timeout("Wait for state to be reached", 10000); 74 final static Timeout DELTA_TIMEOUT = new Timeout("Delta timeout of wait for state to be reached", 1000); 75 76 public RobotDriver2Test() { 77 } 78 79 @BeforeClass 80 public static void setUpClass() throws Exception { 81 File workdir = new File(System.getProperty("user.dir") + File.separator + 82 "build" + File.separator + 83 "test" + File.separator + 84 "results"); 85 workdir.mkdirs(); 86 AWTImage.setImageRoot(workdir); 87 } 88 89 @AfterClass 90 public static void tearDownClass() throws Exception { 91 RobotDriver.exit(); 92 } 93 94 Frame frm; 95 Button btn; 96 Wrap<Object> area; 97 RobotDriver instance; 98 Robot rb; 99 Queue<InputEvent> queue = new ConcurrentLinkedQueue<InputEvent>(); 100 static Random r = new Random(); 101 102 @BeforeMethod 103 public void setUp() throws InterruptedException, AWTException, InvocationTargetException { 104 EventQueue.invokeAndWait(new Runnable() { 105 106 public void run() { 107 frm = new Frame("some frame"); 108 frm.setSize(100, 100); 109 frm.setLocation(100, 100); 110 btn = new Button("some button"); 111 MouseAdapter m = new MouseAdapter() { 112 113 @Override 114 public void mousePressed(MouseEvent e) { 115 System.out.println("mousePressed event triggered: " + e); 116 System.out.flush(); 117 queue.add(e); 118 } 119 120 @Override 121 public void mouseReleased(MouseEvent e) { 122 System.out.println("mouseReleased event triggered: " + e); 123 System.out.flush(); 124 queue.add(e); 125 } 126 127 @Override 128 public void mouseMoved(MouseEvent e) { 129 System.out.println("mouseMoved event triggered: " + e); 130 System.out.flush(); 131 queue.add(e); 132 } 133 134 @Override 135 public void mouseClicked(MouseEvent e) { 136 System.out.println("mouseClicked event triggered: " + e); 137 System.out.flush(); 138 queue.add(e); 139 } 140 141 @Override 142 public void mouseDragged(MouseEvent e) { 143 System.out.println("mouseDragged event triggered: " + e); 144 System.out.flush(); 145 queue.add(e); 146 } 147 148 }; 149 btn.addMouseListener(m); 150 btn.addMouseMotionListener(m); 151 btn.addKeyListener(new KeyAdapter() { 152 153 @Override 154 public void keyPressed(KeyEvent e) { 155 System.out.println("keyPressed event triggered: " + e); 156 System.out.flush(); 157 queue.add(e); 158 } 159 160 @Override 161 public void keyReleased(KeyEvent e) { 162 System.out.println("keyReleased event triggered: " + e); 163 System.out.flush(); 164 queue.add(e); 165 } 166 167 }); 168 frm.add(btn, BorderLayout.SOUTH); 169 frm.doLayout(); 170 instance = new RobotDriver(Environment.getEnvironment()); 171 frm.setVisible(true); 172 btn.requestFocusInWindow(); 173 } 174 }); 175 176 rb = new Robot(); 177 rb.waitForIdle(); 178 179 RobotExecutor.get().setRunInOtherJVM(true); 180 181 } 182 183 @AfterMethod 184 public void tearDown() throws InterruptedException, InvocationTargetException { 185 EventQueue.invokeAndWait(new Runnable() { 186 187 public void run() { 188 frm.setVisible(false); 189 } 190 }); 191 } 192 193 // /** 194 // * Test of createScreenCapture method, of class RobotDriver. 195 // */ 196 // @Test 197 // public void testCreateScreenCaptureLocally() throws AWTException, InterruptedException { 198 // System.out.println("testCreateScreenCaptureLocally"); 199 // Thread.sleep(3000); 200 // Rectangle screenRect = new Rectangle(100, 100, 100, 100); 201 // RobotExecutor.get().setRunInOtherJVM(false); 202 // Image expResult = new AWTImage(new Robot().createScreenCapture(new java.awt.Rectangle(100, 100, 100, 100))); 203 // Image result = RobotDriver.createScreenCapture(screenRect); 204 // Image diff = expResult.compareTo(result); 205 // if (diff != null) { 206 // diff.save("testCreateScreenCaptureLocally.png"); 207 // fail(); 208 // } 209 // } 210 // 211 // /** 212 // * Test of createScreenCapture method, of class RobotDriver. 213 // */ 214 // @Test 215 // public void testCreateScreenCaptureRemotely() throws AWTException, InterruptedException { 216 // System.out.println("testCreateScreenCaptureRemotely"); 217 // Thread.sleep(3000); 218 // Rectangle screenRect = new Rectangle(100, 100, 100, 100); 219 // RobotExecutor.get().setRunInOtherJVM(true); 220 // Image expResult = new AWTImage(new Robot().createScreenCapture(new java.awt.Rectangle(100, 100, 100, 100))); 221 // Image result = RobotDriver.createScreenCapture(screenRect); 222 // RobotDriver.createScreenCapture(screenRect); 223 // Image diff = expResult.compareTo(result); 224 // if (diff != null) { 225 // diff.save("testCreateScreenCaptureRemotely.png"); 226 // fail(); 227 // } 228 // } 229 // 230 // /** 231 // * Test of createScreenCapture method, of class RobotDriver. 232 // */ 233 // @Test 234 // public void testCreateScreenCaptureRemotely2() throws AWTException, InterruptedException { 235 // System.out.println("testCreateScreenCaptureRemotely2"); 236 // Thread.sleep(3000); 237 // Rectangle screenRect = new Rectangle(100, 100, 100, 100); 238 // RobotExecutor.get().setRunInOtherJVM(true); 239 // Image expResult = new AWTImage(new Robot().createScreenCapture(new java.awt.Rectangle(100, 100, 100, 100))); 240 // Image result = RobotDriver.createScreenCapture(screenRect); 241 // Image diff = expResult.compareTo(result); 242 // if (diff != null) { 243 // diff.save("testCreateScreenCaptureRemotely2.png"); 244 // fail(); 245 // } 246 // } 247 248 /** 249 * Test of all RobotDriver methods invoked multiple times 250 * @throws InterruptedException 251 */ 252 // @Test 253 public void testAll() throws InterruptedException { 254 for(int i = 0; i < 10; i++) { 255 testPressMouse(); 256 } 257 } 258 259 public void test() throws InterruptedException { 260 // testPressMouse(); 261 testPressKey(); 262 } 263 264 @Test 265 public void test0() throws InterruptedException { 266 test(); 267 } 268 269 @Test 270 public void test1() throws InterruptedException { 271 test(); 272 } 273 274 @Test 275 public void test2() throws InterruptedException { 276 test(); 277 } 278 279 @Test 280 public void test3() throws InterruptedException { 281 test(); 282 } 283 284 @Test 285 public void test4() throws InterruptedException { 286 test(); 287 } 288 289 @Test 290 public void test5() throws InterruptedException { 291 test(); 292 } 293 294 @Test 295 public void test6() throws InterruptedException { 296 test(); 297 } 298 299 @Test 300 public void test7() throws InterruptedException { 301 test(); 302 } 303 304 @Test 305 public void test8() throws InterruptedException { 306 test(); 307 } 308 309 @Test 310 public void test9() throws InterruptedException { 311 test(); 312 } 313 314 protected static final int[] MODIFIERS = new int[] { 315 InputEvent.SHIFT_DOWN_MASK, 316 InputEvent.CTRL_DOWN_MASK, 317 InputEvent.ALT_DOWN_MASK, 318 InputEvent.SHIFT_MASK, 319 InputEvent.CTRL_MASK, 320 InputEvent.ALT_MASK, 321 // MouseEvent.ALT_GRAPH_DOWN_MASK, 322 // MouseEvent.META_DOWN_MASK 323 }; 324 325 public static int getModifiers() { 326 int modifiersMask = r.nextInt(1 << MODIFIERS.length/2); 327 int m = 0; 328 System.out.print("Modifiers:"); 329 for (int i = 0; i < MODIFIERS.length/2; i++) { 330 if ((modifiersMask & (1 << i)) != 0 ) { 331 m |= MODIFIERS[i]; 332 System.out.print(" " + i); 333 } 334 } 335 System.out.println(""); 336 return m; 337 } 338 339 protected static HashMap<Integer, Integer> normalizeMap = new HashMap<Integer, Integer>(); 340 static { 341 normalizeMap.put(InputEvent.SHIFT_MASK,InputEvent.SHIFT_DOWN_MASK); 342 normalizeMap.put(InputEvent.CTRL_MASK,InputEvent.CTRL_DOWN_MASK); 343 normalizeMap.put(InputEvent.ALT_MASK,InputEvent.ALT_DOWN_MASK); 344 normalizeMap.put(InputEvent.META_MASK,InputEvent.META_DOWN_MASK); 345 } 346 347 protected static HashSet<Integer> normalize(HashSet<Integer> modifiers) { 348 HashSet<Integer> normalized = new HashSet<Integer>(); 349 for (Integer mod : modifiers) { 350 Integer n = normalizeMap.get(mod); 351 if (n != null) { 352 normalized.add(n); 353 } else { 354 normalized.add(mod); 355 } 356 } 357 return normalized; 358 } 359 360 protected static HashSet<Integer> modifiers2Set(int mods) { 361 HashSet<Integer> set = new HashSet<Integer>(); 362 for (int i = 0; i < MODIFIERS.length; i++) { 363 if ((mods & MODIFIERS[i]) > 0) { 364 set.add(MODIFIERS[i]); 365 } 366 } 367 return set; 368 } 369 370 protected static boolean compareModifiers(int m1, int m2) { 371 return normalize(modifiers2Set(m1)).equals(normalize(modifiers2Set(m2))); 372 } 373 /** 374 * Test of pressMouse method, of class RobotDriver. 375 */ 376 public void testPressMouse() throws InterruptedException { 377 System.out.println("pressMouse"); 378 Thread.sleep(3000); 379 final int[] MOUSE_BUTTONS_1 = new int[] { 380 MouseEvent.BUTTON1_MASK, 381 MouseEvent.BUTTON2_MASK, 382 MouseEvent.BUTTON3_MASK 383 }; 384 final int[] MOUSE_BUTTONS_2 = new int[] { 385 MouseEvent.BUTTON1, 386 MouseEvent.BUTTON2, 387 MouseEvent.BUTTON3 388 }; 389 int bIndex = r.nextInt(MOUSE_BUTTONS_1.length); 390 final int mouseButton1 = MOUSE_BUTTONS_1[bIndex]; 391 final int mouseButton2 = MOUSE_BUTTONS_2[bIndex]; 392 System.out.print("Button: " + bIndex + " Modifier:"); 393 final int modifiers = getModifiers(); 394 queue.clear(); 395 java.awt.Point locationOnScreen = btn.getLocationOnScreen(); 396 System.out.println("Pressing mouse"); 397 instance.moveMouse(new Point(locationOnScreen.x + btn.getWidth() / 2, locationOnScreen.y + btn.getHeight() / 2)); 398 AWTMap map = new AWTMap(); 399 MouseButton button = map.convertMouseButton(mouseButton1); 400 Modifier[] converted_modifiers = map.convertModifiers(modifiers); 401 instance.pressMouse(button, converted_modifiers); 402 instance.releaseMouse(button, converted_modifiers); 403 404 rb.waitForIdle(); 405 new Waiter(TIMEOUT, DELTA_TIMEOUT).ensureState(new State<Boolean>(){ 406 407 public Boolean reached() { 408 while(true) { 409 InputEvent e = queue.poll(); 410 if (e != null) { 411 if (e instanceof MouseEvent) { 412 MouseEvent me = (MouseEvent) e; 413 if (me.getID() == MouseEvent.MOUSE_PRESSED && me.getButton() == mouseButton2 && (compareModifiers(me.getModifiers(), modifiers))) { 414 return true; 415 } 416 if (me.getID() == MouseEvent.MOUSE_PRESSED) { 417 System.out.println("Wrong combination of button and modifiers triggered:"); 418 System.out.println("me.getModifiers() = " + Integer.toString(me.getModifiers(), 2) + ", modifiers = " + Integer.toString(modifiers, 2)); 419 System.out.println("expected: " + new MouseEvent( 420 me.getComponent(), MouseEvent.MOUSE_PRESSED, 421 me.getWhen(), modifiers, me.getX(), me.getY(), me.getClickCount(), me.isPopupTrigger(), mouseButton2)); 422 System.out.println(" got: " + me); 423 } 424 } 425 } else { 426 break; 427 } 428 } 429 return null; 430 } 431 432 }); 433 434 System.out.println("PASSED"); 435 436 } 437 438 // /** 439 // * Test of releaseMouse method, of class RobotDriver. 440 // */ 441 // @Test 442 // public void testReleaseMouse() throws InterruptedException { 443 // System.out.println("releaseMouse"); 444 // Thread.sleep(3000); 445 // int mouseButton = MouseEvent.BUTTON2_MASK; 446 // int modifiers = MouseEvent.CTRL_DOWN_MASK; 447 // mouseReleased = false; 448 // java.awt.Point locationOnScreen = btn.getLocationOnScreen(); 449 // instance.moveMouse(new Point(locationOnScreen.x + btn.getWidth() / 2, locationOnScreen.y + btn.getHeight() / 2)); 450 // System.out.println("Pressing mouse"); 451 // instance.pressMouse(mouseButton, modifiers); 452 // System.out.println("Releasing mouse"); 453 // instance.releaseMouse(mouseButton, modifiers); 454 // 455 // rb.waitForIdle(); 456 // new Waiter(TIMEOUT, DELTA_TIMEOUT).ensureState(new State<Boolean>(){ 457 // 458 // public Boolean reached() { 459 // return mouseReleased ? true: null; 460 // } 461 // 462 // }); 463 // assertTrue(mouseReleased); 464 // } 465 // 466 // /** 467 // * Test of moveMouse method, of class RobotDriver. 468 // */ 469 // @Test 470 // public void testMoveMouse() throws InterruptedException { 471 // System.out.println("moveMouse"); 472 // Thread.sleep(3000); 473 // mouseMoved = false; 474 // java.awt.Point locationOnScreen = btn.getLocationOnScreen(); 475 // System.out.println("Moving mouse"); 476 // Point startPoint = new Point(locationOnScreen.x, locationOnScreen.y); 477 // Point endPoint = new Point(locationOnScreen.x + btn.getWidth(), locationOnScreen.y + btn.getHeight()); 478 // double steps = 5; //Math.max(btn.getWidth(), btn.getHeight()); 479 // double dx = (endPoint.x - startPoint.x) / steps; 480 // double dy = (endPoint.y - startPoint.y) / steps; 481 // for(int i = 0; i < steps; i++) { 482 // Point point = new Point(startPoint.x + dx * i, startPoint.y + dy * i); 483 // instance.moveMouse(point); 484 // Thread.sleep(100); 485 // } 486 // 487 // rb.waitForIdle(); 488 // new Waiter(TIMEOUT, DELTA_TIMEOUT).ensureState(new State<Boolean>(){ 489 // 490 // public Boolean reached() { 491 // return mouseMoved ? true: null; 492 // } 493 // 494 // }); 495 // assertTrue(mouseMoved); 496 // } 497 // 498 // /** 499 // * Test of clickMouse method, of class RobotDriver. 500 // */ 501 // @Test 502 // public void testClickMouse() throws InterruptedException { 503 // System.out.println("clickMouse"); 504 // Thread.sleep(3000); 505 // mouseClicked = false; 506 // java.awt.Point locationOnScreen = btn.getLocationOnScreen(); 507 // Point point = new Point(locationOnScreen.x + btn.getWidth() / 2, locationOnScreen.y + btn.getHeight() / 2); 508 // int clickCount = 1; 509 // int mouseButton = MouseEvent.BUTTON3_MASK; 510 // int modifiers = InputEvent.ALT_DOWN_MASK; 511 // Timeout mouseClick = new Timeout("mouseClick", 100); 512 // System.out.println("Clicking mouse"); 513 // instance.clickMouse(point, clickCount, mouseButton, modifiers, mouseClick); 514 // 515 // rb.waitForIdle(); 516 // new Waiter(TIMEOUT, DELTA_TIMEOUT).ensureState(new State<Boolean>(){ 517 // 518 // public Boolean reached() { 519 // return mouseClicked ? true: null; 520 // } 521 // 522 // }); 523 // assertTrue(mouseClicked); 524 // } 525 // 526 // /** 527 // * Test of dragNDrop method, of class RobotDriver. 528 // */ 529 // @Test 530 // public void testDragNDrop() throws InterruptedException { 531 // System.out.println("dragNDrop"); 532 // java.awt.Point locationOnScreen = btn.getLocationOnScreen(); 533 // Point startPoint = new Point(locationOnScreen.x + btn.getWidth() / 2, locationOnScreen.y + btn.getHeight() / 2); 534 // Point endPoint = new Point(frm.getLocationOnScreen().x + frm.getWidth() / 2, frm.getLocationOnScreen().y + frm.getHeight() / 2); 535 // int mouseButton = MouseEvent.BUTTON2_MASK; 536 // int modifiers = 0; 537 // Timeout before = new Timeout("before", 500); 538 // Timeout after = new Timeout("after", 500); 539 // mouseDragged = false; 540 // instance.dragNDrop(startPoint, endPoint, mouseButton, modifiers, before, after); 541 // 542 // rb.waitForIdle(); 543 // new Waiter(TIMEOUT, DELTA_TIMEOUT).ensureState(new State<Boolean>(){ 544 // 545 // public Boolean reached() { 546 // return mouseDragged ? true: null; 547 // } 548 // 549 // }); 550 // assertTrue(mouseDragged); 551 // } 552 553 /** 554 * Test of pressKey method, of class RobotDriver. 555 */ 556 public void testPressKey() throws InterruptedException { 557 System.out.println("pressKey"); 558 Thread.sleep(3000); 559 560 final int keyCode = KeyEvent.VK_A; 561 final int modifiers = getModifiers(); 562 AWTMap map = new AWTMap(); 563 KeyboardButton button = map.convertKeyboardButton(keyCode); 564 Modifier[] converted_modifiers = map.convertModifiers(modifiers); 565 566 queue.clear(); 567 568 java.awt.Point locationOnScreen = btn.getLocationOnScreen(); 569 instance.clickMouse(new Point(locationOnScreen.x + btn.getWidth() / 2, locationOnScreen.y + btn.getHeight() / 2), 1, 570 MouseButtons.BUTTON1, DELTA_TIMEOUT); 571 572 rb.waitForIdle(); 573 574 instance.pressKey(button, converted_modifiers); 575 instance.releaseKey(button, converted_modifiers); 576 577 rb.waitForIdle(); 578 new Waiter(TIMEOUT, DELTA_TIMEOUT).ensureState(new State<Boolean>(){ 579 580 public Boolean reached() { 581 while(true) { 582 InputEvent e = queue.poll(); 583 if (e != null) { 584 if (e instanceof KeyEvent) { 585 KeyEvent ke = (KeyEvent) e; 586 if (ke.getID() == KeyEvent.KEY_PRESSED && ke.getKeyCode() == keyCode && compareModifiers(ke.getModifiers(), modifiers)) { 587 return true; 588 } 589 if (ke.getID() == KeyEvent.KEY_PRESSED) { 590 System.out.println("Wrong combination of button and modifiers triggered:"); 591 System.out.println("ke.getModifiers() = " + Integer.toString(ke.getModifiers(), 2) + ", modifiers = " + Integer.toString(modifiers, 2)); 592 System.out.println("expected: " + new KeyEvent(ke.getComponent(), KeyEvent.KEY_PRESSED, ke.getWhen(), modifiers, keyCode, KeyEvent.CHAR_UNDEFINED)); 593 System.out.println(" got: " + ke); 594 } 595 } 596 } else { 597 break; 598 } 599 } 600 return null; 601 } 602 603 }); 604 605 System.out.println("PASSED"); 606 } 607 608 // /** 609 // * Test of releaseKey method, of class RobotDriver. 610 // */ 611 // @Test 612 // public void testReleaseKey() throws InterruptedException { 613 // System.out.println("releaseKey"); 614 // int keyCode = KeyEvent.VK_B; 615 // int modifiers = 0; 616 // keyReleased = false; 617 // instance.pressKey(keyCode, modifiers); 618 // instance.releaseKey(keyCode, modifiers); 619 // 620 // rb.waitForIdle(); 621 // new Waiter(TIMEOUT, DELTA_TIMEOUT).ensureState(new State<Boolean>(){ 622 // 623 // public Boolean reached() { 624 // return keyReleased ? true: null; 625 // } 626 // 627 // }); 628 // assertTrue(keyReleased); 629 // } 630 631 }