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