8000626: Implement dead key detection for KeyEvent on Linux
authoralexsch
Wed, 17 Oct 2012 10:16:26 -0400
changeset 14163 87f1bc730fe2
parent 14162 a78ee9af4a48
child 14164 8c51259d0843
8000626: Implement dead key detection for KeyEvent on Linux Reviewed-by: kizune
jdk/src/solaris/classes/sun/awt/X11/XKeysym.java
jdk/src/solaris/classes/sun/awt/X11/XWindow.java
jdk/src/solaris/classes/sun/awt/X11/keysym2ucs.h
--- a/jdk/src/solaris/classes/sun/awt/X11/XKeysym.java	Wed Oct 17 17:33:26 2012 +0400
+++ b/jdk/src/solaris/classes/sun/awt/X11/XKeysym.java	Wed Oct 17 10:16:26 2012 -0400
@@ -379,6 +379,25 @@
         keysym2UCSHash.put( (long)0xFFB8, (char)0x0038); // XK_KP_8 --> DIGIT EIGHT
         keysym2UCSHash.put( (long)0xFFB9, (char)0x0039); // XK_KP_9 --> DIGIT NINE
         keysym2UCSHash.put( (long)0xFE20, (char)0x0009); // XK_ISO_Left_Tab --> <control>
+        keysym2UCSHash.put( (long)0xFE50, (char)0x02CB); // XK_dead_grave --> MODIFIER LETTER GRAVE ACCENT
+        keysym2UCSHash.put( (long)0xFE51, (char)0x02CA); // XK_dead_acute --> MODIFIER LETTER ACUTE ACCENT
+        keysym2UCSHash.put( (long)0xFE52, (char)0x02C6); // XK_dead_circumflex --> MODIFIER LETTER CIRCUMFLEX ACCENT
+        keysym2UCSHash.put( (long)0xFE53, (char)0x02DC); // XK_dead_tilde --> SMALL TILDE
+        keysym2UCSHash.put( (long)0xFE54, (char)0x02C9); // XK_dead_macron --> MODIFIER LETTER MACRON
+        keysym2UCSHash.put( (long)0xFE55, (char)0x02D8); // XK_dead_breve --> BREVE
+        keysym2UCSHash.put( (long)0xFE56, (char)0x02D9); // XK_dead_abovedot --> DOT ABOVE
+        keysym2UCSHash.put( (long)0xFE57, (char)0x00A8); // XK_dead_diaeresis --> DIAERESIS
+        keysym2UCSHash.put( (long)0xFE58, (char)0x02DA); // XK_dead_abovering --> RING ABOVE
+        keysym2UCSHash.put( (long)0xFE59, (char)0x02DD); // XK_dead_doubleacute --> DOUBLE ACUTE ACCENT
+        keysym2UCSHash.put( (long)0xFE5A, (char)0x02C7); // XK_dead_caron --> CARON
+        keysym2UCSHash.put( (long)0xFE5B, (char)0x00B8); // XK_dead_cedilla --> CEDILLA
+        keysym2UCSHash.put( (long)0xFE5C, (char)0x02DB); // XK_dead_ogonek --> OGONEK
+        keysym2UCSHash.put( (long)0xFE5D, (char)0x0269); // XK_dead_iota --> LATIN SMALL LETTER IOTA
+        keysym2UCSHash.put( (long)0xFE5E, (char)0x3099); // XK_dead_voiced_sound --> COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK
+        keysym2UCSHash.put( (long)0xFE5F, (char)0x309A); // XK_dead_semivoiced_sound --> COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+        keysym2UCSHash.put( (long)0xFE60, (char)0x0323); // XK_dead_belowdot --> COMBINING DOT BELOW
+        keysym2UCSHash.put( (long)0xFE61, (char)0x0321); // XK_dead_hook --> COMBINING PALATALIZED HOOK BELOW
+        keysym2UCSHash.put( (long)0xFE62, (char)0x031B); // XK_dead_horn --> COMBINING HORN
         keysym2UCSHash.put( (long)0x1a1, (char)0x0104); // XK_Aogonek --> LATIN CAPITAL LETTER A WITH OGONEK
         keysym2UCSHash.put( (long)0x1a2, (char)0x02d8); // XK_breve --> BREVE
         keysym2UCSHash.put( (long)0x1a3, (char)0x0141); // XK_Lstroke --> LATIN CAPITAL LETTER L WITH STROKE
--- a/jdk/src/solaris/classes/sun/awt/X11/XWindow.java	Wed Oct 17 17:33:26 2012 +0400
+++ b/jdk/src/solaris/classes/sun/awt/X11/XWindow.java	Wed Oct 17 10:16:26 2012 -0400
@@ -1115,7 +1115,10 @@
         //  (1) either XIM could not handle it or
         //  (2) it was Latin 1:1 mapping.
         //
-        XKeysym.Keysym2JavaKeycode jkc = XKeysym.getJavaKeycode(ev);
+        // Preserve modifiers to get Java key code for dead keys
+        boolean isDeadKey = isDeadKey(keysym[0]);
+        XKeysym.Keysym2JavaKeycode jkc = isDeadKey ? XKeysym.getJavaKeycode(keysym[0])
+                : XKeysym.getJavaKeycode(ev);
         if( jkc == null ) {
             jkc = new XKeysym.Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_UNDEFINED, java.awt.event.KeyEvent.KEY_LOCATION_UNKNOWN);
         }
@@ -1141,7 +1144,7 @@
                              jkc.getJavaKeycode();
         postKeyEvent( java.awt.event.KeyEvent.KEY_PRESSED,
                           ev.get_time(),
-                          jkeyToReturn,
+                          isDeadKey ? jkeyExtended : jkeyToReturn,
                           (unicodeKey == 0 ? java.awt.event.KeyEvent.CHAR_UNDEFINED : unicodeKey),
                           jkc.getKeyLocation(),
                           ev.get_state(),ev.getPData(), XKeyEvent.getSize(), (long)(ev.get_keycode()),
@@ -1149,7 +1152,7 @@
                           jkeyExtended);
 
 
-        if( unicodeKey > 0 ) {
+        if (unicodeKey > 0 && !isDeadKey) {
                 keyEventLog.fine("fire _TYPED on "+unicodeKey);
                 postKeyEvent( java.awt.event.KeyEvent.KEY_TYPED,
                               ev.get_time(),
@@ -1176,9 +1179,7 @@
     }
     // un-private it if you need to call it from elsewhere
     private void handleKeyRelease(XKeyEvent ev) {
-        long keysym[] = new long[2];
         int unicodeKey = 0;
-        keysym[0] = XConstants.NoSymbol;
 
         if (keyEventLog.isLoggable(PlatformLogger.FINE)) {
             logIncomingKeyEvent( ev );
@@ -1187,7 +1188,11 @@
         // and Java KeyEvent keycode should be calculated.
         // For release we should post released event.
         //
-        XKeysym.Keysym2JavaKeycode jkc = XKeysym.getJavaKeycode(ev);
+        // Preserve modifiers to get Java key code for dead keys
+        long keysym = xkeycodeToKeysym(ev);
+        boolean isDeadKey = isDeadKey(keysym);
+        XKeysym.Keysym2JavaKeycode jkc = isDeadKey ? XKeysym.getJavaKeycode(keysym)
+                : XKeysym.getJavaKeycode(ev);
         if( jkc == null ) {
             jkc = new XKeysym.Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_UNDEFINED, java.awt.event.KeyEvent.KEY_LOCATION_UNKNOWN);
         }
@@ -1219,7 +1224,7 @@
                              jkc.getJavaKeycode();
         postKeyEvent(  java.awt.event.KeyEvent.KEY_RELEASED,
                           ev.get_time(),
-                          jkeyToReturn,
+                          isDeadKey ? jkeyExtended : jkeyToReturn,
                           (unicodeKey == 0 ? java.awt.event.KeyEvent.CHAR_UNDEFINED : unicodeKey),
                           jkc.getKeyLocation(),
                           ev.get_state(),ev.getPData(), XKeyEvent.getSize(), (long)(ev.get_keycode()),
@@ -1229,6 +1234,11 @@
 
     }
 
+
+    private boolean isDeadKey(long keysym){
+        return XKeySymConstants.XK_dead_grave <= keysym && keysym <= XKeySymConstants.XK_dead_semivoiced_sound;
+    }
+
     /*
      * XmNiconic and Map/UnmapNotify (that XmNiconic relies on) are
      * unreliable, since mapping changes can happen for a virtual desktop
--- a/jdk/src/solaris/classes/sun/awt/X11/keysym2ucs.h	Wed Oct 17 17:33:26 2012 +0400
+++ b/jdk/src/solaris/classes/sun/awt/X11/keysym2ucs.h	Wed Oct 17 10:16:26 2012 -0400
@@ -695,25 +695,25 @@
 0x0000 #define    XK_ISO_Center_Object                0xFE33
 0x0000 #define    XK_ISO_Enter                    0xFE34
 
-0x0000 #define    XK_dead_grave                    0xFE50
-0x0000 #define    XK_dead_acute                    0xFE51
-0x0000 #define    XK_dead_circumflex                0xFE52
-0x0000 #define    XK_dead_tilde                    0xFE53
-0x0000 #define    XK_dead_macron                    0xFE54
-0x0000 #define    XK_dead_breve                    0xFE55
-0x0000 #define    XK_dead_abovedot                0xFE56
-0x0000 #define    XK_dead_diaeresis                0xFE57
-0x0000 #define    XK_dead_abovering                0xFE58
-0x0000 #define    XK_dead_doubleacute                0xFE59
-0x0000 #define    XK_dead_caron                    0xFE5A
-0x0000 #define    XK_dead_cedilla                    0xFE5B
-0x0000 #define    XK_dead_ogonek                    0xFE5C
-0x0000 #define    XK_dead_iota                    0xFE5D
-0x0000 #define    XK_dead_voiced_sound                0xFE5E
-0x0000 #define    XK_dead_semivoiced_sound            0xFE5F
-0x0000 #define    XK_dead_belowdot                0xFE60
-0x0000 #define XK_dead_hook                    0xFE61
-0x0000 #define XK_dead_horn                    0xFE62
+0x02CB #define    XK_dead_grave                    0xFE50
+0x02CA #define    XK_dead_acute                    0xFE51
+0x02C6 #define    XK_dead_circumflex                0xFE52
+0x02DC #define    XK_dead_tilde                    0xFE53
+0x02C9 #define    XK_dead_macron                    0xFE54
+0x02D8 #define    XK_dead_breve                    0xFE55
+0x02D9 #define    XK_dead_abovedot                0xFE56
+0x00A8 #define    XK_dead_diaeresis                0xFE57
+0x02DA #define    XK_dead_abovering                0xFE58
+0x02DD #define    XK_dead_doubleacute                0xFE59
+0x02C7 #define    XK_dead_caron                    0xFE5A
+0x00B8 #define    XK_dead_cedilla                    0xFE5B
+0x02DB #define    XK_dead_ogonek                    0xFE5C
+0x0269 #define    XK_dead_iota                    0xFE5D
+0x3099 #define    XK_dead_voiced_sound                0xFE5E
+0x309A #define    XK_dead_semivoiced_sound            0xFE5F
+0x0323 #define    XK_dead_belowdot                0xFE60
+0x0321 #define XK_dead_hook                    0xFE61
+0x031B #define XK_dead_horn                    0xFE62
 
 0x0000 #define    XK_First_Virtual_Screen                0xFED0
 0x0000 #define    XK_Prev_Virtual_Screen                0xFED1
@@ -2466,6 +2466,7 @@
 tojava         keysym2JavaKeycodeHash.put( Long.valueOf(XKeySymConstants.XK_Meta_L),     new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_META, java.awt.event.KeyEvent.KEY_LOCATION_LEFT));
 tojava         keysym2JavaKeycodeHash.put( Long.valueOf(XKeySymConstants.XK_Meta_R),     new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_META, java.awt.event.KeyEvent.KEY_LOCATION_RIGHT));
 tojava         keysym2JavaKeycodeHash.put( Long.valueOf(XKeySymConstants.XK_Caps_Lock),     new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_CAPS_LOCK, java.awt.event.KeyEvent.KEY_LOCATION_STANDARD));
+tojava         keysym2JavaKeycodeHash.put( Long.valueOf(XKeySymConstants.XK_Shift_Lock),     new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_CAPS_LOCK, java.awt.event.KeyEvent.KEY_LOCATION_STANDARD));
 tojava
 tojava             /* Misc Functions */
 tojava         keysym2JavaKeycodeHash.put( Long.valueOf(XKeySymConstants.XK_Print),     new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_PRINTSCREEN, java.awt.event.KeyEvent.KEY_LOCATION_STANDARD));
@@ -2640,6 +2641,21 @@
 tojava         keysym2JavaKeycodeHash.put( Long.valueOf(XKeySymConstants.XK_Kanji),     new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_CONVERT, java.awt.event.KeyEvent.KEY_LOCATION_STANDARD));
 tojava             /* Type 5c Japanese keyboard: nihongo */
 tojava         keysym2JavaKeycodeHash.put( Long.valueOf(XKeySymConstants.XK_Henkan_Mode),     new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_INPUT_METHOD_ON_OFF, java.awt.event.KeyEvent.KEY_LOCATION_STANDARD));
+tojava         keysym2JavaKeycodeHash.put( Long.valueOf(XKeySymConstants.XK_Eisu_Shift   ), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_ALPHANUMERIC       , java.awt.event.KeyEvent.KEY_LOCATION_STANDARD));
+tojava         keysym2JavaKeycodeHash.put( Long.valueOf(XKeySymConstants.XK_Eisu_toggle  ), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_ALPHANUMERIC       , java.awt.event.KeyEvent.KEY_LOCATION_STANDARD));
+tojava         keysym2JavaKeycodeHash.put( Long.valueOf(XKeySymConstants.XK_Zenkaku      ), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_FULL_WIDTH         , java.awt.event.KeyEvent.KEY_LOCATION_STANDARD));
+tojava         keysym2JavaKeycodeHash.put( Long.valueOf(XKeySymConstants.XK_Hankaku      ), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_HALF_WIDTH         , java.awt.event.KeyEvent.KEY_LOCATION_STANDARD));
+tojava         keysym2JavaKeycodeHash.put( Long.valueOf(XKeySymConstants.XK_Hiragana     ), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_HIRAGANA           , java.awt.event.KeyEvent.KEY_LOCATION_STANDARD));
+tojava         keysym2JavaKeycodeHash.put( Long.valueOf(XKeySymConstants.XK_Katakana     ), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_KATAKANA           , java.awt.event.KeyEvent.KEY_LOCATION_STANDARD));
+tojava         keysym2JavaKeycodeHash.put( Long.valueOf(XKeySymConstants.XK_Romaji       ), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_JAPANESE_ROMAN     , java.awt.event.KeyEvent.KEY_LOCATION_STANDARD));
+tojava         keysym2JavaKeycodeHash.put( Long.valueOf(XKeySymConstants.XK_Kana_Shift   ), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_KANA               , java.awt.event.KeyEvent.KEY_LOCATION_STANDARD));
+tojava         keysym2JavaKeycodeHash.put( Long.valueOf(XKeySymConstants.XK_Kana_Lock    ), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_KANA_LOCK          , java.awt.event.KeyEvent.KEY_LOCATION_STANDARD));
+tojava         keysym2JavaKeycodeHash.put( Long.valueOf(XKeySymConstants.XK_Muhenkan     ), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_NONCONVERT         , java.awt.event.KeyEvent.KEY_LOCATION_STANDARD));
+tojava         keysym2JavaKeycodeHash.put( Long.valueOf(XKeySymConstants.XK_Zen_Koho     ), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_ALL_CANDIDATES     , java.awt.event.KeyEvent.KEY_LOCATION_STANDARD));
+tojava         keysym2JavaKeycodeHash.put( Long.valueOf(XKeySymConstants.XK_Kanji_Bangou ), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_CODE_INPUT         , java.awt.event.KeyEvent.KEY_LOCATION_STANDARD));
+tojava         keysym2JavaKeycodeHash.put( Long.valueOf(XKeySymConstants.XK_Mae_Koho     ), new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_PREVIOUS_CANDIDATE , java.awt.event.KeyEvent.KEY_LOCATION_STANDARD));
+tojava
+tojava
 tojava             /* VK_KANA_LOCK is handled separately because it generates the
 tojava              * same keysym as ALT_GRAPH in spite of its different behavior.
 tojava              */