|
33 | 33 |
|
34 | 34 | #include "imKStoUCS.h" |
35 | 35 |
|
| 36 | +#ifdef X_HAVE_UTF8_STRING |
| 37 | +#include <locale.h> |
| 38 | +#endif |
| 39 | + |
36 | 40 | /* *INDENT-OFF* */ |
37 | 41 | static const struct { |
38 | 42 | KeySym keysym; |
@@ -262,19 +266,82 @@ X11_InitKeyboard(_THIS) |
262 | 266 | int best_distance; |
263 | 267 | int best_index; |
264 | 268 | int distance; |
265 | | - |
| 269 | + BOOL xkb_repeat = 0; |
| 270 | + |
266 | 271 | X11_XAutoRepeatOn(data->display); |
267 | 272 |
|
268 | 273 | #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM |
269 | 274 | { |
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 | + } |
276 | 316 | #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); |
277 | 328 |
|
| 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 |
278 | 345 | /* Try to determine which scancodes are being used based on fingerprint */ |
279 | 346 | best_distance = SDL_arraysize(fingerprint) + 1; |
280 | 347 | best_index = -1; |
|
0 commit comments