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