Try to recognize the keyboard comparing keysyms instead of converting them to multibyte strings, which makes the process locale-dependent and therefore more fragile.
Unfortunately this means that the layout tables might need to be updated. However, this change is known to fix the recognitions of a few keys in the French layout. --- dlls/winex11.drv/keyboard.c | 64 ++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 33 deletions(-)
This is the meaty patch in the series, and the one about which I would especially like to gather some feedback. I believe the current mechanism for detecting keys is broken, because sometimes it translates keys to (locale-dependent) encodings, sometimes it just use the last byte in the keysym. I believe the right space to run the key detection algorithm is KeySym, because it is really meant to indicate what label is written on the physical keys.
The full solution would be to just use keysyms, without touching them. However, this would completely invalidate current layout tables. Instead, my patch contains an intermediate solution: instead of the keysym, use its last byte. I don't understand all the details of the current matching filter, but I think current layout tables should largely remain valid.
diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index d9a6879ee04..fe4a29c4b06 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1417,6 +1417,35 @@ BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) return TRUE; }
+/* From the point of view of this function there are two types of + * keys: those for which the mapping to vkey and scancode depends on + * the keyboard layout (i.e., letters, numbers, punctuation) and those + * for which it doesn't (control keys); since this function is used to + * recognize the keyboard layout and map keysyms to vkeys and + * scancodes, we are only concerned about the first type, and map + * everything in the second type to zero. + */ +static char keysym_to_char( KeySym keysym ) +{ + /* Dead keys */ + if (0xfe50 <= keysym && keysym < 0xfed0) + return KEYBOARD_MapDeadKeysym( keysym ); + + /* Control keys (there is nothing allocated below 0xfc00, but I + take some margin in case something is added in the future) */ + if (0xf000 <= keysym && keysym < 0x10000) + return 0; + + /* XFree86 vendor keys */ + if (0x10000000 <= keysym) + return 0; + + /* "Normal" keys: return last octet, because our tables don't have + more than that; it would be better to extend the tables and + compare the whole keysym, but it's a lot of work... */ + return keysym & 0xff; +} + /********************************************************************** * X11DRV_KEYBOARD_DetectLayout * @@ -1447,24 +1476,7 @@ X11DRV_KEYBOARD_DetectLayout( Display *display ) /* get data for keycode from X server */ for (i = 0; i < syms; i++) { if (!(keysym = keycode_to_keysym (display, keyc, i))) continue; - /* Allow both one-byte and two-byte national keysyms */ - if ((keysym < 0x8000) && (keysym != ' ')) - { -#ifdef HAVE_XKB - if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL)) -#endif - { - TRACE("XKB could not translate keysym %04lx\n", keysym); - /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent - * with appropriate ShiftMask and Mode_switch, use XLookupString - * to get character in the local encoding. - */ - ckey[keyc][i] = keysym & 0xFF; - } - } - else { - ckey[keyc][i] = KEYBOARD_MapDeadKeysym(keysym); - } + ckey[keyc][i] = keysym_to_char(keysym); } }
@@ -1713,21 +1725,7 @@ void X11DRV_InitKeyboard( Display *display ) int maxlen=0,maxval=-1,ok; for (i=0; i<syms; i++) { keysym = keycode_to_keysym(display, keyc, i); - if ((keysym<0x8000) && (keysym!=' ')) - { -#ifdef HAVE_XKB - if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL)) -#endif - { - /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent - * with appropriate ShiftMask and Mode_switch, use XLookupString - * to get character in the local encoding. - */ - ckey[i] = (keysym <= 0x7F) ? keysym : 0; - } - } else { - ckey[i] = KEYBOARD_MapDeadKeysym(keysym); - } + ckey[i] = keysym_to_char(keysym); } /* find key with longest match streak */ for (keyn=0; keyn<MAIN_LEN; keyn++) {