5099725: AWT doesn't seem to handle MappingNotify events under X11.
authoryan
Mon, 07 Dec 2009 13:32:50 +0300
changeset 4370 cc409c51b108
parent 4369 18b883ed2b58
child 4372 5d8e826073e1
5099725: AWT doesn't seem to handle MappingNotify events under X11. 5036807: Pressing action keys "STOP/AGAIN/COMPOSE" generates keycode of F11/F12 keys. 4787377: VK_STOP key on Solaris generates wrong Key Code Summary: Added an event processing lumped with similar native code for similar bugs. Reviewed-by: art
jdk/make/sun/xawt/mapfile-vers
jdk/src/solaris/classes/sun/awt/X11/XEmbedHelper.java
jdk/src/solaris/classes/sun/awt/X11/XKeysym.java
jdk/src/solaris/classes/sun/awt/X11/XToolkit.java
jdk/src/solaris/classes/sun/awt/X11/XlibWrapper.java
jdk/src/solaris/classes/sun/awt/X11/keysym2ucs.h
jdk/src/solaris/native/sun/xawt/XlibWrapper.c
--- a/jdk/make/sun/xawt/mapfile-vers	Fri Dec 04 15:07:15 2009 +0300
+++ b/jdk/make/sun/xawt/mapfile-vers	Mon Dec 07 13:32:50 2009 +0300
@@ -126,6 +126,8 @@
         Java_sun_awt_X11_XlibWrapper_ServerVendor;
         Java_sun_awt_X11_XlibWrapper_VendorRelease;
         Java_sun_awt_X11_XlibWrapper_IsXsunKPBehavior;
+        Java_sun_awt_X11_XlibWrapper_IsSunKeyboard;
+        Java_sun_awt_X11_XlibWrapper_IsKanaKeyboard;
         Java_sun_awt_X11_XlibWrapper_SetToolkitErrorHandler;
         Java_sun_awt_X11_XlibWrapper_XSetErrorHandler;
         Java_sun_awt_X11_XlibWrapper_CallErrorHandler;
@@ -306,6 +308,7 @@
         Java_sun_awt_X11_XlibWrapper_XkbTranslateKeyCode;
         Java_sun_awt_X11_XlibWrapper_XGetModifierMapping;
         Java_sun_awt_X11_XlibWrapper_XFreeModifiermap;
+        Java_sun_awt_X11_XlibWrapper_XRefreshKeyboardMapping;
         Java_sun_awt_X11_XlibWrapper_XChangeActivePointerGrab;
         Java_sun_awt_X11_XlibWrapper_XNextSecondaryLoopEvent;
         Java_sun_awt_X11_XlibWrapper_ExitSecondaryLoop;
--- a/jdk/src/solaris/classes/sun/awt/X11/XEmbedHelper.java	Fri Dec 04 15:07:15 2009 +0300
+++ b/jdk/src/solaris/classes/sun/awt/X11/XEmbedHelper.java	Mon Dec 07 13:32:50 2009 +0300
@@ -216,7 +216,12 @@
 
         XToolkit.awtLock();
         try {
-            keycode = XWindow.getAWTKeyCodeForKeySym((int)keysym);
+            XKeysym.Keysym2JavaKeycode kc = XKeysym.getJavaKeycode( keysym );
+            if(kc == null) {
+                keycode = java.awt.event.KeyEvent.VK_UNDEFINED;
+            }else{
+                keycode = kc.getJavaKeycode();
+            }
         } finally {
             XToolkit.awtUnlock();
         }
--- a/jdk/src/solaris/classes/sun/awt/X11/XKeysym.java	Fri Dec 04 15:07:15 2009 +0300
+++ b/jdk/src/solaris/classes/sun/awt/X11/XKeysym.java	Mon Dec 07 13:32:50 2009 +0300
@@ -69,6 +69,8 @@
     static Hashtable<Integer, Long> javaKeycode2KeysymHash = new Hashtable<Integer, Long>();
     static long keysym_lowercase = unsafe.allocateMemory(Native.getLongSize());
     static long keysym_uppercase = unsafe.allocateMemory(Native.getLongSize());
+    static Keysym2JavaKeycode kanaLock = new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_KANA_LOCK,
+                                                                java.awt.event.KeyEvent.KEY_LOCATION_STANDARD);
     private static PlatformLogger keyEventLog = PlatformLogger.getLogger("sun.awt.X11.kye.XKeysym");
     public static char convertKeysym( long ks, int state ) {
 
@@ -214,12 +216,35 @@
         }
         return keysym;
     }
+
+    /**
+        Return java.awt.KeyEvent constant meaning (Java) keycode, derived from X keysym.
+        Some keysyms maps to more than one keycode, these would require extra processing.
+    */
+    static Keysym2JavaKeycode getJavaKeycode( long keysym ) {
+        if(keysym == XKeySymConstants.XK_Mode_switch){
+           /* XK_Mode_switch on solaris maps either to VK_ALT_GRAPH (default) or VK_KANA_LOCK */
+           if( XToolkit.isKanaKeyboard() ) {
+               return kanaLock;
+           }
+        }else if(keysym == XKeySymConstants.XK_L1){
+           /* if it is Sun keyboard, trick hash to return VK_STOP else VK_F11 (default) */
+           if( XToolkit.isSunKeyboard() ) {
+               keysym = XKeySymConstants.SunXK_Stop;
+           }
+        }else if(keysym == XKeySymConstants.XK_L2) {
+           /* if it is Sun keyboard, trick hash to return VK_AGAIN else VK_F12 (default) */
+           if( XToolkit.isSunKeyboard() ) {
+               keysym = XKeySymConstants.SunXK_Again;
+           }
+        }
+
+        return  keysym2JavaKeycodeHash.get( keysym );
+    }
     /**
         Return java.awt.KeyEvent constant meaning (Java) keycode, derived from X Window KeyEvent.
         Algorithm is, extract via XKeycodeToKeysym  a proper keysym according to Xlib spec rules and
         err exceptions, then search a java keycode in a table.
-        Some keysyms maps to more than one keycode, these would require extra processing. If someone
-        points me to such a keysym.
     */
     static Keysym2JavaKeycode getJavaKeycode( XKeyEvent ev ) {
         // get from keysym2JavaKeycodeHash.
@@ -234,7 +259,7 @@
             keysym = xkeycode2keysym(ev, ndx);
         }
 
-        Keysym2JavaKeycode jkc = keysym2JavaKeycodeHash.get( keysym );
+        Keysym2JavaKeycode jkc = getJavaKeycode( keysym );
         return jkc;
     }
     static int getJavaKeycodeOnly( XKeyEvent ev ) {
@@ -259,7 +284,7 @@
             ndx = 0;
             keysym = xkeycode2keysym_noxkb(ev, ndx);
         }
-        Keysym2JavaKeycode jkc = keysym2JavaKeycodeHash.get( keysym );
+        Keysym2JavaKeycode jkc = getJavaKeycode( keysym );
         return jkc == null ? java.awt.event.KeyEvent.VK_UNDEFINED : jkc.getJavaKeycode();
     }
     static long javaKeycode2Keysym( int jkey ) {
--- a/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java	Fri Dec 04 15:07:15 2009 +0300
+++ b/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java	Mon Dec 07 13:32:50 2009 +0300
@@ -533,6 +533,16 @@
             processGlobalMotionEvent(ev);
         }
 
+        if( ev.get_type() == XConstants.MappingNotify ) {
+            // The 'window' field in this event is unused.
+            // This application itself does nothing to initiate such an event
+            // (no calls of XChangeKeyboardMapping etc.).
+            // SunRay server sends this event to the application once on every
+            // keyboard (not just layout) change which means, quite seldom.
+            XlibWrapper.XRefreshKeyboardMapping(ev.pData);
+            resetKeyboardSniffer();
+            setupModifierMap();
+        }
         XBaseWindow.dispatchToWindow(ev);
 
         Collection dispatchers = null;
@@ -2112,6 +2122,11 @@
 
     static final int XSUN_KP_BEHAVIOR = 1;
     static final int XORG_KP_BEHAVIOR = 2;
+    static final int    IS_SUN_KEYBOARD = 1;
+    static final int IS_NONSUN_KEYBOARD = 2;
+    static final int    IS_KANA_KEYBOARD = 1;
+    static final int IS_NONKANA_KEYBOARD = 2;
+
 
     static int     awt_IsXsunKPBehavior = 0;
     static boolean awt_UseXKB         = false;
@@ -2141,6 +2156,33 @@
             awtUnlock();
         }
     }
+
+    static int  sunOrNotKeyboard = 0;
+    static int kanaOrNotKeyboard = 0;
+    static void resetKeyboardSniffer() {
+        sunOrNotKeyboard  = 0;
+        kanaOrNotKeyboard = 0;
+    }
+    static boolean isSunKeyboard() {
+        if( sunOrNotKeyboard == 0 ) {
+            if( XlibWrapper.IsSunKeyboard( getDisplay() )) {
+                sunOrNotKeyboard = IS_SUN_KEYBOARD;
+            }else{
+                sunOrNotKeyboard = IS_NONSUN_KEYBOARD;
+            }
+        }
+        return (sunOrNotKeyboard == IS_SUN_KEYBOARD);
+    }
+    static boolean isKanaKeyboard() {
+        if( kanaOrNotKeyboard == 0 ) {
+            if( XlibWrapper.IsKanaKeyboard( getDisplay() )) {
+                kanaOrNotKeyboard = IS_KANA_KEYBOARD;
+            }else{
+                kanaOrNotKeyboard = IS_NONKANA_KEYBOARD;
+            }
+        }
+        return (kanaOrNotKeyboard == IS_KANA_KEYBOARD);
+    }
     static boolean isXKBenabled() {
         awtLock();
         try {
--- a/jdk/src/solaris/classes/sun/awt/X11/XlibWrapper.java	Fri Dec 04 15:07:15 2009 +0300
+++ b/jdk/src/solaris/classes/sun/awt/X11/XlibWrapper.java	Mon Dec 07 13:32:50 2009 +0300
@@ -353,6 +353,8 @@
     static native String ServerVendor(long display);
     static native int VendorRelease(long display);
     static native boolean IsXsunKPBehavior(long display);
+    static native boolean IsSunKeyboard(long display);
+    static native boolean IsKanaKeyboard(long display);
 
     static native void XBell(long display, int percent);
 
@@ -513,8 +515,9 @@
                                     long keysym_uppercase);
 
     static native long XGetModifierMapping(long display);
+    static native void XFreeModifiermap(long keymap);
+    static native void XRefreshKeyboardMapping(long event);
 
-    static native void XFreeModifiermap(long keymap);
 
     static native void XChangeActivePointerGrab(long display, int mask,
                                                 long cursor, long time);
--- a/jdk/src/solaris/classes/sun/awt/X11/keysym2ucs.h	Fri Dec 04 15:07:15 2009 +0300
+++ b/jdk/src/solaris/classes/sun/awt/X11/keysym2ucs.h	Mon Dec 07 13:32:50 2009 +0300
@@ -107,6 +107,8 @@
 tojava     static Hashtable<Integer, Long> javaKeycode2KeysymHash = new Hashtable<Integer, Long>();
 tojava     static long keysym_lowercase = unsafe.allocateMemory(Native.getLongSize());
 tojava     static long keysym_uppercase = unsafe.allocateMemory(Native.getLongSize());
+tojava     static Keysym2JavaKeycode kanaLock = new Keysym2JavaKeycode(java.awt.event.KeyEvent.VK_KANA_LOCK,
+tojava                                                                 java.awt.event.KeyEvent.KEY_LOCATION_STANDARD);
 tojava     private static PlatformLogger keyEventLog = PlatformLogger.getLogger("sun.awt.X11.kye.XKeysym");
 tojava     public static char convertKeysym( long ks, int state ) {
 tojava
@@ -252,12 +254,35 @@
 tojava         }
 tojava         return keysym;
 tojava     }
+tojava
+tojava     /**
+tojava         Return java.awt.KeyEvent constant meaning (Java) keycode, derived from X keysym.
+tojava         Some keysyms maps to more than one keycode, these would require extra processing.
+tojava     */
+tojava     static Keysym2JavaKeycode getJavaKeycode( long keysym ) {
+tojava         if(keysym == XKeySymConstants.XK_Mode_switch){
+tojava            /* XK_Mode_switch on solaris maps either to VK_ALT_GRAPH (default) or VK_KANA_LOCK */
+tojava            if( XToolkit.isKanaKeyboard() ) {
+tojava                return kanaLock;
+tojava            }
+tojava         }else if(keysym == XKeySymConstants.XK_L1){
+tojava            /* if it is Sun keyboard, trick hash to return VK_STOP else VK_F11 (default) */
+tojava            if( XToolkit.isSunKeyboard() ) {
+tojava                keysym = XKeySymConstants.SunXK_Stop;
+tojava            }
+tojava         }else if(keysym == XKeySymConstants.XK_L2) {
+tojava            /* if it is Sun keyboard, trick hash to return VK_AGAIN else VK_F12 (default) */
+tojava            if( XToolkit.isSunKeyboard() ) {
+tojava                keysym = XKeySymConstants.SunXK_Again;
+tojava            }
+tojava         }
+tojava
+tojava         return  keysym2JavaKeycodeHash.get( keysym );
+tojava     }
 tojava     /**
 tojava         Return java.awt.KeyEvent constant meaning (Java) keycode, derived from X Window KeyEvent.
 tojava         Algorithm is, extract via XKeycodeToKeysym  a proper keysym according to Xlib spec rules and
 tojava         err exceptions, then search a java keycode in a table.
-tojava         Some keysyms maps to more than one keycode, these would require extra processing. If someone
-tojava         points me to such a keysym.
 tojava     */
 tojava     static Keysym2JavaKeycode getJavaKeycode( XKeyEvent ev ) {
 tojava         // get from keysym2JavaKeycodeHash.
@@ -272,7 +297,7 @@
 tojava             keysym = xkeycode2keysym(ev, ndx);
 tojava         }
 tojava
-tojava         Keysym2JavaKeycode jkc = keysym2JavaKeycodeHash.get( keysym );
+tojava         Keysym2JavaKeycode jkc = getJavaKeycode( keysym );
 tojava         return jkc;
 tojava     }
 tojava     static int getJavaKeycodeOnly( XKeyEvent ev ) {
@@ -297,7 +322,7 @@
 tojava             ndx = 0;
 tojava             keysym = xkeycode2keysym_noxkb(ev, ndx);
 tojava         }
-tojava         Keysym2JavaKeycode jkc = keysym2JavaKeycodeHash.get( keysym );
+tojava         Keysym2JavaKeycode jkc = getJavaKeycode( keysym );
 tojava         return jkc == null ? java.awt.event.KeyEvent.VK_UNDEFINED : jkc.getJavaKeycode();
 tojava     }
 tojava     static long javaKeycode2Keysym( int jkey ) {
--- a/jdk/src/solaris/native/sun/xawt/XlibWrapper.c	Fri Dec 04 15:07:15 2009 +0300
+++ b/jdk/src/solaris/native/sun/xawt/XlibWrapper.c	Mon Dec 07 13:32:50 2009 +0300
@@ -33,6 +33,7 @@
 #include <X11/extensions/shape.h>
 #include <string.h>
 #include <stdlib.h>
+#include <X11/Sunkeysym.h>
 
 #include <jni.h>
 #include <jni_util.h>
@@ -1214,6 +1215,48 @@
     }
 }
 
+
+JNIEXPORT jboolean JNICALL Java_sun_awt_X11_XlibWrapper_IsSunKeyboard
+(JNIEnv *env, jclass clazz, jlong display)
+{
+    int xx;
+    AWT_CHECK_HAVE_LOCK();
+    xx = XKeysymToKeycode((Display*)jlong_to_ptr(display), SunXK_F37);
+    return (!xx) ? JNI_FALSE : JNI_TRUE;
+}
+
+JNIEXPORT jboolean JNICALL Java_sun_awt_X11_XlibWrapper_IsKanaKeyboard
+(JNIEnv *env, jclass clazz, jlong display)
+{
+    int xx;
+    AWT_CHECK_HAVE_LOCK();
+    static jboolean result = JNI_FALSE;
+
+    int32_t minKeyCode, maxKeyCode, keySymsPerKeyCode;
+    KeySym *keySyms, *keySymsStart, keySym;
+    int32_t i;
+    int32_t kanaCount = 0;
+
+    // There's no direct way to determine whether the keyboard has
+    // a kana lock key. From available keyboard mapping tables, it looks
+    // like only keyboards with the kana lock key can produce keysyms
+    // for kana characters. So, as an indirect test, we check for those.
+    XDisplayKeycodes((Display*)jlong_to_ptr(display), &minKeyCode, &maxKeyCode);
+    keySyms = XGetKeyboardMapping((Display*)jlong_to_ptr(display), minKeyCode, maxKeyCode - minKeyCode + 1, &keySymsPerKeyCode);
+    keySymsStart = keySyms;
+    for (i = 0; i < (maxKeyCode - minKeyCode + 1) * keySymsPerKeyCode; i++) {
+        keySym = *keySyms++;
+        if ((keySym & 0xff00) == 0x0400) {
+            kanaCount++;
+        }
+    }
+    XFree(keySymsStart);
+
+    // use a (somewhat arbitrary) minimum so we don't get confused by a stray function key
+    result = kanaCount > 10;
+    return result ? JNI_TRUE : JNI_FALSE;
+}
+
 JavaVM* jvm = NULL;
 static int ToolkitErrorHandler(Display * dpy, XErrorEvent * event) {
     if (jvm != NULL) {
@@ -1261,6 +1304,7 @@
     return (*(XErrorHandler)jlong_to_ptr(handler))((Display*) jlong_to_ptr(display), (XErrorEvent*) jlong_to_ptr(event_ptr));
 }
 
+
 /*
  * Class:     sun_awt_X11_XlibWrapper
  * Method:    PrintXErrorEvent
@@ -1853,6 +1897,17 @@
     AWT_CHECK_HAVE_LOCK();
     XFreeModifiermap((XModifierKeymap*) jlong_to_ptr(keymap));
 }
+/*
+ * Class:     sun_awt_X11_XlibWrapper
+ * Method:    XRefreshKeyboardMapping
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_sun_awt_X11_XlibWrapper_XRefreshKeyboardMapping
+(JNIEnv *env, jclass clazz, jlong event_ptr)
+{
+    AWT_CHECK_HAVE_LOCK();
+    XRefreshKeyboardMapping((XMappingEvent*) jlong_to_ptr(event_ptr));
+}
 
 JNIEXPORT void JNICALL
 Java_sun_awt_X11_XlibWrapper_XChangeActivePointerGrab(JNIEnv *env, jclass clazz,