Fix double events / no repeat flag on key events when built withoutibus/fcitx
authorAlex Baines <alex@abaines.me.uk>
Fri, 28 Oct 2016 01:28:58 +0100
changeset 10562b48d8a98e261
parent 10561 35fee69e84df
child 10563 e3d84016cb79
Fix double events / no repeat flag on key events when built withoutibus/fcitx

Uses XkbSetDetectableKeyRepeat, and falls back to forcing @im=none if it's not
supported.
src/video/x11/SDL_x11events.c
src/video/x11/SDL_x11keyboard.c
src/video/x11/SDL_x11sym.h
src/video/x11/SDL_x11video.c
     1.1 --- a/src/video/x11/SDL_x11events.c	Fri Oct 28 17:00:37 2016 -0700
     1.2 +++ b/src/video/x11/SDL_x11events.c	Fri Oct 28 01:28:58 2016 +0100
     1.3 @@ -568,14 +568,18 @@
     1.4          printf("Filtered event type = %d display = %d window = %d\n",
     1.5                 xevent.type, xevent.xany.display, xevent.xany.window);
     1.6  #endif
     1.7 +        /* Make sure dead key press/release events are sent */
     1.8 +        /* But only if we're using one of the DBus IMEs, otherwise
     1.9 +           some XIM IMEs will generate duplicate events */
    1.10          if (orig_keycode) {
    1.11 -            /* Make sure dead key press/release events are sent */
    1.12 +#if defined(HAVE_IBUS_IBUS_H) || defined(HAVE_FCITX_FRONTEND_H)
    1.13              SDL_Scancode scancode = videodata->key_layout[orig_keycode];
    1.14              if (orig_event_type == KeyPress) {
    1.15                  SDL_SendKeyboardKey(SDL_PRESSED, scancode);
    1.16              } else {
    1.17                  SDL_SendKeyboardKey(SDL_RELEASED, scancode);
    1.18              }
    1.19 +#endif
    1.20          }
    1.21          return;
    1.22      }
     2.1 --- a/src/video/x11/SDL_x11keyboard.c	Fri Oct 28 17:00:37 2016 -0700
     2.2 +++ b/src/video/x11/SDL_x11keyboard.c	Fri Oct 28 01:28:58 2016 +0100
     2.3 @@ -33,6 +33,10 @@
     2.4  
     2.5  #include "imKStoUCS.h"
     2.6  
     2.7 +#ifdef X_HAVE_UTF8_STRING
     2.8 +#include <locale.h>
     2.9 +#endif
    2.10 +
    2.11  /* *INDENT-OFF* */
    2.12  static const struct {
    2.13      KeySym keysym;
    2.14 @@ -262,19 +266,82 @@
    2.15      int best_distance;
    2.16      int best_index;
    2.17      int distance;
    2.18 -
    2.19 +    BOOL xkb_repeat = 0;
    2.20 +    
    2.21      X11_XAutoRepeatOn(data->display);
    2.22  
    2.23  #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
    2.24      {
    2.25 -	    int xkb_major = XkbMajorVersion;
    2.26 -	    int xkb_minor = XkbMinorVersion;
    2.27 -	    if (X11_XkbQueryExtension(data->display, NULL, NULL, NULL, &xkb_major, &xkb_minor)) {
    2.28 -	        data->xkb = X11_XkbGetMap(data->display, XkbAllClientInfoMask, XkbUseCoreKbd);
    2.29 -	    }
    2.30 -	}
    2.31 +        int xkb_major = XkbMajorVersion;
    2.32 +        int xkb_minor = XkbMinorVersion;
    2.33 +
    2.34 +        if (X11_XkbQueryExtension(data->display, NULL, NULL, NULL, &xkb_major, &xkb_minor)) {
    2.35 +            data->xkb = X11_XkbGetMap(data->display, XkbAllClientInfoMask, XkbUseCoreKbd);
    2.36 +        }
    2.37 +
    2.38 +        /* This will remove KeyRelease events for held keys */
    2.39 +        X11_XkbSetDetectableAutoRepeat(data->display, True, &xkb_repeat);
    2.40 +    }
    2.41  #endif
    2.42 +    
    2.43 +    /* Open a connection to the X input manager */
    2.44 +#ifdef X_HAVE_UTF8_STRING
    2.45 +    if (SDL_X11_HAVE_UTF8) {
    2.46 +        /* Set the locale, and call XSetLocaleModifiers before XOpenIM so that 
    2.47 +           Compose keys will work correctly. */
    2.48 +        char *prev_locale = setlocale(LC_ALL, NULL);
    2.49 +        char *prev_xmods  = X11_XSetLocaleModifiers(NULL);
    2.50 +        const char *new_xmods = "";
    2.51 +#if defined(HAVE_IBUS_IBUS_H) || defined(HAVE_FCITX_FRONTEND_H)
    2.52 +        const char *env_xmods = SDL_getenv("XMODIFIERS");
    2.53 +#endif
    2.54 +        SDL_bool has_dbus_ime_support = SDL_FALSE;
    2.55  
    2.56 +        if (prev_locale) {
    2.57 +            prev_locale = SDL_strdup(prev_locale);
    2.58 +        }
    2.59 +
    2.60 +        if (prev_xmods) {
    2.61 +            prev_xmods = SDL_strdup(prev_xmods);
    2.62 +        }
    2.63 +
    2.64 +        /* IBus resends some key events that were filtered by XFilterEvents
    2.65 +           when it is used via XIM which causes issues. Prevent this by forcing
    2.66 +           @im=none if XMODIFIERS contains @im=ibus. IBus can still be used via 
    2.67 +           the DBus implementation, which also has support for pre-editing. */
    2.68 +#ifdef HAVE_IBUS_IBUS_H
    2.69 +        if (env_xmods && SDL_strstr(env_xmods, "@im=ibus") != NULL) {
    2.70 +            has_dbus_ime_support = SDL_TRUE;
    2.71 +        }
    2.72 +#endif
    2.73 +#ifdef HAVE_FCITX_FRONTEND_H
    2.74 +        if (env_xmods && SDL_strstr(env_xmods, "@im=fcitx") != NULL) {
    2.75 +            has_dbus_ime_support = SDL_TRUE;
    2.76 +        }
    2.77 +#endif
    2.78 +        if (has_dbus_ime_support || !xkb_repeat) {
    2.79 +            new_xmods = "@im=none";
    2.80 +        }
    2.81 +
    2.82 +        setlocale(LC_ALL, "");
    2.83 +        X11_XSetLocaleModifiers(new_xmods);
    2.84 +
    2.85 +        data->im = X11_XOpenIM(data->display, NULL, data->classname, data->classname);
    2.86 +
    2.87 +        /* Reset the locale + X locale modifiers back to how they were,
    2.88 +           locale first because the X locale modifiers depend on it. */
    2.89 +        setlocale(LC_ALL, prev_locale);
    2.90 +        X11_XSetLocaleModifiers(prev_xmods);
    2.91 +
    2.92 +        if (prev_locale) {
    2.93 +            SDL_free(prev_locale);
    2.94 +        }
    2.95 +
    2.96 +        if (prev_xmods) {
    2.97 +            SDL_free(prev_xmods);
    2.98 +        }
    2.99 +    }
   2.100 +#endif
   2.101      /* Try to determine which scancodes are being used based on fingerprint */
   2.102      best_distance = SDL_arraysize(fingerprint) + 1;
   2.103      best_index = -1;
     3.1 --- a/src/video/x11/SDL_x11sym.h	Fri Oct 28 17:00:37 2016 -0700
     3.2 +++ b/src/video/x11/SDL_x11sym.h	Fri Oct 28 01:28:58 2016 +0100
     3.3 @@ -179,6 +179,7 @@
     3.4  SDL_X11_SYM(Status,XkbGetUpdatedMap,(Display* a,unsigned int b,XkbDescPtr c),(a,b,c),return)
     3.5  SDL_X11_SYM(XkbDescPtr,XkbGetMap,(Display* a,unsigned int b,unsigned int c),(a,b,c),return)
     3.6  SDL_X11_SYM(void,XkbFreeClientMap,(XkbDescPtr a,unsigned int b, Bool c),(a,b,c),)
     3.7 +SDL_X11_SYM(BOOL,XkbSetDetectableAutoRepeat,(Display* a, BOOL b, BOOL* c),(a,b,c),return)
     3.8  #endif
     3.9  
    3.10  #if NeedWidePrototypes
     4.1 --- a/src/video/x11/SDL_x11video.c	Fri Oct 28 17:00:37 2016 -0700
     4.2 +++ b/src/video/x11/SDL_x11video.c	Fri Oct 28 01:28:58 2016 +0100
     4.3 @@ -39,10 +39,6 @@
     4.4  #include "SDL_x11opengles.h"
     4.5  #endif
     4.6  
     4.7 -#ifdef X_HAVE_UTF8_STRING
     4.8 -#include <locale.h>
     4.9 -#endif
    4.10 -
    4.11  /* Initialization/Query functions */
    4.12  static int X11_VideoInit(_THIS);
    4.13  static void X11_VideoQuit(_THIS);
    4.14 @@ -388,65 +384,6 @@
    4.15      /* I have no idea how random this actually is, or has to be. */
    4.16      data->window_group = (XID) (((size_t) data->pid) ^ ((size_t) _this));
    4.17  
    4.18 -    /* Open a connection to the X input manager */
    4.19 -#ifdef X_HAVE_UTF8_STRING
    4.20 -    if (SDL_X11_HAVE_UTF8) {
    4.21 -        /* Set the locale, and call XSetLocaleModifiers before XOpenIM so that 
    4.22 -           Compose keys will work correctly. */
    4.23 -        char *prev_locale = setlocale(LC_ALL, NULL);
    4.24 -        char *prev_xmods  = X11_XSetLocaleModifiers(NULL);
    4.25 -        const char *new_xmods = "";
    4.26 -#if defined(HAVE_IBUS_IBUS_H) || defined(HAVE_FCITX_FRONTEND_H)
    4.27 -        const char *env_xmods = SDL_getenv("XMODIFIERS");
    4.28 -#endif
    4.29 -        SDL_bool has_dbus_ime_support = SDL_FALSE;
    4.30 -
    4.31 -        if (prev_locale) {
    4.32 -            prev_locale = SDL_strdup(prev_locale);
    4.33 -        }
    4.34 -
    4.35 -        if (prev_xmods) {
    4.36 -            prev_xmods = SDL_strdup(prev_xmods);
    4.37 -        }
    4.38 -
    4.39 -        /* IBus resends some key events that were filtered by XFilterEvents
    4.40 -           when it is used via XIM which causes issues. Prevent this by forcing
    4.41 -           @im=none if XMODIFIERS contains @im=ibus. IBus can still be used via 
    4.42 -           the DBus implementation, which also has support for pre-editing. */
    4.43 -#ifdef HAVE_IBUS_IBUS_H
    4.44 -        if (env_xmods && SDL_strstr(env_xmods, "@im=ibus") != NULL) {
    4.45 -            has_dbus_ime_support = SDL_TRUE;
    4.46 -        }
    4.47 -#endif
    4.48 -#ifdef HAVE_FCITX_FRONTEND_H
    4.49 -        if (env_xmods && SDL_strstr(env_xmods, "@im=fcitx") != NULL) {
    4.50 -            has_dbus_ime_support = SDL_TRUE;
    4.51 -        }
    4.52 -#endif
    4.53 -        if (has_dbus_ime_support) {
    4.54 -            new_xmods = "@im=none";
    4.55 -        }
    4.56 -
    4.57 -        setlocale(LC_ALL, "");
    4.58 -        X11_XSetLocaleModifiers(new_xmods);
    4.59 -
    4.60 -        data->im = X11_XOpenIM(data->display, NULL, data->classname, data->classname);
    4.61 -
    4.62 -        /* Reset the locale + X locale modifiers back to how they were,
    4.63 -           locale first because the X locale modifiers depend on it. */
    4.64 -        setlocale(LC_ALL, prev_locale);
    4.65 -        X11_XSetLocaleModifiers(prev_xmods);
    4.66 -
    4.67 -        if (prev_locale) {
    4.68 -            SDL_free(prev_locale);
    4.69 -        }
    4.70 -
    4.71 -        if (prev_xmods) {
    4.72 -            SDL_free(prev_xmods);
    4.73 -        }
    4.74 -    }
    4.75 -#endif
    4.76 -
    4.77      /* Look up some useful Atoms */
    4.78  #define GET_ATOM(X) data->X = X11_XInternAtom(data->display, #X, False)
    4.79      GET_ATOM(WM_PROTOCOLS);