From 752931d85ee7f10d51db5e52c146cbbe0cb29f6e Mon Sep 17 00:00:00 2001 From: Alex Baines Date: Mon, 3 Oct 2016 11:35:34 +0100 Subject: [PATCH] Improve X11 key handling when XKB isn't available + add xvnc scancodes. Based on a patch by Bill Lash (see bug 3094). --- src/events/scancodes_xfree86.h | 85 +++++++++++++++++++++++++++++++++ src/video/x11/SDL_x11events.c | 6 +-- src/video/x11/SDL_x11keyboard.c | 70 +++++++++++++++------------ src/video/x11/SDL_x11keyboard.h | 1 + src/video/x11/SDL_x11sym.h | 1 + 5 files changed, 127 insertions(+), 36 deletions(-) diff --git a/src/events/scancodes_xfree86.h b/src/events/scancodes_xfree86.h index 29d9ef944..804196ca4 100644 --- a/src/events/scancodes_xfree86.h +++ b/src/events/scancodes_xfree86.h @@ -418,4 +418,89 @@ static const SDL_Scancode xfree86_scancode_table2[] = { /* 238 */ SDL_SCANCODE_UNKNOWN, /* XF86WLAN */ }; +/* Xvnc / Xtightvnc scancodes from xmodmap -pk */ +static const SDL_Scancode xvnc_scancode_table[] = { + /* 0 */ SDL_SCANCODE_LCTRL, + /* 1 */ SDL_SCANCODE_RCTRL, + /* 2 */ SDL_SCANCODE_LSHIFT, + /* 3 */ SDL_SCANCODE_RSHIFT, + /* 4 */ SDL_SCANCODE_UNKNOWN, /* Meta_L */ + /* 5 */ SDL_SCANCODE_UNKNOWN, /* Meta_R */ + /* 6 */ SDL_SCANCODE_LALT, + /* 7 */ SDL_SCANCODE_RALT, + /* 8 */ SDL_SCANCODE_SPACE, + /* 9 */ SDL_SCANCODE_0, + /* 10 */ SDL_SCANCODE_1, + /* 11 */ SDL_SCANCODE_2, + /* 12 */ SDL_SCANCODE_3, + /* 13 */ SDL_SCANCODE_4, + /* 14 */ SDL_SCANCODE_5, + /* 15 */ SDL_SCANCODE_6, + /* 16 */ SDL_SCANCODE_7, + /* 17 */ SDL_SCANCODE_8, + /* 18 */ SDL_SCANCODE_9, + /* 19 */ SDL_SCANCODE_MINUS, + /* 20 */ SDL_SCANCODE_EQUALS, + /* 21 */ SDL_SCANCODE_LEFTBRACKET, + /* 22 */ SDL_SCANCODE_RIGHTBRACKET, + /* 23 */ SDL_SCANCODE_SEMICOLON, + /* 24 */ SDL_SCANCODE_APOSTROPHE, + /* 25 */ SDL_SCANCODE_GRAVE, + /* 26 */ SDL_SCANCODE_COMMA, + /* 27 */ SDL_SCANCODE_PERIOD, + /* 28 */ SDL_SCANCODE_SLASH, + /* 29 */ SDL_SCANCODE_BACKSLASH, + /* 30 */ SDL_SCANCODE_A, + /* 31 */ SDL_SCANCODE_B, + /* 32 */ SDL_SCANCODE_C, + /* 33 */ SDL_SCANCODE_D, + /* 34 */ SDL_SCANCODE_E, + /* 35 */ SDL_SCANCODE_F, + /* 36 */ SDL_SCANCODE_G, + /* 37 */ SDL_SCANCODE_H, + /* 38 */ SDL_SCANCODE_I, + /* 39 */ SDL_SCANCODE_J, + /* 40 */ SDL_SCANCODE_K, + /* 41 */ SDL_SCANCODE_L, + /* 42 */ SDL_SCANCODE_M, + /* 43 */ SDL_SCANCODE_N, + /* 44 */ SDL_SCANCODE_O, + /* 45 */ SDL_SCANCODE_P, + /* 46 */ SDL_SCANCODE_Q, + /* 47 */ SDL_SCANCODE_R, + /* 48 */ SDL_SCANCODE_S, + /* 49 */ SDL_SCANCODE_T, + /* 50 */ SDL_SCANCODE_U, + /* 51 */ SDL_SCANCODE_V, + /* 52 */ SDL_SCANCODE_W, + /* 53 */ SDL_SCANCODE_X, + /* 54 */ SDL_SCANCODE_Y, + /* 55 */ SDL_SCANCODE_Z, + /* 56 */ SDL_SCANCODE_BACKSPACE, + /* 57 */ SDL_SCANCODE_RETURN, + /* 58 */ SDL_SCANCODE_TAB, + /* 59 */ SDL_SCANCODE_ESCAPE, + /* 60 */ SDL_SCANCODE_DELETE, + /* 61 */ SDL_SCANCODE_HOME, + /* 62 */ SDL_SCANCODE_END, + /* 63 */ SDL_SCANCODE_PAGEUP, + /* 64 */ SDL_SCANCODE_PAGEDOWN, + /* 65 */ SDL_SCANCODE_UP, + /* 66 */ SDL_SCANCODE_DOWN, + /* 67 */ SDL_SCANCODE_LEFT, + /* 68 */ SDL_SCANCODE_RIGHT, + /* 69 */ SDL_SCANCODE_F1, + /* 70 */ SDL_SCANCODE_F2, + /* 71 */ SDL_SCANCODE_F3, + /* 72 */ SDL_SCANCODE_F4, + /* 73 */ SDL_SCANCODE_F5, + /* 74 */ SDL_SCANCODE_F6, + /* 75 */ SDL_SCANCODE_F7, + /* 76 */ SDL_SCANCODE_F8, + /* 77 */ SDL_SCANCODE_F9, + /* 78 */ SDL_SCANCODE_F10, + /* 79 */ SDL_SCANCODE_F11, + /* 80 */ SDL_SCANCODE_F12, +}; + /* *INDENT-ON* */ diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index 5d7f1df66..716bc18be 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -766,11 +766,7 @@ X11_DispatchEvent(_THIS) if (videodata->key_layout[keycode] == SDL_SCANCODE_UNKNOWN && keycode) { int min_keycode, max_keycode; X11_XDisplayKeycodes(display, &min_keycode, &max_keycode); -#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM - keysym = X11_XkbKeycodeToKeysym(display, keycode, 0, 0); -#else - keysym = X11_XKeycodeToKeysym(display, keycode, 0); -#endif + keysym = X11_KeyCodeToSym(_this, keycode, xevent.xkey.state >> 13); fprintf(stderr, "The key you just pressed is not recognized by SDL. To help get this fixed, please report this to the SDL mailing list X11 KeyCode %d (%d), X11 KeySym 0x%lX (%s).\n", keycode, keycode - min_keycode, keysym, diff --git a/src/video/x11/SDL_x11keyboard.c b/src/video/x11/SDL_x11keyboard.c index d775b2c02..26ad8fe45 100644 --- a/src/video/x11/SDL_x11keyboard.c +++ b/src/video/x11/SDL_x11keyboard.c @@ -154,21 +154,18 @@ static const struct { darwin_scancode_table, SDL_arraysize(darwin_scancode_table) }, { xfree86_scancode_table, SDL_arraysize(xfree86_scancode_table) }, { xfree86_scancode_table2, SDL_arraysize(xfree86_scancode_table2) }, + { xvnc_scancode_table, SDL_arraysize(xvnc_scancode_table) }, }; /* *INDENT-OFF* */ /* This function only works for keyboards in US QWERTY layout */ static SDL_Scancode -X11_KeyCodeToSDLScancode(Display *display, KeyCode keycode) +X11_KeyCodeToSDLScancode(_THIS, KeyCode keycode) { KeySym keysym; int i; -#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM - keysym = X11_XkbKeycodeToKeysym(display, keycode, 0, 0); -#else - keysym = X11_XKeycodeToKeysym(display, keycode, 0); -#endif + keysym = X11_KeyCodeToSym(_this, keycode, 0); if (keysym == NoSymbol) { return SDL_SCANCODE_UNKNOWN; } @@ -196,8 +193,21 @@ X11_KeyCodeToSDLScancode(Display *display, KeyCode keycode) } static Uint32 -X11_KeyCodeToUcs4(SDL_VideoData *data, KeyCode keycode, unsigned char group) +X11_KeyCodeToUcs4(_THIS, KeyCode keycode, unsigned char group) { + KeySym keysym = X11_KeyCodeToSym(_this, keycode, group); + + if (keysym == NoSymbol) { + return 0; + } + + return X11_KeySymToUcs4(keysym); +} + +KeySym +X11_KeyCodeToSym(_THIS, KeyCode keycode, unsigned char group) +{ + SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; KeySym keysym; #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM @@ -219,19 +229,15 @@ X11_KeyCodeToUcs4(SDL_VideoData *data, KeyCode keycode, unsigned char group) group %= num_groups; } } + keysym = X11_XkbKeycodeToKeysym(data->display, keycode, group, 0); } else { - group = 0; + keysym = X11_XKeycodeToKeysym(data->display, keycode, 0); } - - keysym = X11_XkbKeycodeToKeysym(data->display, keycode, group, 0); #else keysym = X11_XKeycodeToKeysym(data->display, keycode, 0); #endif - if (keysym == NoSymbol) { - return 0; - } - return X11_KeySymToUcs4(keysym); + return keysym; } int @@ -259,6 +265,16 @@ X11_InitKeyboard(_THIS) X11_XAutoRepeatOn(data->display); +#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM + { + int xkb_major = XkbMajorVersion; + int xkb_minor = XkbMinorVersion; + if (X11_XkbQueryExtension(data->display, NULL, NULL, NULL, &xkb_major, &xkb_minor)) { + data->xkb = X11_XkbGetMap(data->display, XkbAllClientInfoMask, XkbUseCoreKbd); + } + } +#endif + /* Try to determine which scancodes are being used based on fingerprint */ best_distance = SDL_arraysize(fingerprint) + 1; best_index = -1; @@ -303,16 +319,12 @@ X11_InitKeyboard(_THIS) SDL_GetDefaultKeymap(keymap); for (i = min_keycode; i <= max_keycode; ++i) { KeySym sym; -#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM - sym = X11_XkbKeycodeToKeysym(data->display, i, 0, 0); -#else - sym = X11_XKeycodeToKeysym(data->display, i, 0); -#endif + sym = X11_KeyCodeToSym(_this, (KeyCode) i, 0); if (sym != NoSymbol) { SDL_Scancode scancode; printf("code = %d, sym = 0x%X (%s) ", i - min_keycode, (unsigned int) sym, X11_XKeysymToString(sym)); - scancode = X11_KeyCodeToSDLScancode(data->display, i); + scancode = X11_KeyCodeToSDLScancode(_this, i); data->key_layout[i] = scancode; if (scancode == SDL_SCANCODE_UNKNOWN) { printf("scancode not found\n"); @@ -344,16 +356,11 @@ X11_UpdateKeymap(_THIS) unsigned char group = 0; SDL_GetDefaultKeymap(keymap); - -#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM - { - XkbStateRec state; - if (data->xkb) { - X11_XkbGetUpdatedMap(data->display, XkbAllClientInfoMask, data->xkb); - } else { - data->xkb = X11_XkbGetMap(data->display, XkbAllClientInfoMask, XkbUseCoreKbd); - } +#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM + if (data->xkb) { + XkbStateRec state; + X11_XkbGetUpdatedMap(data->display, XkbAllClientInfoMask, data->xkb); if (X11_XkbGetState(data->display, XkbUseCoreKbd, &state) == Success) { group = state.group; @@ -372,11 +379,11 @@ X11_UpdateKeymap(_THIS) } /* See if there is a UCS keycode for this scancode */ - key = X11_KeyCodeToUcs4(data, (KeyCode)i, group); + key = X11_KeyCodeToUcs4(_this, (KeyCode)i, group); if (key) { keymap[scancode] = key; } else { - SDL_Scancode keyScancode = X11_KeyCodeToSDLScancode(data->display, (KeyCode)i); + SDL_Scancode keyScancode = X11_KeyCodeToSDLScancode(_this, (KeyCode)i); switch (keyScancode) { case SDL_SCANCODE_RETURN: @@ -411,6 +418,7 @@ X11_QuitKeyboard(_THIS) #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM if (data->xkb) { X11_XkbFreeClientMap(data->xkb, 0, True); + data->xkb = NULL; } #endif diff --git a/src/video/x11/SDL_x11keyboard.h b/src/video/x11/SDL_x11keyboard.h index a1102ed75..6ce3c9cce 100644 --- a/src/video/x11/SDL_x11keyboard.h +++ b/src/video/x11/SDL_x11keyboard.h @@ -29,6 +29,7 @@ extern void X11_QuitKeyboard(_THIS); extern void X11_StartTextInput(_THIS); extern void X11_StopTextInput(_THIS); extern void X11_SetTextInputRect(_THIS, SDL_Rect *rect); +extern KeySym X11_KeyCodeToSym(_THIS, KeyCode, unsigned char group); #endif /* _SDL_x11keyboard_h */ diff --git a/src/video/x11/SDL_x11sym.h b/src/video/x11/SDL_x11sym.h index d3af2aff1..c9840d845 100644 --- a/src/video/x11/SDL_x11sym.h +++ b/src/video/x11/SDL_x11sym.h @@ -169,6 +169,7 @@ SDL_X11_SYM(void,XFreeEventData,(Display* a,XGenericEventCookie* b),(a,b),) #endif #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM +SDL_X11_SYM(Bool,XkbQueryExtension,(Display* a,int * b,int * c,int * d,int * e, int *f),(a,b,c,d,e,f),return) #if NeedWidePrototypes SDL_X11_SYM(KeySym,XkbKeycodeToKeysym,(Display* a,unsigned int b,int c,int d),(a,b,c,d),return) #else