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
--- 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,