Skip to content

Commit

Permalink
Fix double events / no repeat flag on key events when built withoutib…
Browse files Browse the repository at this point in the history
…us/fcitx

Uses XkbSetDetectableKeyRepeat, and falls back to forcing @im=none if it's not
supported.
  • Loading branch information
baines committed Oct 28, 2016
1 parent 88f2d16 commit 5fe9849
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 71 deletions.
6 changes: 5 additions & 1 deletion src/video/x11/SDL_x11events.c
Expand Up @@ -568,14 +568,18 @@ X11_DispatchEvent(_THIS)
printf("Filtered event type = %d display = %d window = %d\n",
xevent.type, xevent.xany.display, xevent.xany.window);
#endif
/* Make sure dead key press/release events are sent */
/* But only if we're using one of the DBus IMEs, otherwise
some XIM IMEs will generate duplicate events */
if (orig_keycode) {
/* Make sure dead key press/release events are sent */
#if defined(HAVE_IBUS_IBUS_H) || defined(HAVE_FCITX_FRONTEND_H)
SDL_Scancode scancode = videodata->key_layout[orig_keycode];
if (orig_event_type == KeyPress) {
SDL_SendKeyboardKey(SDL_PRESSED, scancode);
} else {
SDL_SendKeyboardKey(SDL_RELEASED, scancode);
}
#endif
}
return;
}
Expand Down
81 changes: 74 additions & 7 deletions src/video/x11/SDL_x11keyboard.c
Expand Up @@ -33,6 +33,10 @@

#include "imKStoUCS.h"

#ifdef X_HAVE_UTF8_STRING
#include <locale.h>
#endif

/* *INDENT-OFF* */
static const struct {
KeySym keysym;
Expand Down Expand Up @@ -262,19 +266,82 @@ X11_InitKeyboard(_THIS)
int best_distance;
int best_index;
int distance;

BOOL xkb_repeat = 0;

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);
}
}
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);
}

/* This will remove KeyRelease events for held keys */
X11_XkbSetDetectableAutoRepeat(data->display, True, &xkb_repeat);
}
#endif

/* 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);
const char *new_xmods = "";
#if defined(HAVE_IBUS_IBUS_H) || defined(HAVE_FCITX_FRONTEND_H)
const char *env_xmods = SDL_getenv("XMODIFIERS");
#endif
SDL_bool has_dbus_ime_support = SDL_FALSE;

if (prev_locale) {
prev_locale = SDL_strdup(prev_locale);
}

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. */
#ifdef HAVE_IBUS_IBUS_H
if (env_xmods && SDL_strstr(env_xmods, "@im=ibus") != NULL) {
has_dbus_ime_support = SDL_TRUE;
}
#endif
#ifdef HAVE_FCITX_FRONTEND_H
if (env_xmods && SDL_strstr(env_xmods, "@im=fcitx") != NULL) {
has_dbus_ime_support = SDL_TRUE;
}
#endif
if (has_dbus_ime_support || !xkb_repeat) {
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_locale) {
SDL_free(prev_locale);
}

if (prev_xmods) {
SDL_free(prev_xmods);
}
}
#endif
/* Try to determine which scancodes are being used based on fingerprint */
best_distance = SDL_arraysize(fingerprint) + 1;
best_index = -1;
Expand Down
1 change: 1 addition & 0 deletions src/video/x11/SDL_x11sym.h
Expand Up @@ -179,6 +179,7 @@ SDL_X11_SYM(Status,XkbGetState,(Display* a,unsigned int b,XkbStatePtr c),(a,b,c)
SDL_X11_SYM(Status,XkbGetUpdatedMap,(Display* a,unsigned int b,XkbDescPtr c),(a,b,c),return)
SDL_X11_SYM(XkbDescPtr,XkbGetMap,(Display* a,unsigned int b,unsigned int c),(a,b,c),return)
SDL_X11_SYM(void,XkbFreeClientMap,(XkbDescPtr a,unsigned int b, Bool c),(a,b,c),)
SDL_X11_SYM(BOOL,XkbSetDetectableAutoRepeat,(Display* a, BOOL b, BOOL* c),(a,b,c),return)
#endif

#if NeedWidePrototypes
Expand Down
63 changes: 0 additions & 63 deletions src/video/x11/SDL_x11video.c
Expand Up @@ -39,10 +39,6 @@
#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);
Expand Down Expand Up @@ -388,65 +384,6 @@ X11_VideoInit(_THIS)
/* I have no idea how random this actually is, or has to be. */
data->window_group = (XID) (((size_t) data->pid) ^ ((size_t) _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);
const char *new_xmods = "";
#if defined(HAVE_IBUS_IBUS_H) || defined(HAVE_FCITX_FRONTEND_H)
const char *env_xmods = SDL_getenv("XMODIFIERS");
#endif
SDL_bool has_dbus_ime_support = SDL_FALSE;

if (prev_locale) {
prev_locale = SDL_strdup(prev_locale);
}

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. */
#ifdef HAVE_IBUS_IBUS_H
if (env_xmods && SDL_strstr(env_xmods, "@im=ibus") != NULL) {
has_dbus_ime_support = SDL_TRUE;
}
#endif
#ifdef HAVE_FCITX_FRONTEND_H
if (env_xmods && SDL_strstr(env_xmods, "@im=fcitx") != NULL) {
has_dbus_ime_support = SDL_TRUE;
}
#endif
if (has_dbus_ime_support) {
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_locale) {
SDL_free(prev_locale);
}

if (prev_xmods) {
SDL_free(prev_xmods);
}
}
#endif

/* Look up some useful Atoms */
#define GET_ATOM(X) data->X = X11_XInternAtom(data->display, #X, False)
GET_ATOM(WM_PROTOCOLS);
Expand Down

0 comments on commit 5fe9849

Please sign in to comment.