1 | /* |
2 | Simple DirectMedia Layer |
3 | Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org> |
4 | |
5 | This software is provided 'as-is', without any express or implied |
6 | warranty. In no event will the authors be held liable for any damages |
7 | arising from the use of this software. |
8 | |
9 | Permission is granted to anyone to use this software for any purpose, |
10 | including commercial applications, and to alter it and redistribute it |
11 | freely, subject to the following restrictions: |
12 | |
13 | 1. The origin of this software must not be misrepresented; you must not |
14 | claim that you wrote the original software. If you use this software |
15 | in a product, an acknowledgment in the product documentation would be |
16 | appreciated but is not required. |
17 | 2. Altered source versions must be plainly marked as such, and must not be |
18 | misrepresented as being the original software. |
19 | 3. This notice may not be removed or altered from any source distribution. |
20 | */ |
21 | #include "../../SDL_internal.h" |
22 | |
23 | #if SDL_VIDEO_DRIVER_X11 |
24 | |
25 | #include "SDL_x11video.h" |
26 | |
27 | #include "../../events/SDL_keyboard_c.h" |
28 | #include "../../events/scancodes_darwin.h" |
29 | #include "../../events/scancodes_xfree86.h" |
30 | |
31 | #include <X11/keysym.h> |
32 | #include <X11/XKBlib.h> |
33 | |
34 | #include "imKStoUCS.h" |
35 | |
36 | #ifdef X_HAVE_UTF8_STRING |
37 | #include <locale.h> |
38 | #endif |
39 | |
40 | /* *INDENT-OFF* */ |
41 | static const struct { |
42 | KeySym keysym; |
43 | SDL_Scancode scancode; |
44 | } KeySymToSDLScancode[] = { |
45 | { XK_Return, SDL_SCANCODE_RETURN }, |
46 | { XK_Escape, SDL_SCANCODE_ESCAPE }, |
47 | { XK_BackSpace, SDL_SCANCODE_BACKSPACE }, |
48 | { XK_Tab, SDL_SCANCODE_TAB }, |
49 | { XK_Caps_Lock, SDL_SCANCODE_CAPSLOCK }, |
50 | { XK_F1, SDL_SCANCODE_F1 }, |
51 | { XK_F2, SDL_SCANCODE_F2 }, |
52 | { XK_F3, SDL_SCANCODE_F3 }, |
53 | { XK_F4, SDL_SCANCODE_F4 }, |
54 | { XK_F5, SDL_SCANCODE_F5 }, |
55 | { XK_F6, SDL_SCANCODE_F6 }, |
56 | { XK_F7, SDL_SCANCODE_F7 }, |
57 | { XK_F8, SDL_SCANCODE_F8 }, |
58 | { XK_F9, SDL_SCANCODE_F9 }, |
59 | { XK_F10, SDL_SCANCODE_F10 }, |
60 | { XK_F11, SDL_SCANCODE_F11 }, |
61 | { XK_F12, SDL_SCANCODE_F12 }, |
62 | { XK_Print, SDL_SCANCODE_PRINTSCREEN }, |
63 | { XK_Scroll_Lock, SDL_SCANCODE_SCROLLLOCK }, |
64 | { XK_Pause, SDL_SCANCODE_PAUSE }, |
65 | { XK_Insert, SDL_SCANCODE_INSERT }, |
66 | { XK_Home, SDL_SCANCODE_HOME }, |
67 | { XK_Prior, SDL_SCANCODE_PAGEUP }, |
68 | { XK_Delete, SDL_SCANCODE_DELETE }, |
69 | { XK_End, SDL_SCANCODE_END }, |
70 | { XK_Next, SDL_SCANCODE_PAGEDOWN }, |
71 | { XK_Right, SDL_SCANCODE_RIGHT }, |
72 | { XK_Left, SDL_SCANCODE_LEFT }, |
73 | { XK_Down, SDL_SCANCODE_DOWN }, |
74 | { XK_Up, SDL_SCANCODE_UP }, |
75 | { XK_Num_Lock, SDL_SCANCODE_NUMLOCKCLEAR }, |
76 | { XK_KP_Divide, SDL_SCANCODE_KP_DIVIDE }, |
77 | { XK_KP_Multiply, SDL_SCANCODE_KP_MULTIPLY }, |
78 | { XK_KP_Subtract, SDL_SCANCODE_KP_MINUS }, |
79 | { XK_KP_Add, SDL_SCANCODE_KP_PLUS }, |
80 | { XK_KP_Enter, SDL_SCANCODE_KP_ENTER }, |
81 | { XK_KP_Delete, SDL_SCANCODE_KP_PERIOD }, |
82 | { XK_KP_End, SDL_SCANCODE_KP_1 }, |
83 | { XK_KP_Down, SDL_SCANCODE_KP_2 }, |
84 | { XK_KP_Next, SDL_SCANCODE_KP_3 }, |
85 | { XK_KP_Left, SDL_SCANCODE_KP_4 }, |
86 | { XK_KP_Begin, SDL_SCANCODE_KP_5 }, |
87 | { XK_KP_Right, SDL_SCANCODE_KP_6 }, |
88 | { XK_KP_Home, SDL_SCANCODE_KP_7 }, |
89 | { XK_KP_Up, SDL_SCANCODE_KP_8 }, |
90 | { XK_KP_Prior, SDL_SCANCODE_KP_9 }, |
91 | { XK_KP_Insert, SDL_SCANCODE_KP_0 }, |
92 | { XK_KP_Decimal, SDL_SCANCODE_KP_PERIOD }, |
93 | { XK_KP_1, SDL_SCANCODE_KP_1 }, |
94 | { XK_KP_2, SDL_SCANCODE_KP_2 }, |
95 | { XK_KP_3, SDL_SCANCODE_KP_3 }, |
96 | { XK_KP_4, SDL_SCANCODE_KP_4 }, |
97 | { XK_KP_5, SDL_SCANCODE_KP_5 }, |
98 | { XK_KP_6, SDL_SCANCODE_KP_6 }, |
99 | { XK_KP_7, SDL_SCANCODE_KP_7 }, |
100 | { XK_KP_8, SDL_SCANCODE_KP_8 }, |
101 | { XK_KP_9, SDL_SCANCODE_KP_9 }, |
102 | { XK_KP_0, SDL_SCANCODE_KP_0 }, |
103 | { XK_KP_Decimal, SDL_SCANCODE_KP_PERIOD }, |
104 | { XK_Hyper_R, SDL_SCANCODE_APPLICATION }, |
105 | { XK_KP_Equal, SDL_SCANCODE_KP_EQUALS }, |
106 | { XK_F13, SDL_SCANCODE_F13 }, |
107 | { XK_F14, SDL_SCANCODE_F14 }, |
108 | { XK_F15, SDL_SCANCODE_F15 }, |
109 | { XK_F16, SDL_SCANCODE_F16 }, |
110 | { XK_F17, SDL_SCANCODE_F17 }, |
111 | { XK_F18, SDL_SCANCODE_F18 }, |
112 | { XK_F19, SDL_SCANCODE_F19 }, |
113 | { XK_F20, SDL_SCANCODE_F20 }, |
114 | { XK_F21, SDL_SCANCODE_F21 }, |
115 | { XK_F22, SDL_SCANCODE_F22 }, |
116 | { XK_F23, SDL_SCANCODE_F23 }, |
117 | { XK_F24, SDL_SCANCODE_F24 }, |
118 | { XK_Execute, SDL_SCANCODE_EXECUTE }, |
119 | { XK_Help, SDL_SCANCODE_HELP }, |
120 | { XK_Menu, SDL_SCANCODE_MENU }, |
121 | { XK_Select, SDL_SCANCODE_SELECT }, |
122 | { XK_Cancel, SDL_SCANCODE_STOP }, |
123 | { XK_Redo, SDL_SCANCODE_AGAIN }, |
124 | { XK_Undo, SDL_SCANCODE_UNDO }, |
125 | { XK_Find, SDL_SCANCODE_FIND }, |
126 | { XK_KP_Separator, SDL_SCANCODE_KP_COMMA }, |
127 | { XK_Sys_Req, SDL_SCANCODE_SYSREQ }, |
128 | { XK_Control_L, SDL_SCANCODE_LCTRL }, |
129 | { XK_Shift_L, SDL_SCANCODE_LSHIFT }, |
130 | { XK_Alt_L, SDL_SCANCODE_LALT }, |
131 | { XK_Meta_L, SDL_SCANCODE_LGUI }, |
132 | { XK_Super_L, SDL_SCANCODE_LGUI }, |
133 | { XK_Control_R, SDL_SCANCODE_RCTRL }, |
134 | { XK_Shift_R, SDL_SCANCODE_RSHIFT }, |
135 | { XK_Alt_R, SDL_SCANCODE_RALT }, |
136 | { XK_ISO_Level3_Shift, SDL_SCANCODE_RALT }, |
137 | { XK_Meta_R, SDL_SCANCODE_RGUI }, |
138 | { XK_Super_R, SDL_SCANCODE_RGUI }, |
139 | { XK_Mode_switch, SDL_SCANCODE_MODE }, |
140 | { XK_period, SDL_SCANCODE_PERIOD }, |
141 | { XK_comma, SDL_SCANCODE_COMMA }, |
142 | { XK_slash, SDL_SCANCODE_SLASH }, |
143 | { XK_backslash, SDL_SCANCODE_BACKSLASH }, |
144 | { XK_minus, SDL_SCANCODE_MINUS }, |
145 | { XK_equal, SDL_SCANCODE_EQUALS }, |
146 | { XK_space, SDL_SCANCODE_SPACE }, |
147 | { XK_grave, SDL_SCANCODE_GRAVE }, |
148 | { XK_apostrophe, SDL_SCANCODE_APOSTROPHE }, |
149 | { XK_bracketleft, SDL_SCANCODE_LEFTBRACKET }, |
150 | { XK_bracketright, SDL_SCANCODE_RIGHTBRACKET }, |
151 | }; |
152 | |
153 | static const struct |
154 | { |
155 | SDL_Scancode const *table; |
156 | int table_size; |
157 | } scancode_set[] = { |
158 | { darwin_scancode_table, SDL_arraysize(darwin_scancode_table) }, |
159 | { xfree86_scancode_table, SDL_arraysize(xfree86_scancode_table) }, |
160 | { xfree86_scancode_table2, SDL_arraysize(xfree86_scancode_table2) }, |
161 | { xvnc_scancode_table, SDL_arraysize(xvnc_scancode_table) }, |
162 | }; |
163 | /* *INDENT-OFF* */ |
164 | |
165 | /* This function only works for keyboards in US QWERTY layout */ |
166 | static SDL_Scancode |
167 | X11_KeyCodeToSDLScancode(_THIS, KeyCode keycode) |
168 | { |
169 | KeySym keysym; |
170 | int i; |
171 | |
172 | keysym = X11_KeyCodeToSym(_this, keycode, 0); |
173 | if (keysym == NoSymbol) { |
174 | return SDL_SCANCODE_UNKNOWN; |
175 | } |
176 | |
177 | if (keysym >= XK_a && keysym <= XK_z) { |
178 | return SDL_SCANCODE_A + (keysym - XK_a); |
179 | } |
180 | if (keysym >= XK_A && keysym <= XK_Z) { |
181 | return SDL_SCANCODE_A + (keysym - XK_A); |
182 | } |
183 | |
184 | if (keysym == XK_0) { |
185 | return SDL_SCANCODE_0; |
186 | } |
187 | if (keysym >= XK_1 && keysym <= XK_9) { |
188 | return SDL_SCANCODE_1 + (keysym - XK_1); |
189 | } |
190 | |
191 | for (i = 0; i < SDL_arraysize(KeySymToSDLScancode); ++i) { |
192 | if (keysym == KeySymToSDLScancode[i].keysym) { |
193 | return KeySymToSDLScancode[i].scancode; |
194 | } |
195 | } |
196 | return SDL_SCANCODE_UNKNOWN; |
197 | } |
198 | |
199 | static Uint32 |
200 | X11_KeyCodeToUcs4(_THIS, KeyCode keycode, unsigned char group) |
201 | { |
202 | KeySym keysym = X11_KeyCodeToSym(_this, keycode, group); |
203 | |
204 | if (keysym == NoSymbol) { |
205 | return 0; |
206 | } |
207 | |
208 | return X11_KeySymToUcs4(keysym); |
209 | } |
210 | |
211 | KeySym |
212 | X11_KeyCodeToSym(_THIS, KeyCode keycode, unsigned char group) |
213 | { |
214 | SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; |
215 | KeySym keysym; |
216 | |
217 | #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM |
218 | if (data->xkb) { |
219 | int num_groups = XkbKeyNumGroups(data->xkb, keycode); |
220 | unsigned char info = XkbKeyGroupInfo(data->xkb, keycode); |
221 | |
222 | if (num_groups && group >= num_groups) { |
223 | |
224 | int action = XkbOutOfRangeGroupAction(info); |
225 | |
226 | if (action == XkbRedirectIntoRange) { |
227 | if ((group = XkbOutOfRangeGroupNumber(info)) >= num_groups) { |
228 | group = 0; |
229 | } |
230 | } else if (action == XkbClampIntoRange) { |
231 | group = num_groups - 1; |
232 | } else { |
233 | group %= num_groups; |
234 | } |
235 | } |
236 | keysym = X11_XkbKeycodeToKeysym(data->display, keycode, group, 0); |
237 | } else { |
238 | keysym = X11_XKeycodeToKeysym(data->display, keycode, 0); |
239 | } |
240 | #else |
241 | keysym = X11_XKeycodeToKeysym(data->display, keycode, 0); |
242 | #endif |
243 | |
244 | return keysym; |
245 | } |
246 | |
247 | int |
248 | X11_InitKeyboard(_THIS) |
249 | { |
250 | SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; |
251 | int i = 0; |
252 | int j = 0; |
253 | int min_keycode, max_keycode; |
254 | struct { |
255 | SDL_Scancode scancode; |
256 | KeySym keysym; |
257 | int value; |
258 | } fingerprint[] = { |
259 | { SDL_SCANCODE_HOME, XK_Home, 0 }, |
260 | { SDL_SCANCODE_PAGEUP, XK_Prior, 0 }, |
261 | { SDL_SCANCODE_UP, XK_Up, 0 }, |
262 | { SDL_SCANCODE_LEFT, XK_Left, 0 }, |
263 | { SDL_SCANCODE_DELETE, XK_Delete, 0 }, |
264 | { SDL_SCANCODE_KP_ENTER, XK_KP_Enter, 0 }, |
265 | }; |
266 | int best_distance; |
267 | int best_index; |
268 | int distance; |
269 | Bool xkb_repeat = 0; |
270 | XKeyboardState values = { .global_auto_repeat = AutoRepeatModeOff }; |
271 | |
272 | X11_XGetKeyboardControl(data->display, &values); |
273 | if (values.global_auto_repeat != AutoRepeatModeOn) |
274 | X11_XAutoRepeatOn(data->display); |
275 | |
276 | #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM |
277 | { |
278 | int xkb_major = XkbMajorVersion; |
279 | int xkb_minor = XkbMinorVersion; |
280 | |
281 | if (X11_XkbQueryExtension(data->display, NULL, NULL, NULL, &xkb_major, &xkb_minor)) { |
282 | data->xkb = X11_XkbGetMap(data->display, XkbAllClientInfoMask, XkbUseCoreKbd); |
283 | } |
284 | |
285 | /* This will remove KeyRelease events for held keys */ |
286 | X11_XkbSetDetectableAutoRepeat(data->display, True, &xkb_repeat); |
287 | } |
288 | #endif |
289 | |
290 | /* Open a connection to the X input manager */ |
291 | #ifdef X_HAVE_UTF8_STRING |
292 | if (SDL_X11_HAVE_UTF8) { |
293 | /* Set the locale, and call XSetLocaleModifiers before XOpenIM so that |
294 | Compose keys will work correctly. */ |
295 | char *prev_locale = setlocale(LC_ALL, NULL); |
296 | char *prev_xmods = X11_XSetLocaleModifiers(NULL); |
297 | const char *new_xmods = "" ; |
298 | const char *env_xmods = SDL_getenv("XMODIFIERS" ); |
299 | SDL_bool has_dbus_ime_support = SDL_FALSE; |
300 | |
301 | if (prev_locale) { |
302 | prev_locale = SDL_strdup(prev_locale); |
303 | } |
304 | |
305 | if (prev_xmods) { |
306 | prev_xmods = SDL_strdup(prev_xmods); |
307 | } |
308 | |
309 | /* IBus resends some key events that were filtered by XFilterEvents |
310 | when it is used via XIM which causes issues. Prevent this by forcing |
311 | @im=none if XMODIFIERS contains @im=ibus. IBus can still be used via |
312 | the DBus implementation, which also has support for pre-editing. */ |
313 | if (env_xmods && SDL_strstr(env_xmods, "@im=ibus" ) != NULL) { |
314 | has_dbus_ime_support = SDL_TRUE; |
315 | } |
316 | if (env_xmods && SDL_strstr(env_xmods, "@im=fcitx" ) != NULL) { |
317 | has_dbus_ime_support = SDL_TRUE; |
318 | } |
319 | if (has_dbus_ime_support || !xkb_repeat) { |
320 | new_xmods = "@im=none" ; |
321 | } |
322 | |
323 | setlocale(LC_ALL, "" ); |
324 | X11_XSetLocaleModifiers(new_xmods); |
325 | |
326 | data->im = X11_XOpenIM(data->display, NULL, data->classname, data->classname); |
327 | |
328 | /* Reset the locale + X locale modifiers back to how they were, |
329 | locale first because the X locale modifiers depend on it. */ |
330 | setlocale(LC_ALL, prev_locale); |
331 | X11_XSetLocaleModifiers(prev_xmods); |
332 | |
333 | if (prev_locale) { |
334 | SDL_free(prev_locale); |
335 | } |
336 | |
337 | if (prev_xmods) { |
338 | SDL_free(prev_xmods); |
339 | } |
340 | } |
341 | #endif |
342 | /* Try to determine which scancodes are being used based on fingerprint */ |
343 | best_distance = SDL_arraysize(fingerprint) + 1; |
344 | best_index = -1; |
345 | X11_XDisplayKeycodes(data->display, &min_keycode, &max_keycode); |
346 | for (i = 0; i < SDL_arraysize(fingerprint); ++i) { |
347 | fingerprint[i].value = |
348 | X11_XKeysymToKeycode(data->display, fingerprint[i].keysym) - |
349 | min_keycode; |
350 | } |
351 | for (i = 0; i < SDL_arraysize(scancode_set); ++i) { |
352 | /* Make sure the scancode set isn't too big */ |
353 | if ((max_keycode - min_keycode + 1) <= scancode_set[i].table_size) { |
354 | continue; |
355 | } |
356 | distance = 0; |
357 | for (j = 0; j < SDL_arraysize(fingerprint); ++j) { |
358 | if (fingerprint[j].value < 0 |
359 | || fingerprint[j].value >= scancode_set[i].table_size) { |
360 | distance += 1; |
361 | } else if (scancode_set[i].table[fingerprint[j].value] != fingerprint[j].scancode) { |
362 | distance += 1; |
363 | } |
364 | } |
365 | if (distance < best_distance) { |
366 | best_distance = distance; |
367 | best_index = i; |
368 | } |
369 | } |
370 | if (best_index >= 0 && best_distance <= 2) { |
371 | #ifdef DEBUG_KEYBOARD |
372 | printf("Using scancode set %d, min_keycode = %d, max_keycode = %d, table_size = %d\n" , best_index, min_keycode, max_keycode, scancode_set[best_index].table_size); |
373 | #endif |
374 | SDL_memcpy(&data->key_layout[min_keycode], scancode_set[best_index].table, |
375 | sizeof(SDL_Scancode) * scancode_set[best_index].table_size); |
376 | } else { |
377 | SDL_Keycode keymap[SDL_NUM_SCANCODES]; |
378 | |
379 | printf |
380 | ("Keyboard layout unknown, please report the following to the SDL forums/mailing list (https://discourse.libsdl.org/):\n" ); |
381 | |
382 | /* Determine key_layout - only works on US QWERTY layout */ |
383 | SDL_GetDefaultKeymap(keymap); |
384 | for (i = min_keycode; i <= max_keycode; ++i) { |
385 | KeySym sym; |
386 | sym = X11_KeyCodeToSym(_this, (KeyCode) i, 0); |
387 | if (sym != NoSymbol) { |
388 | SDL_Scancode scancode; |
389 | printf("code = %d, sym = 0x%X (%s) " , i - min_keycode, |
390 | (unsigned int) sym, X11_XKeysymToString(sym)); |
391 | scancode = X11_KeyCodeToSDLScancode(_this, i); |
392 | data->key_layout[i] = scancode; |
393 | if (scancode == SDL_SCANCODE_UNKNOWN) { |
394 | printf("scancode not found\n" ); |
395 | } else { |
396 | printf("scancode = %d (%s)\n" , scancode, SDL_GetScancodeName(scancode)); |
397 | } |
398 | } |
399 | } |
400 | } |
401 | |
402 | X11_UpdateKeymap(_this); |
403 | |
404 | SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu" ); |
405 | |
406 | #ifdef SDL_USE_IME |
407 | SDL_IME_Init(); |
408 | #endif |
409 | |
410 | return 0; |
411 | } |
412 | |
413 | void |
414 | X11_UpdateKeymap(_THIS) |
415 | { |
416 | SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; |
417 | int i; |
418 | SDL_Scancode scancode; |
419 | SDL_Keycode keymap[SDL_NUM_SCANCODES]; |
420 | unsigned char group = 0; |
421 | |
422 | SDL_GetDefaultKeymap(keymap); |
423 | |
424 | #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM |
425 | if (data->xkb) { |
426 | XkbStateRec state; |
427 | X11_XkbGetUpdatedMap(data->display, XkbAllClientInfoMask, data->xkb); |
428 | |
429 | if (X11_XkbGetState(data->display, XkbUseCoreKbd, &state) == Success) { |
430 | group = state.group; |
431 | } |
432 | } |
433 | #endif |
434 | |
435 | |
436 | for (i = 0; i < SDL_arraysize(data->key_layout); i++) { |
437 | Uint32 key; |
438 | |
439 | /* Make sure this is a valid scancode */ |
440 | scancode = data->key_layout[i]; |
441 | if (scancode == SDL_SCANCODE_UNKNOWN) { |
442 | continue; |
443 | } |
444 | |
445 | /* See if there is a UCS keycode for this scancode */ |
446 | key = X11_KeyCodeToUcs4(_this, (KeyCode)i, group); |
447 | if (key) { |
448 | keymap[scancode] = key; |
449 | } else { |
450 | SDL_Scancode keyScancode = X11_KeyCodeToSDLScancode(_this, (KeyCode)i); |
451 | |
452 | switch (keyScancode) { |
453 | case SDL_SCANCODE_RETURN: |
454 | keymap[scancode] = SDLK_RETURN; |
455 | break; |
456 | case SDL_SCANCODE_ESCAPE: |
457 | keymap[scancode] = SDLK_ESCAPE; |
458 | break; |
459 | case SDL_SCANCODE_BACKSPACE: |
460 | keymap[scancode] = SDLK_BACKSPACE; |
461 | break; |
462 | case SDL_SCANCODE_TAB: |
463 | keymap[scancode] = SDLK_TAB; |
464 | break; |
465 | case SDL_SCANCODE_DELETE: |
466 | keymap[scancode] = SDLK_DELETE; |
467 | break; |
468 | default: |
469 | keymap[scancode] = SDL_SCANCODE_TO_KEYCODE(keyScancode); |
470 | break; |
471 | } |
472 | } |
473 | } |
474 | SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES); |
475 | } |
476 | |
477 | void |
478 | X11_QuitKeyboard(_THIS) |
479 | { |
480 | SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; |
481 | |
482 | #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM |
483 | if (data->xkb) { |
484 | X11_XkbFreeKeyboard(data->xkb, 0, True); |
485 | data->xkb = NULL; |
486 | } |
487 | #endif |
488 | |
489 | #ifdef SDL_USE_IME |
490 | SDL_IME_Quit(); |
491 | #endif |
492 | } |
493 | |
494 | static void |
495 | X11_ResetXIM(_THIS) |
496 | { |
497 | #ifdef X_HAVE_UTF8_STRING |
498 | SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata; |
499 | int i; |
500 | |
501 | if (videodata && videodata->windowlist) { |
502 | for (i = 0; i < videodata->numwindows; ++i) { |
503 | SDL_WindowData *data = videodata->windowlist[i]; |
504 | if (data && data->ic) { |
505 | /* Clear any partially entered dead keys */ |
506 | char *contents = X11_Xutf8ResetIC(data->ic); |
507 | if (contents) { |
508 | X11_XFree(contents); |
509 | } |
510 | } |
511 | } |
512 | } |
513 | #endif |
514 | } |
515 | |
516 | void |
517 | X11_StartTextInput(_THIS) |
518 | { |
519 | X11_ResetXIM(_this); |
520 | } |
521 | |
522 | void |
523 | X11_StopTextInput(_THIS) |
524 | { |
525 | X11_ResetXIM(_this); |
526 | #ifdef SDL_USE_IME |
527 | SDL_IME_Reset(); |
528 | #endif |
529 | } |
530 | |
531 | void |
532 | X11_SetTextInputRect(_THIS, SDL_Rect *rect) |
533 | { |
534 | if (!rect) { |
535 | SDL_InvalidParamError("rect" ); |
536 | return; |
537 | } |
538 | |
539 | #ifdef SDL_USE_IME |
540 | SDL_IME_UpdateTextRect(rect); |
541 | #endif |
542 | } |
543 | |
544 | #endif /* SDL_VIDEO_DRIVER_X11 */ |
545 | |
546 | /* vi: set ts=4 sw=4 expandtab: */ |
547 | |