Skip to content

Commit 5fe9849

Browse files
committed
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.
1 parent 88f2d16 commit 5fe9849

4 files changed

Lines changed: 80 additions & 71 deletions

File tree

src/video/x11/SDL_x11events.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -568,14 +568,18 @@ X11_DispatchEvent(_THIS)
568568
printf("Filtered event type = %d display = %d window = %d\n",
569569
xevent.type, xevent.xany.display, xevent.xany.window);
570570
#endif
571+
/* Make sure dead key press/release events are sent */
572+
/* But only if we're using one of the DBus IMEs, otherwise
573+
some XIM IMEs will generate duplicate events */
571574
if (orig_keycode) {
572-
/* Make sure dead key press/release events are sent */
575+
#if defined(HAVE_IBUS_IBUS_H) || defined(HAVE_FCITX_FRONTEND_H)
573576
SDL_Scancode scancode = videodata->key_layout[orig_keycode];
574577
if (orig_event_type == KeyPress) {
575578
SDL_SendKeyboardKey(SDL_PRESSED, scancode);
576579
} else {
577580
SDL_SendKeyboardKey(SDL_RELEASED, scancode);
578581
}
582+
#endif
579583
}
580584
return;
581585
}

src/video/x11/SDL_x11keyboard.c

Lines changed: 74 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@
3333

3434
#include "imKStoUCS.h"
3535

36+
#ifdef X_HAVE_UTF8_STRING
37+
#include <locale.h>
38+
#endif
39+
3640
/* *INDENT-OFF* */
3741
static const struct {
3842
KeySym keysym;
@@ -262,19 +266,82 @@ X11_InitKeyboard(_THIS)
262266
int best_distance;
263267
int best_index;
264268
int distance;
265-
269+
BOOL xkb_repeat = 0;
270+
266271
X11_XAutoRepeatOn(data->display);
267272

268273
#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
269274
{
270-
int xkb_major = XkbMajorVersion;
271-
int xkb_minor = XkbMinorVersion;
272-
if (X11_XkbQueryExtension(data->display, NULL, NULL, NULL, &xkb_major, &xkb_minor)) {
273-
data->xkb = X11_XkbGetMap(data->display, XkbAllClientInfoMask, XkbUseCoreKbd);
274-
}
275-
}
275+
int xkb_major = XkbMajorVersion;
276+
int xkb_minor = XkbMinorVersion;
277+
278+
if (X11_XkbQueryExtension(data->display, NULL, NULL, NULL, &xkb_major, &xkb_minor)) {
279+
data->xkb = X11_XkbGetMap(data->display, XkbAllClientInfoMask, XkbUseCoreKbd);
280+
}
281+
282+
/* This will remove KeyRelease events for held keys */
283+
X11_XkbSetDetectableAutoRepeat(data->display, True, &xkb_repeat);
284+
}
285+
#endif
286+
287+
/* Open a connection to the X input manager */
288+
#ifdef X_HAVE_UTF8_STRING
289+
if (SDL_X11_HAVE_UTF8) {
290+
/* Set the locale, and call XSetLocaleModifiers before XOpenIM so that
291+
Compose keys will work correctly. */
292+
char *prev_locale = setlocale(LC_ALL, NULL);
293+
char *prev_xmods = X11_XSetLocaleModifiers(NULL);
294+
const char *new_xmods = "";
295+
#if defined(HAVE_IBUS_IBUS_H) || defined(HAVE_FCITX_FRONTEND_H)
296+
const char *env_xmods = SDL_getenv("XMODIFIERS");
297+
#endif
298+
SDL_bool has_dbus_ime_support = SDL_FALSE;
299+
300+
if (prev_locale) {
301+
prev_locale = SDL_strdup(prev_locale);
302+
}
303+
304+
if (prev_xmods) {
305+
prev_xmods = SDL_strdup(prev_xmods);
306+
}
307+
308+
/* IBus resends some key events that were filtered by XFilterEvents
309+
when it is used via XIM which causes issues. Prevent this by forcing
310+
@im=none if XMODIFIERS contains @im=ibus. IBus can still be used via
311+
the DBus implementation, which also has support for pre-editing. */
312+
#ifdef HAVE_IBUS_IBUS_H
313+
if (env_xmods && SDL_strstr(env_xmods, "@im=ibus") != NULL) {
314+
has_dbus_ime_support = SDL_TRUE;
315+
}
276316
#endif
317+
#ifdef HAVE_FCITX_FRONTEND_H
318+
if (env_xmods && SDL_strstr(env_xmods, "@im=fcitx") != NULL) {
319+
has_dbus_ime_support = SDL_TRUE;
320+
}
321+
#endif
322+
if (has_dbus_ime_support || !xkb_repeat) {
323+
new_xmods = "@im=none";
324+
}
325+
326+
setlocale(LC_ALL, "");
327+
X11_XSetLocaleModifiers(new_xmods);
277328

329+
data->im = X11_XOpenIM(data->display, NULL, data->classname, data->classname);
330+
331+
/* Reset the locale + X locale modifiers back to how they were,
332+
locale first because the X locale modifiers depend on it. */
333+
setlocale(LC_ALL, prev_locale);
334+
X11_XSetLocaleModifiers(prev_xmods);
335+
336+
if (prev_locale) {
337+
SDL_free(prev_locale);
338+
}
339+
340+
if (prev_xmods) {
341+
SDL_free(prev_xmods);
342+
}
343+
}
344+
#endif
278345
/* Try to determine which scancodes are being used based on fingerprint */
279346
best_distance = SDL_arraysize(fingerprint) + 1;
280347
best_index = -1;

src/video/x11/SDL_x11sym.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ SDL_X11_SYM(Status,XkbGetState,(Display* a,unsigned int b,XkbStatePtr c),(a,b,c)
179179
SDL_X11_SYM(Status,XkbGetUpdatedMap,(Display* a,unsigned int b,XkbDescPtr c),(a,b,c),return)
180180
SDL_X11_SYM(XkbDescPtr,XkbGetMap,(Display* a,unsigned int b,unsigned int c),(a,b,c),return)
181181
SDL_X11_SYM(void,XkbFreeClientMap,(XkbDescPtr a,unsigned int b, Bool c),(a,b,c),)
182+
SDL_X11_SYM(BOOL,XkbSetDetectableAutoRepeat,(Display* a, BOOL b, BOOL* c),(a,b,c),return)
182183
#endif
183184

184185
#if NeedWidePrototypes

src/video/x11/SDL_x11video.c

Lines changed: 0 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,6 @@
3939
#include "SDL_x11opengles.h"
4040
#endif
4141

42-
#ifdef X_HAVE_UTF8_STRING
43-
#include <locale.h>
44-
#endif
45-
4642
/* Initialization/Query functions */
4743
static int X11_VideoInit(_THIS);
4844
static void X11_VideoQuit(_THIS);
@@ -388,65 +384,6 @@ X11_VideoInit(_THIS)
388384
/* I have no idea how random this actually is, or has to be. */
389385
data->window_group = (XID) (((size_t) data->pid) ^ ((size_t) _this));
390386

391-
/* Open a connection to the X input manager */
392-
#ifdef X_HAVE_UTF8_STRING
393-
if (SDL_X11_HAVE_UTF8) {
394-
/* Set the locale, and call XSetLocaleModifiers before XOpenIM so that
395-
Compose keys will work correctly. */
396-
char *prev_locale = setlocale(LC_ALL, NULL);
397-
char *prev_xmods = X11_XSetLocaleModifiers(NULL);
398-
const char *new_xmods = "";
399-
#if defined(HAVE_IBUS_IBUS_H) || defined(HAVE_FCITX_FRONTEND_H)
400-
const char *env_xmods = SDL_getenv("XMODIFIERS");
401-
#endif
402-
SDL_bool has_dbus_ime_support = SDL_FALSE;
403-
404-
if (prev_locale) {
405-
prev_locale = SDL_strdup(prev_locale);
406-
}
407-
408-
if (prev_xmods) {
409-
prev_xmods = SDL_strdup(prev_xmods);
410-
}
411-
412-
/* IBus resends some key events that were filtered by XFilterEvents
413-
when it is used via XIM which causes issues. Prevent this by forcing
414-
@im=none if XMODIFIERS contains @im=ibus. IBus can still be used via
415-
the DBus implementation, which also has support for pre-editing. */
416-
#ifdef HAVE_IBUS_IBUS_H
417-
if (env_xmods && SDL_strstr(env_xmods, "@im=ibus") != NULL) {
418-
has_dbus_ime_support = SDL_TRUE;
419-
}
420-
#endif
421-
#ifdef HAVE_FCITX_FRONTEND_H
422-
if (env_xmods && SDL_strstr(env_xmods, "@im=fcitx") != NULL) {
423-
has_dbus_ime_support = SDL_TRUE;
424-
}
425-
#endif
426-
if (has_dbus_ime_support) {
427-
new_xmods = "@im=none";
428-
}
429-
430-
setlocale(LC_ALL, "");
431-
X11_XSetLocaleModifiers(new_xmods);
432-
433-
data->im = X11_XOpenIM(data->display, NULL, data->classname, data->classname);
434-
435-
/* Reset the locale + X locale modifiers back to how they were,
436-
locale first because the X locale modifiers depend on it. */
437-
setlocale(LC_ALL, prev_locale);
438-
X11_XSetLocaleModifiers(prev_xmods);
439-
440-
if (prev_locale) {
441-
SDL_free(prev_locale);
442-
}
443-
444-
if (prev_xmods) {
445-
SDL_free(prev_xmods);
446-
}
447-
}
448-
#endif
449-
450387
/* Look up some useful Atoms */
451388
#define GET_ATOM(X) data->X = X11_XInternAtom(data->display, #X, False)
452389
GET_ATOM(WM_PROTOCOLS);

0 commit comments

Comments
 (0)