8008366: [macosx] ActionListener called twice for JMenuItem using ScreenMenuBar
authorleonidr
Mon, 22 Apr 2013 19:24:41 +0400
changeset 17144 0c7842966236
parent 17143 8c04982f62b3
child 17145 ae4ad5910e3b
8008366: [macosx] ActionListener called twice for JMenuItem using ScreenMenuBar Reviewed-by: anthony, serb
jdk/src/macosx/native/sun/awt/AWTEvent.h
jdk/src/macosx/native/sun/awt/AWTEvent.m
jdk/src/macosx/native/sun/awt/CMenuItem.m
jdk/test/javax/swing/JMenuItem/ActionListenerCalledTwice/ActionListenerCalledTwiceTest.java
--- a/jdk/src/macosx/native/sun/awt/AWTEvent.h	Mon Apr 22 18:39:04 2013 +0400
+++ b/jdk/src/macosx/native/sun/awt/AWTEvent.h	Mon Apr 22 19:24:41 2013 +0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,5 +35,6 @@
 jint GetJavaMouseModifiers(NSInteger button, NSUInteger modifierFlags);
 jint NsKeyModifiersToJavaModifiers(NSUInteger nsFlags, BOOL isExtMods);
 NSUInteger JavaModifiersToNsKeyModifiers(jint javaModifiers, BOOL isExtMods);
+unichar NsCharToJavaChar(unichar nsChar, NSUInteger modifiers);
 
 #endif /* __AWTEVENT_H */
--- a/jdk/src/macosx/native/sun/awt/AWTEvent.m	Mon Apr 22 18:39:04 2013 +0400
+++ b/jdk/src/macosx/native/sun/awt/AWTEvent.m	Mon Apr 22 19:24:41 2013 +0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -341,8 +341,7 @@
     {0, 0, 0}
 };
 
-static unichar
-NsCharToJavaChar(unichar nsChar, NSUInteger modifiers)
+unichar NsCharToJavaChar(unichar nsChar, NSUInteger modifiers)
 {
     const struct _char *cur;
     // Mask off just the keyboard modifiers from the event modifier mask.
--- a/jdk/src/macosx/native/sun/awt/CMenuItem.m	Mon Apr 22 18:39:04 2013 +0400
+++ b/jdk/src/macosx/native/sun/awt/CMenuItem.m	Mon Apr 22 19:24:41 2013 +0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -71,12 +71,21 @@
 JNF_COCOA_ENTER(env);
 
     // If we are called as a result of user pressing a shorcut, do nothing,
-    // because AVTView has already sent corresponding key event to the Java 
+    // because AVTView has already sent corresponding key event to the Java
     // layer from performKeyEquivalent
     NSEvent *currEvent = [[NSApplication sharedApplication] currentEvent];
     if ([currEvent type] == NSKeyDown) {
         NSString *menuKey = [sender keyEquivalent];
         NSString *eventKey = [currEvent charactersIgnoringModifiers];
+
+        // Apple uses characters from private Unicode range for some of the
+        // keys, so we need to do the same translation here that we do
+        // for the regular key down events
+        if ([eventKey length] == 1) {
+            unichar ch =  NsCharToJavaChar([eventKey characterAtIndex:0], 0);
+            eventKey = [NSString stringWithCharacters: &ch length: 1];
+        }
+
         if ([menuKey isEqualToString:eventKey]) {
             return;
         }
--- a/jdk/test/javax/swing/JMenuItem/ActionListenerCalledTwice/ActionListenerCalledTwiceTest.java	Mon Apr 22 18:39:04 2013 +0400
+++ b/jdk/test/javax/swing/JMenuItem/ActionListenerCalledTwice/ActionListenerCalledTwiceTest.java	Mon Apr 22 19:24:41 2013 +0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,43 +35,72 @@
 import javax.swing.*;
 
 public class ActionListenerCalledTwiceTest {
+    static String menuItems[] = { "Item1", "Item2" };
+    static KeyStroke keyStrokes[] = {
+        KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.META_MASK),
+        KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0)
+    };
+
     static volatile int listenerCallCounter = 0;
     public static void main(String[] args) throws Exception {
         if (sun.awt.OSInfo.getOSType() != sun.awt.OSInfo.OSType.MACOSX) {
             System.out.println("This test is for MacOS only. Automatically passed on other platforms.");
             return;
         }
+
         System.setProperty("apple.laf.useScreenMenuBar", "true");
         SwingUtilities.invokeAndWait(new Runnable() {
             public void run() {
                 createAndShowGUI();
             }
         });
+
         SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit();
         Robot robot = new Robot();
         robot.setAutoDelay(100);
-        robot.keyPress(KeyEvent.VK_META);
-        robot.keyPress(KeyEvent.VK_E);
-        robot.keyRelease(KeyEvent.VK_E);
-        robot.keyRelease(KeyEvent.VK_META);
-        toolkit.realSync();
-        if (listenerCallCounter != 1) {
-            throw new Exception("Test failed: ActionListener called " + listenerCallCounter + " times instead of 1!");
+
+        for (int i = 0; i < menuItems.length; ++i) {
+            KeyStroke ks = keyStrokes[i];
+            int modKeyCode = getModKeyCode(ks.getModifiers());
+
+            if (modKeyCode != 0) {
+                robot.keyPress(modKeyCode);
+            }
+
+            robot.keyPress(ks.getKeyCode());
+            robot.keyRelease(ks.getKeyCode());
+
+            if (modKeyCode != 0) {
+                robot.keyRelease(modKeyCode);
+            }
+
+            toolkit.realSync();
+
+            if (listenerCallCounter != 1) {
+                throw new Exception("Test failed: ActionListener for " + menuItems[i] +
+                    " called " + listenerCallCounter + " times instead of 1!");
+            }
+
+            listenerCallCounter = 0;
         }
     }
 
     private static void createAndShowGUI() {
-        JMenuItem newItem = new JMenuItem("Exit");
-        newItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.META_MASK));
-        newItem.addActionListener(
-            new ActionListener(){
-                public void actionPerformed(ActionEvent e) {
-                    listenerCallCounter++;
+        JMenu menu = new JMenu("Menu");
+
+        for (int i = 0; i < menuItems.length; ++i) {
+            JMenuItem newItem = new JMenuItem(menuItems[i]);
+            newItem.setAccelerator(keyStrokes[i]);
+            newItem.addActionListener(
+                new ActionListener(){
+                    public void actionPerformed(ActionEvent e) {
+                        listenerCallCounter++;
+                    }
                 }
-            }
-        );
-        JMenu menu = new JMenu("Menu");
-        menu.add(newItem);
+            );
+            menu.add(newItem);
+        }
+
         JMenuBar bar = new JMenuBar();
         bar.add(menu);
         JFrame frame = new JFrame("Test");
@@ -80,4 +109,24 @@
         frame.pack();
         frame.setVisible(true);
     }
+
+    private static int getModKeyCode(int mod) {
+        if ((mod & (InputEvent.SHIFT_DOWN_MASK | InputEvent.SHIFT_MASK)) != 0) {
+            return KeyEvent.VK_SHIFT;
+        }
+
+        if ((mod & (InputEvent.CTRL_DOWN_MASK | InputEvent.CTRL_MASK)) != 0) {
+            return KeyEvent.VK_CONTROL;
+        }
+
+        if ((mod & (InputEvent.ALT_DOWN_MASK | InputEvent.ALT_MASK)) != 0) {
+            return KeyEvent.VK_ALT;
+        }
+
+        if ((mod & (InputEvent.META_DOWN_MASK | InputEvent.META_MASK)) != 0) {
+            return KeyEvent.VK_META;
+        }
+
+        return 0;
+    }
 }