1 /*
   2  * Copyright (c) 2008, 2016, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25   @test %I% %E%
  26   @key headful
  27   @bug 6315717
  28   @summary verifies that modifiers are correct for extra buttons
  29   @author Andrei Dmitriev : area=awt.mouse
  30   @run main MouseModifiersUnitTest_Extra
  31  */
  32 
  33 import sun.awt.OSInfo;
  34 
  35 import java.awt.*;
  36 import java.awt.event.*;
  37 import java.util.Arrays;
  38 import java.util.HashMap;
  39 import java.util.StringTokenizer;
  40 import java.util.Vector;
  41 
  42 // will process extra buttons only
  43 // asking parameters from CMD: manual/automatic, modifier to test
  44 
  45 public class MouseModifiersUnitTest_Extra extends Frame {
  46     static final int NONE = 0;
  47     static final int SHIFT = 1;
  48     static final int CTRL = 2;
  49     static final int ALT = 3;
  50     static CheckingModifierAdapterExtra adapterTest1;
  51     static CheckingModifierAdapterExtra adapterTest2;
  52     static CheckingModifierAdapterExtra adapterTest3;
  53     static CheckingModifierAdapterExtra adapterTest4;
  54 
  55     static boolean debug = true; //dump all errors (debug) or throw first(under jtreg) exception
  56     static boolean autorun = false; //use robot or manual run
  57     static int testModifier = NONE;
  58 
  59     static int [] mouseButtonDownMasks;
  60 
  61     //an arrays representing a modifiersEx of extra mouse buttons while using ALT/CTRL/SHIFT or none of them
  62     static int [] modifiersExStandard;
  63     static int [] modifiersExStandardSHIFT;
  64     static int [] modifiersExStandardCTRL;
  65     static int [] modifiersExStandardALT;
  66 
  67     private final static String SHIFT_MODIFIER = OSInfo.getOSType().equals(OSInfo.OSType.MACOSX) ?
  68                                                 "\u21e7" : "Shift";
  69 
  70     private final static String ALT_MODIFIER = OSInfo.getOSType().equals(OSInfo.OSType.MACOSX) ?
  71                                                 "\u2325" : "Alt";
  72 
  73 
  74     private final static String CTRL_MODIFIER = OSInfo.getOSType().equals(OSInfo.OSType.MACOSX) ?
  75                                                 "\u2303" : "Ctrl";
  76 
  77 
  78     // BUTTON1, 2, 3 press-release.
  79     final static int  modifiersStandard = 0; //InputEvent.BUTTON_DOWN_MASK;
  80 
  81     public static void checkPressedModifiersTest(int testModifier, MouseEvent event){
  82         int [] curStandardExModifiers = getStandardExArray(testModifier);
  83         int button = event.getButton();
  84         int modifiers = event.getModifiers();
  85         int modifiersEx = event.getModifiersEx();
  86         int index = (button - 4)*3;
  87         dumpValues(button, modifiers, modifiersStandard, modifiersEx, curStandardExModifiers[index]);
  88         if (modifiers != modifiersStandard){
  89             MessageLogger.reportError("Test failed :  Pressed. modifiers != modifiersStandard");
  90         }
  91 
  92         if (modifiersEx != curStandardExModifiers[index]){
  93 //            System.out.println(">>>>>>>>>>>>>>> Pressed. modifiersEx "+modifiersEx +" : "+!= curStandardExModifiers");
  94             MessageLogger.reportError("Test failed :  Pressed. modifiersEx != curStandardExModifiers. Got: "
  95                     + modifiersEx + " , Expected: " + curStandardExModifiers[index]);
  96         }
  97 
  98      //check event.paramString() output
  99         HashMap <String, String> paramStringElements = tokenizeParamString(event.paramString());
 100         System.out.println(event.paramString());
 101         checkButton(paramStringElements, button);
 102         checkModifiers(testModifier, paramStringElements, button);
 103         checkExtModifiersOnPress(testModifier, paramStringElements, button);
 104     }
 105 
 106     public static void checkExtModifiersOnReleaseClick(int testModifier, HashMap<String, String> h, int button){
 107         String ethalon = "";
 108         switch (testModifier){
 109             case SHIFT:{
 110                 ethalon = SHIFT_MODIFIER;
 111                 break;
 112             }
 113             case ALT:{
 114                 ethalon = ALT_MODIFIER;
 115                 break;
 116             }
 117             case CTRL:{
 118                 ethalon = CTRL_MODIFIER;
 119                 break;
 120             }
 121         }
 122 
 123         if (h.get("extModifiers") == null){
 124             h.put("extModifiers", "");
 125         }
 126 
 127         if (!ethalon.equals(h.get("extModifiers"))) {
 128             MessageLogger.reportError("Test failed :  Released/Clicked. extModifiers = "
 129                     + h.get("extModifiers") + " instead of : " + ethalon);
 130         }
 131     }
 132 
 133     public static void checkExtModifiersOnPress(int testModifier, HashMap<String, String> h, int button){
 134         String ethalon = "";
 135         switch (testModifier){
 136             case SHIFT:{
 137                 ethalon = SHIFT_MODIFIER + "+";
 138                 break;
 139             }
 140             case ALT:{
 141                 ethalon = ALT_MODIFIER + "+";
 142                 break;
 143             }
 144             case CTRL:{
 145                 ethalon = CTRL_MODIFIER + "+";
 146                 break;
 147             }
 148         }
 149         ethalon = ethalon + "Button" +button;
 150 
 151         if (!h.get("extModifiers").equals(ethalon)) {
 152             MessageLogger.reportError("Test failed :  Pressed. extModifiers = " +h.get("extModifiers")+" instead of : "
 153                     + ethalon);
 154         }
 155     }
 156 
 157     public static void checkModifiers(int testModifier, HashMap<String, String> h, int button){
 158         // none of modifiers for extra button should be null
 159         if (h.get("modifiers") != null) {
 160             MessageLogger.reportError("Test failed : modifiers != null");
 161         }
 162     }
 163 
 164     public static void checkButton(HashMap<String, String> h, int button){
 165         if (h.get("button") == null) {
 166             MessageLogger.reportError("Test failed :  checkButton(). button is absent in paramString()");
 167         }
 168         if (Integer.parseInt(h.get("button")) != button) {
 169             MessageLogger.reportError("Test failed :  checkButton. button in paramString() doesn't equal to button being pressed.");
 170         }
 171     }
 172     public static HashMap<String, String> tokenizeParamString(String param){
 173         HashMap <String, String> params = new HashMap<>();
 174         StringTokenizer st = new StringTokenizer(param, ",=");
 175         while (st.hasMoreTokens()){
 176             String tmp = st.nextToken();
 177 //            System.out.println("PARSER : "+tmp);
 178             if (tmp.equals("button") ||
 179                     tmp.equals("modifiers") ||
 180                     tmp.equals("extModifiers")) {
 181                 params.put(tmp, st.nextToken());
 182             }
 183         }
 184         return params;
 185     }
 186 
 187     public static Vector<String> tokenizeModifiers(String modifierList){
 188         Vector<String> modifiers = new Vector<>();
 189         StringTokenizer st = new StringTokenizer(modifierList, "+");
 190         while (st.hasMoreTokens()){
 191             String tmp = st.nextToken();
 192             modifiers.addElement(tmp);
 193             System.out.println("MODIFIER PARSER : "+tmp);
 194         }
 195         return modifiers;
 196     }
 197 
 198     public static void checkReleasedModifiersTest(int testModifier, MouseEvent event){
 199         int [] curStandardExModifiers = getStandardExArray(testModifier);
 200         int button = event.getButton();
 201         int modifiers = event.getModifiers();
 202         int modifiersEx = event.getModifiersEx();
 203         int index = (button - 4)*3 + 1;
 204         dumpValues(button, modifiers, modifiersStandard, modifiersEx, curStandardExModifiers[index]);
 205         if (modifiers != modifiersStandard){
 206             MessageLogger.reportError("Test failed :  Released. modifiers != modifiersStandard");
 207         }
 208 
 209         if (modifiersEx != curStandardExModifiers[index]){
 210             MessageLogger.reportError("Test failed :  Released. modifiersEx != curStandardExModifiers. Got: "
 211                     + modifiersEx + " , Expected: " + curStandardExModifiers[index]);
 212         }
 213 
 214      //check event.paramString() output
 215         HashMap <String, String> paramStringElements = tokenizeParamString(event.paramString());
 216         checkButton(paramStringElements, button);
 217         checkModifiers(testModifier, paramStringElements, button);
 218         System.out.println("paramStringElements = "+paramStringElements);
 219         checkExtModifiersOnReleaseClick(testModifier, paramStringElements, button);
 220     }
 221 
 222     public static void checkClickedModifiersTest(int testModifier, MouseEvent event){
 223         int [] curStandardExModifiers = getStandardExArray(testModifier);
 224         int button = event.getButton();
 225         int modifiers = event.getModifiers();
 226         int modifiersEx = event.getModifiersEx();
 227         int index = (button - 4)*3 + 2;
 228         dumpValues(button, modifiers, modifiersStandard, modifiersEx, curStandardExModifiers[index]);
 229         if (modifiers != modifiersStandard){
 230             MessageLogger.reportError("Test failed :  Clicked. modifiers != modifiersStandard");
 231         }
 232 
 233         if (modifiersEx != curStandardExModifiers[index]){
 234             MessageLogger.reportError("Test failed :  Clicked. modifiersEx != curStandardExModifiers. Got: "
 235                     + modifiersEx + " , Expected: " + curStandardExModifiers[index]);
 236         }
 237 
 238      //check event.paramString() output
 239         HashMap <String, String> paramStringElements = tokenizeParamString(event.paramString());
 240         checkButton(paramStringElements, button);
 241         checkModifiers(testModifier, paramStringElements, button);
 242         checkExtModifiersOnReleaseClick(testModifier, paramStringElements, button);
 243     }
 244 
 245     private static int[] getStandardExArray(int testModifier) {
 246         int [] curStandardExModifiers;
 247         switch (testModifier){
 248             case SHIFT:
 249                 curStandardExModifiers = modifiersExStandardSHIFT;
 250                 break;
 251             case CTRL:
 252                 curStandardExModifiers = modifiersExStandardCTRL;
 253                 break;
 254             case ALT:
 255                 curStandardExModifiers = modifiersExStandardALT;
 256                 break;
 257             default: //NONE by default
 258                 curStandardExModifiers = modifiersExStandard;
 259         }
 260         return curStandardExModifiers;
 261     }
 262 
 263     static Robot robot;
 264     public void init() {
 265         this.setLayout(new BorderLayout());
 266         try {
 267             robot  = new Robot();
 268             robot.setAutoDelay(100);
 269             robot.setAutoWaitForIdle(true);
 270         } catch (Exception e) {
 271             MessageLogger.reportError("Test failed. "+e);
 272         }
 273     }//End  init()
 274 
 275     public void start() {
 276         //Get things going.  Request focus, set size, et cetera
 277         setSize(200,200);
 278         setVisible(true);
 279         validate();
 280         if (autorun) {
 281             testNONE();
 282             testSHIFT();
 283             testCTRL();
 284             testALT();
 285         } else {
 286             switch (testModifier){
 287                 case SHIFT:
 288                     this.addMouseListener(adapterTest2);
 289                     break;
 290                 case CTRL:
 291                     this.addMouseListener(adapterTest3);
 292                     break;
 293                 case ALT:
 294                     this.addMouseListener(adapterTest4);
 295                     break;
 296                 default:  //NONE by default
 297                     this.addMouseListener(adapterTest1);
 298             }
 299         }
 300     }// start()
 301 
 302     //000000000000000000000000000000000000000000000000000000000000000
 303     public void testNONE(){
 304         this.addMouseListener(adapterTest1);
 305         robot.delay(1000);
 306         robot.mouseMove(getLocationOnScreen().x + getWidth()/2, getLocationOnScreen().y + getHeight()/2);
 307         for (int i = 3; i< mouseButtonDownMasks.length; i++){
 308             System.out.println("testNONE() => " + mouseButtonDownMasks[i]);
 309             robot.mousePress(mouseButtonDownMasks[i]);
 310             robot.mouseRelease(mouseButtonDownMasks[i]);
 311         }
 312         robot.delay(1000);
 313         this.removeMouseListener(adapterTest1);
 314     }
 315 
 316     public void testSHIFT(){
 317         this.addMouseListener(adapterTest2);
 318         robot.delay(1000);
 319         robot.mouseMove(getLocationOnScreen().x + getWidth()/2, getLocationOnScreen().y + getHeight()/2);
 320         for (int i = 3; i< mouseButtonDownMasks.length; i++){
 321             robot.keyPress(KeyEvent.VK_SHIFT);
 322             System.out.println("testSHIFT() => " + mouseButtonDownMasks[i]);
 323             robot.mousePress(mouseButtonDownMasks[i]);
 324             robot.mouseRelease(mouseButtonDownMasks[i]);
 325             robot.keyRelease(KeyEvent.VK_SHIFT);
 326         }
 327         robot.delay(1000);
 328         this.removeMouseListener(adapterTest2);
 329     }
 330 
 331     public void testCTRL(){
 332         this.addMouseListener(adapterTest3);
 333         robot.delay(1000);
 334         robot.mouseMove(getLocationOnScreen().x + getWidth()/2, getLocationOnScreen().y + getHeight()/2);
 335         for (int i = 3; i< mouseButtonDownMasks.length; i++){
 336             robot.keyPress(KeyEvent.VK_CONTROL);
 337             System.out.println("testCTRL() => " + mouseButtonDownMasks[i]);
 338             robot.mousePress(mouseButtonDownMasks[i]);
 339             robot.mouseRelease(mouseButtonDownMasks[i]);
 340             robot.keyRelease(KeyEvent.VK_CONTROL);
 341         }
 342         robot.delay(1000);
 343         this.removeMouseListener(adapterTest3);
 344     }
 345 
 346     public void testALT(){
 347         this.addMouseListener(adapterTest4);
 348         robot.delay(1000);
 349         robot.mouseMove(getLocationOnScreen().x + getWidth()/2, getLocationOnScreen().y + getHeight()/2);
 350         for (int i = 3; i< mouseButtonDownMasks.length; i++){
 351             robot.keyPress(KeyEvent.VK_ALT);
 352             System.out.println("testALT() => " + mouseButtonDownMasks[i]);
 353             robot.mousePress(mouseButtonDownMasks[i]);
 354             robot.mouseRelease(mouseButtonDownMasks[i]);
 355             robot.keyRelease(KeyEvent.VK_ALT);
 356         }
 357         robot.delay(1000);
 358         this.removeMouseListener(adapterTest4);
 359     }
 360 
 361     //**************************************************************************************************
 362     public static void dumpValues(int button, int modifiers, int modifiersStandard, int modifiersEx, int modifiersExStandard){
 363         System.out.println("Button = "+button + "Modifiers = "+ modifiers + "standard = "+ modifiersStandard);
 364         System.out.println("Button = "+button + "ModifiersEx = "+ modifiersEx + "standardEx = "+ modifiersExStandard);
 365     }
 366 
 367     public static void initParams(String []s){
 368         if (s.length != 3){
 369             autorun = true;
 370             debug = false;
 371             testModifier = NONE;
 372         } else {
 373             autorun = Boolean.valueOf(s[0]);
 374             debug = Boolean.valueOf(s[1]);
 375 
 376             if (s[2].equals("NONE")){
 377                 testModifier = NONE;
 378             }
 379             if (s[2].equals("SHIFT")){
 380                 testModifier = SHIFT;
 381             }
 382             if (s[2].equals("CTRL")){
 383                 testModifier = CTRL;
 384             }
 385             if (s[2].equals("ALT")){
 386                 testModifier = ALT;
 387             }
 388         }
 389         MessageLogger.setDebug(debug);
 390         System.out.println("Autorun : " +autorun);
 391         System.out.println("Debug mode : " +debug);
 392         System.out.println("Modifier to verify : " + testModifier);
 393     }
 394 
 395     public static void initAdapters(){
 396         adapterTest1 = new CheckingModifierAdapterExtra(NONE);
 397         adapterTest2 = new CheckingModifierAdapterExtra(SHIFT);
 398         adapterTest3 = new CheckingModifierAdapterExtra(CTRL);
 399         adapterTest4 = new CheckingModifierAdapterExtra(ALT);
 400     }
 401 
 402     public static void initVars(){
 403         //Init the array of the mouse button masks. It will be used for generating mouse events.
 404         mouseButtonDownMasks = new int [MouseInfo.getNumberOfButtons()];
 405         for (int i = 0; i < mouseButtonDownMasks.length; i++){
 406             mouseButtonDownMasks[i] = InputEvent.getMaskForButton(i+1);
 407             System.out.println("MouseArray [i] == "+mouseButtonDownMasks[i]);
 408         }
 409 
 410         // So we need to get the number of extra buttons on the mouse:  "MouseInfo.getNumberOfButtons() - 3"
 411         // and multyply on 3 because each button will generate three events : PRESS, RELEASE and CLICK.
 412         int [] tmp = new int [(MouseInfo.getNumberOfButtons()-3)*3];
 413 
 414         //Fill array of expected results for the case when mouse buttons are only used (no-modifier keys)
 415         Arrays.fill(tmp, 0);
 416         for (int i = 0, j = 3; i < tmp.length; i = i + 3, j++){
 417             tmp[i] = mouseButtonDownMasks[j];
 418         }
 419         modifiersExStandard = Arrays.copyOf(tmp, tmp.length);
 420 
 421         //Fill array of expected results for the case when mouse buttons are only used with SHIFT modifier key
 422         Arrays.fill(tmp, InputEvent.SHIFT_DOWN_MASK);
 423         for (int i = 0, j = 3; i < tmp.length; i = i + 3, j++){
 424             System.out.println("modifiersExStandardSHIFT FILLING : " + tmp[i] + " + " + mouseButtonDownMasks[j]);
 425             tmp[i] = tmp[i] | mouseButtonDownMasks[j];
 426         }
 427         modifiersExStandardSHIFT = Arrays.copyOf(tmp, tmp.length);
 428 
 429         //Fill array of expected results for the case when mouse buttons are only used with CTRL modifier key
 430         Arrays.fill(tmp, InputEvent.CTRL_DOWN_MASK);
 431         for (int i = 0, j = 3; i < tmp.length; i = i + 3, j++){
 432             System.out.println("modifiersExStandardCTRL FILLING : " + tmp[i] + " + " + mouseButtonDownMasks[j]);
 433             tmp[i] = tmp[i] | mouseButtonDownMasks[j];
 434         }
 435         modifiersExStandardCTRL = Arrays.copyOf(tmp, tmp.length);
 436 
 437         //Fill array of expected results for the case when mouse buttons are only used with ALT modifier key
 438         Arrays.fill(tmp, InputEvent.ALT_DOWN_MASK);
 439         for (int i = 0, j = 3; i < tmp.length; i = i + 3, j++){
 440             System.out.println("modifiersExStandardALT FILLING : " + tmp[i] + " + " + mouseButtonDownMasks[j]);
 441             tmp[i] = tmp[i] | mouseButtonDownMasks[j];
 442         }
 443         modifiersExStandardALT = Arrays.copyOf(tmp, tmp.length);
 444     }
 445 
 446     public static void main(String []s){
 447         if (MouseInfo.getNumberOfButtons() < 4){
 448             System.out.println("There are less then 4 buttons on the mouse. The test may not be accomplished. Skipping.");
 449             return;
 450         }
 451         initVars();
 452         MouseModifiersUnitTest_Extra frame = new MouseModifiersUnitTest_Extra();
 453         frame.initParams(s);
 454         frame.init();
 455         initAdapters();
 456         frame.start();
 457     }
 458 
 459 }// class
 460 
 461 /* A class that invoke appropriate verification
 462  * routine with current modifier.
 463  */
 464 class CheckingModifierAdapterExtra extends MouseAdapter{
 465     int modifier;
 466     public CheckingModifierAdapterExtra(int modifier){
 467         this.modifier = modifier;
 468     }
 469 
 470     public void mousePressed(MouseEvent e) {
 471         System.out.println("PRESSED "+e);
 472         if (e.getButton() <= MouseEvent.BUTTON3) {
 473             System.out.println("Standard button affected. Skip.");
 474         } else {
 475             MouseModifiersUnitTest_Extra.checkPressedModifiersTest(modifier, e);
 476         }
 477     }
 478     public void mouseReleased(MouseEvent e) {
 479         System.out.println("RELEASED "+e);
 480         if (e.getButton() <= MouseEvent.BUTTON3) {
 481             System.out.println("Standard button affected. Skip.");
 482         } else {
 483             MouseModifiersUnitTest_Extra.checkReleasedModifiersTest(modifier, e);
 484         }
 485     }
 486     public void mouseClicked(MouseEvent e) {
 487         System.out.println("CLICKED "+e);
 488         if (e.getButton() <= MouseEvent.BUTTON3) {
 489             System.out.println("Standard button affected. Skip.");
 490         } else {
 491             MouseModifiersUnitTest_Extra.checkClickedModifiersTest(modifier, e);
 492         }
 493     }
 494 }
 495 //Utility class that could report a message depending on current purpose of the test run
 496 class MessageLogger{
 497     private static boolean debug;
 498 
 499     public static void setDebug(boolean d){
 500         debug = d;
 501         log("Switch to "+ ((debug)?"debug":"trial") +" mode");
 502     }
 503 
 504     public static void log(String message){
 505         System.out.println(message);
 506     }
 507 
 508     public static void reportError(String message){
 509         if (debug){
 510             System.out.println(message);
 511         } else {
 512             throw new RuntimeException(message);
 513         }
 514     }
 515 }