OpenJDK / portola / portola
changeset 38384:05e90f2c9ab8
8152492: [macosx swing] double key event actions when using Mac menubar
Reviewed-by: serb, mhalder, alexsch
author | aniyogi |
---|---|
date | Wed, 27 Apr 2016 12:08:37 +0400 |
parents | c76fffbf4ef5 |
children | 218b99b653c4 |
files | jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.m jdk/test/javax/swing/JMenuItem/ActionListenerCalledTwice/ActionListenerCalledTwiceTest.java |
diffstat | 2 files changed, 59 insertions(+), 87 deletions(-) [+] |
line wrap: on
line diff
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.m Mon Apr 25 19:14:30 2016 +0300 +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.m Wed Apr 27 12:08:37 2016 +0400 @@ -25,7 +25,6 @@ #import <JavaNativeFoundation/JavaNativeFoundation.h> #include <Carbon/Carbon.h> - #import "CMenuItem.h" #import "CMenu.h" #import "AWTEvent.h" @@ -64,42 +63,6 @@ - (BOOL) worksWhenModal { return YES; } -// This is a method written using Carbon framework methods to remove -// All modifiers including "Shift" modifier. -// Example 1: Shortcut set is "Command Shift m" returns "m" -// Example 2: Shortcut set is "Command m" returns "m" -// Example 3: Shortcut set is "Alt Shift ," returns "," - -CFStringRef createStringForKey(CGKeyCode keyCode) -{ - TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource(); -// currentKeyboard now contains the current input source - CFDataRef layoutData = - TISGetInputSourceProperty(currentKeyboard, - kTISPropertyUnicodeKeyLayoutData); -// the UNICODE keyLayout is fetched from currentKeyboard in layoutData - const UCKeyboardLayout *keyboardLayout = - (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData); -// A read-only data pointer is fetched from layoutData - UInt32 keysDown = 0; - UniChar chars[4]; - UniCharCount realLength; - - UCKeyTranslate(keyboardLayout, - keyCode, - kUCKeyActionDisplay, - 0, - LMGetKbdType(), - kUCKeyTranslateNoDeadKeysBit, - &keysDown, - sizeof(chars) / sizeof(chars[0]), - &realLength, - chars); - CFRelease(currentKeyboard); -// Converts keyCode, modifier and dead-key state into UNICODE characters - return CFStringCreateWithCharacters(kCFAllocatorDefault, chars, 1); -} - // Events - (void)handleAction:(NSMenuItem *)sender { AWT_ASSERT_APPKIT_THREAD; @@ -116,35 +79,6 @@ // from this "frameless" menu, because there are no active windows. This // means we have to handle it here. NSEvent *currEvent = [[NSApplication sharedApplication] currentEvent]; - if ([currEvent type] == NSKeyDown) { - NSString *menuKey = [sender keyEquivalent]; -// If shortcut is "Command Shift ," the menuKey gets the value "," -// But [currEvent charactersIgnoringModifiers]; returns "<" and not "," -// because the charactersIgnoreingModifiers does not ignore "Shift" -// So a shortcut like "Command Shift m" will return "M" where as the -// MenuKey will have the value "m". To remove this issue the below -// createStringForKey is used. - NSString *eventKey = createStringForKey([currEvent keyCode]); - -// 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 origChar = [eventKey characterAtIndex:0]; - unichar newChar = NsCharToJavaChar(origChar, 0); - if (newChar == java_awt_event_KeyEvent_CHAR_UNDEFINED) { - newChar = origChar; - } - - eventKey = [NSString stringWithCharacters: &newChar length: 1]; - } - - NSWindow *keyWindow = [NSApp keyWindow]; - if ([menuKey isEqualToString:eventKey] && keyWindow != nil) { - return; - } - } - if (fIsCheckbox) { static JNF_CLASS_CACHE(jc_CCheckboxMenuItem, "sun/lwawt/macosx/CCheckboxMenuItem"); static JNF_MEMBER_CACHE(jm_ckHandleAction, jc_CCheckboxMenuItem, "handleAction", "(Z)V"); @@ -154,16 +88,47 @@ NSInteger state = [sender state]; jboolean newState = (state == NSOnState ? JNI_FALSE : JNI_TRUE); JNFCallVoidMethod(env, fPeer, jm_ckHandleAction, newState); - } else { - static JNF_CLASS_CACHE(jc_CMenuItem, "sun/lwawt/macosx/CMenuItem"); - static JNF_MEMBER_CACHE(jm_handleAction, jc_CMenuItem, "handleAction", "(JI)V"); // AWT_THREADING Safe (event) - - NSUInteger modifiers = [currEvent modifierFlags]; - jint javaModifiers = NsKeyModifiersToJavaModifiers(modifiers, NO); - - JNFCallVoidMethod(env, fPeer, jm_handleAction, UTC(currEvent), javaModifiers); // AWT_THREADING Safe (event) + } + else { + if ([currEvent type] == NSKeyDown) { + + // Event available through sender variable hence NSApplication + // not needed for checking the keyboard input sans the modifier keys + // Also, the method used to fetch eventKey earlier would be locale dependent + // With earlier implementation, if MenuKey: e EventKey: ा ; if input method + // is not U.S. (Devanagari in this case) + // With current implementation, EventKey = MenuKey = e irrespective of + // input method + + NSString *eventKey = [sender keyEquivalent]; + // 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 origChar = [eventKey characterAtIndex:0]; + unichar newChar = NsCharToJavaChar(origChar, 0); + if (newChar == java_awt_event_KeyEvent_CHAR_UNDEFINED) { + newChar = origChar; + } + eventKey = [NSString stringWithCharacters: &newChar length: 1]; + } + NSWindow *keyWindow = [NSApp keyWindow]; + if (keyWindow != nil) { + return; + } + else { + static JNF_CLASS_CACHE(jc_CMenuItem, "sun/lwawt/macosx/CMenuItem"); + static JNF_MEMBER_CACHE(jm_handleAction, jc_CMenuItem, "handleAction", "(JI)V"); // AWT_THREADING Safe (event) + + NSUInteger modifiers = [currEvent modifierFlags]; + jint javaModifiers = NsKeyModifiersToJavaModifiers(modifiers, NO); + + JNFCallVoidMethod(env, fPeer, jm_handleAction, UTC(currEvent), javaModifiers); // AWT_THREADING Safe (event) + } + } } JNF_COCOA_EXIT(env); + } - (void) setJavaLabel:(NSString *)theLabel shortcut:(NSString *)theKeyEquivalent modifierMask:(jint)modifiers {
--- a/jdk/test/javax/swing/JMenuItem/ActionListenerCalledTwice/ActionListenerCalledTwiceTest.java Mon Apr 25 19:14:30 2016 +0300 +++ b/jdk/test/javax/swing/JMenuItem/ActionListenerCalledTwice/ActionListenerCalledTwiceTest.java Wed Apr 27 12:08:37 2016 +0400 @@ -21,23 +21,23 @@ * questions. */ -/* + /* * @test - * @bug 7160951 + * @bug 7160951 8152492 * @summary [macosx] ActionListener called twice for JMenuItem using ScreenMenuBar * @author vera.akulova@oracle.com * @library ../../../../lib/testlibrary * @build jdk.testlibrary.OSInfo * @run main ActionListenerCalledTwiceTest */ - import jdk.testlibrary.OSInfo; import java.awt.*; import java.awt.event.*; import javax.swing.*; public class ActionListenerCalledTwiceTest { - static String menuItems[] = { "Item1", "Item2", "Item3", "Item4", "Item5", "Item6" }; + + static String menuItems[] = {"Item1", "Item2", "Item3", "Item4", "Item5", "Item6"}; static KeyStroke keyStrokes[] = { KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.META_MASK), KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), @@ -46,8 +46,10 @@ KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.CTRL_MASK), KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, InputEvent.META_MASK) }; + static JMenu menu; + static JFrame frame; + static volatile int listenerCallCounter = 0; - static volatile int listenerCallCounter = 0; public static void main(String[] args) throws Exception { if (OSInfo.getOSType() != OSInfo.OSType.MACOSX) { System.out.println("This test is for MacOS only. Automatically passed on other platforms."); @@ -82,33 +84,38 @@ robot.waitForIdle(); if (listenerCallCounter != 1) { - throw new Exception("Test failed: ActionListener for " + menuItems[i] + - " called " + listenerCallCounter + " times instead of 1!"); + throw new Exception("Test failed: ActionListener for " + menuItems[i] + + " called " + listenerCallCounter + " times instead of 1!"); } listenerCallCounter = 0; } + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame.dispose(); + } + }); } private static void createAndShowGUI() { - JMenu menu = new JMenu("Menu"); + 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++; - } + new ActionListener() { + public void actionPerformed(ActionEvent e) { + listenerCallCounter++; } + } ); menu.add(newItem); } JMenuBar bar = new JMenuBar(); bar.add(menu); - JFrame frame = new JFrame("Test"); + frame = new JFrame("Test"); frame.setJMenuBar(bar); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack();