From 7543092add88c893eff465e054cc8dcb2cb59030 Mon Sep 17 00:00:00 2001 From: Alex Baines <alex@abaines.me.uk> Date: Wed, 30 Sep 2015 04:16:09 +0100 Subject: [PATCH] Call setlocale + XSetModifiers before XOpenIM, Work around ibus+xim duplicate events. --- src/video/x11/SDL_x11events.c | 5 ++--- src/video/x11/SDL_x11sym.h | 1 + src/video/x11/SDL_x11video.c | 36 +++++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index dd0287ec7..e7dbd1125 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -565,15 +565,12 @@ X11_DispatchEvent(_THIS) #endif if (orig_keycode) { /* Make sure dead key press/release events are sent */ - /* Actually, don't do this because it causes double-delivery - of some keys on Ubuntu 14.04 (bug 2526) SDL_Scancode scancode = videodata->key_layout[orig_keycode]; if (orig_event_type == KeyPress) { SDL_SendKeyboardKey(SDL_PRESSED, scancode); } else { SDL_SendKeyboardKey(SDL_RELEASED, scancode); } - */ } return; } @@ -781,6 +778,8 @@ X11_DispatchEvent(_THIS) if (data->ic) { X11_Xutf8LookupString(data->ic, &xevent.xkey, text, sizeof(text), &keysym, &status); + } else { + X11_XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL); } #else X11_XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL); diff --git a/src/video/x11/SDL_x11sym.h b/src/video/x11/SDL_x11sym.h index 30af3f2e6..1caf383a8 100644 --- a/src/video/x11/SDL_x11sym.h +++ b/src/video/x11/SDL_x11sym.h @@ -196,6 +196,7 @@ SDL_X11_SYM(XIM,XOpenIM,(Display* a,struct _XrmHashBucketRec* b,char* c,char* d) SDL_X11_SYM(Status,XCloseIM,(XIM a),(a),return) SDL_X11_SYM(void,Xutf8DrawString,(Display *a, Drawable b, XFontSet c, GC d, int e, int f, _Xconst char *g, int h),(a,b,c,d,e,f,g,h),) SDL_X11_SYM(int,Xutf8TextExtents,(XFontSet a, _Xconst char* b, int c, XRectangle* d, XRectangle* e),(a,b,c,d,e),return) +SDL_X11_SYM(char*,XSetLocaleModifiers,(const char *a),(a),return) #endif #ifndef NO_SHARED_MEMORY diff --git a/src/video/x11/SDL_x11video.c b/src/video/x11/SDL_x11video.c index 4be6b3797..a8c3b2547 100644 --- a/src/video/x11/SDL_x11video.c +++ b/src/video/x11/SDL_x11video.c @@ -39,6 +39,10 @@ #include "SDL_x11opengles.h" #endif +#ifdef X_HAVE_UTF8_STRING +#include <locale.h> +#endif + /* Initialization/Query functions */ static int X11_VideoInit(_THIS); static void X11_VideoQuit(_THIS); @@ -387,8 +391,40 @@ X11_VideoInit(_THIS) /* Open a connection to the X input manager */ #ifdef X_HAVE_UTF8_STRING if (SDL_X11_HAVE_UTF8) { + /* Set the locale, and call XSetLocaleModifiers before XOpenIM so that + Compose keys will work correctly. */ + char *prev_locale = setlocale(LC_ALL, NULL); + char *prev_xmods = X11_XSetLocaleModifiers(NULL); + + if (prev_xmods) { + prev_xmods = SDL_strdup(prev_xmods); + } + + /* IBus resends some key events that were filtered by XFilterEvents + when it is used via XIM which causes issues. Prevent this by forcing + @im=none if XMODIFIERS contains @im=ibus. IBus can still be used via + the DBus implementation, which also has support for pre-editing. */ + const char *new_xmods = ""; + const char *env_xmods = SDL_getenv("XMODIFIERS"); + + if (env_xmods && SDL_strstr(env_xmods, "@im=ibus") != NULL) { + new_xmods = "@im=none"; + } + + setlocale(LC_ALL, ""); + X11_XSetLocaleModifiers(new_xmods); + data->im = X11_XOpenIM(data->display, NULL, data->classname, data->classname); + + /* Reset the locale + X locale modifiers back to how they were, + locale first because the X locale modifiers depend on it. */ + setlocale(LC_ALL, prev_locale); + X11_XSetLocaleModifiers(prev_xmods); + + if (prev_xmods) { + SDL_free(prev_xmods); + } } #endif