src/video/x11/SDL_x11keyboard.c
changeset 10562 b48d8a98e261
parent 10548 aea47b61c640
child 10569 9429d331668e
     1.1 --- a/src/video/x11/SDL_x11keyboard.c	Fri Oct 28 17:00:37 2016 -0700
     1.2 +++ b/src/video/x11/SDL_x11keyboard.c	Fri Oct 28 01:28:58 2016 +0100
     1.3 @@ -33,6 +33,10 @@
     1.4  
     1.5  #include "imKStoUCS.h"
     1.6  
     1.7 +#ifdef X_HAVE_UTF8_STRING
     1.8 +#include <locale.h>
     1.9 +#endif
    1.10 +
    1.11  /* *INDENT-OFF* */
    1.12  static const struct {
    1.13      KeySym keysym;
    1.14 @@ -262,19 +266,82 @@
    1.15      int best_distance;
    1.16      int best_index;
    1.17      int distance;
    1.18 -
    1.19 +    BOOL xkb_repeat = 0;
    1.20 +    
    1.21      X11_XAutoRepeatOn(data->display);
    1.22  
    1.23  #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
    1.24      {
    1.25 -	    int xkb_major = XkbMajorVersion;
    1.26 -	    int xkb_minor = XkbMinorVersion;
    1.27 -	    if (X11_XkbQueryExtension(data->display, NULL, NULL, NULL, &xkb_major, &xkb_minor)) {
    1.28 -	        data->xkb = X11_XkbGetMap(data->display, XkbAllClientInfoMask, XkbUseCoreKbd);
    1.29 -	    }
    1.30 -	}
    1.31 +        int xkb_major = XkbMajorVersion;
    1.32 +        int xkb_minor = XkbMinorVersion;
    1.33 +
    1.34 +        if (X11_XkbQueryExtension(data->display, NULL, NULL, NULL, &xkb_major, &xkb_minor)) {
    1.35 +            data->xkb = X11_XkbGetMap(data->display, XkbAllClientInfoMask, XkbUseCoreKbd);
    1.36 +        }
    1.37 +
    1.38 +        /* This will remove KeyRelease events for held keys */
    1.39 +        X11_XkbSetDetectableAutoRepeat(data->display, True, &xkb_repeat);
    1.40 +    }
    1.41  #endif
    1.42 +    
    1.43 +    /* Open a connection to the X input manager */
    1.44 +#ifdef X_HAVE_UTF8_STRING
    1.45 +    if (SDL_X11_HAVE_UTF8) {
    1.46 +        /* Set the locale, and call XSetLocaleModifiers before XOpenIM so that 
    1.47 +           Compose keys will work correctly. */
    1.48 +        char *prev_locale = setlocale(LC_ALL, NULL);
    1.49 +        char *prev_xmods  = X11_XSetLocaleModifiers(NULL);
    1.50 +        const char *new_xmods = "";
    1.51 +#if defined(HAVE_IBUS_IBUS_H) || defined(HAVE_FCITX_FRONTEND_H)
    1.52 +        const char *env_xmods = SDL_getenv("XMODIFIERS");
    1.53 +#endif
    1.54 +        SDL_bool has_dbus_ime_support = SDL_FALSE;
    1.55  
    1.56 +        if (prev_locale) {
    1.57 +            prev_locale = SDL_strdup(prev_locale);
    1.58 +        }
    1.59 +
    1.60 +        if (prev_xmods) {
    1.61 +            prev_xmods = SDL_strdup(prev_xmods);
    1.62 +        }
    1.63 +
    1.64 +        /* IBus resends some key events that were filtered by XFilterEvents
    1.65 +           when it is used via XIM which causes issues. Prevent this by forcing
    1.66 +           @im=none if XMODIFIERS contains @im=ibus. IBus can still be used via 
    1.67 +           the DBus implementation, which also has support for pre-editing. */
    1.68 +#ifdef HAVE_IBUS_IBUS_H
    1.69 +        if (env_xmods && SDL_strstr(env_xmods, "@im=ibus") != NULL) {
    1.70 +            has_dbus_ime_support = SDL_TRUE;
    1.71 +        }
    1.72 +#endif
    1.73 +#ifdef HAVE_FCITX_FRONTEND_H
    1.74 +        if (env_xmods && SDL_strstr(env_xmods, "@im=fcitx") != NULL) {
    1.75 +            has_dbus_ime_support = SDL_TRUE;
    1.76 +        }
    1.77 +#endif
    1.78 +        if (has_dbus_ime_support || !xkb_repeat) {
    1.79 +            new_xmods = "@im=none";
    1.80 +        }
    1.81 +
    1.82 +        setlocale(LC_ALL, "");
    1.83 +        X11_XSetLocaleModifiers(new_xmods);
    1.84 +
    1.85 +        data->im = X11_XOpenIM(data->display, NULL, data->classname, data->classname);
    1.86 +
    1.87 +        /* Reset the locale + X locale modifiers back to how they were,
    1.88 +           locale first because the X locale modifiers depend on it. */
    1.89 +        setlocale(LC_ALL, prev_locale);
    1.90 +        X11_XSetLocaleModifiers(prev_xmods);
    1.91 +
    1.92 +        if (prev_locale) {
    1.93 +            SDL_free(prev_locale);
    1.94 +        }
    1.95 +
    1.96 +        if (prev_xmods) {
    1.97 +            SDL_free(prev_xmods);
    1.98 +        }
    1.99 +    }
   1.100 +#endif
   1.101      /* Try to determine which scancodes are being used based on fingerprint */
   1.102      best_distance = SDL_arraysize(fingerprint) + 1;
   1.103      best_index = -1;