SDL  2.0
SDL_ibus.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2016 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 #ifdef HAVE_IBUS_IBUS_H
24 #include "SDL.h"
25 #include "SDL_syswm.h"
26 #include "SDL_ibus.h"
27 #include "SDL_dbus.h"
28 #include "../../video/SDL_sysvideo.h"
29 #include "../../events/SDL_keyboard_c.h"
30 
31 #if SDL_VIDEO_DRIVER_X11
32  #include "../../video/x11/SDL_x11video.h"
33 #endif
34 
35 #include <sys/inotify.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 
39 static const char IBUS_SERVICE[] = "org.freedesktop.IBus";
40 static const char IBUS_PATH[] = "/org/freedesktop/IBus";
41 static const char IBUS_INTERFACE[] = "org.freedesktop.IBus";
42 static const char IBUS_INPUT_INTERFACE[] = "org.freedesktop.IBus.InputContext";
43 
44 static char *input_ctx_path = NULL;
45 static SDL_Rect ibus_cursor_rect = {0};
46 static DBusConnection *ibus_conn = NULL;
47 static char *ibus_addr_file = NULL;
48 int inotify_fd = -1, inotify_wd = -1;
49 
50 static Uint32
51 IBus_ModState(void)
52 {
53  Uint32 ibus_mods = 0;
54  SDL_Keymod sdl_mods = SDL_GetModState();
55 
56  /* Not sure about MOD3, MOD4 and HYPER mappings */
57  if (sdl_mods & KMOD_LSHIFT) ibus_mods |= IBUS_SHIFT_MASK;
58  if (sdl_mods & KMOD_CAPS) ibus_mods |= IBUS_LOCK_MASK;
59  if (sdl_mods & KMOD_LCTRL) ibus_mods |= IBUS_CONTROL_MASK;
60  if (sdl_mods & KMOD_LALT) ibus_mods |= IBUS_MOD1_MASK;
61  if (sdl_mods & KMOD_NUM) ibus_mods |= IBUS_MOD2_MASK;
62  if (sdl_mods & KMOD_MODE) ibus_mods |= IBUS_MOD5_MASK;
63  if (sdl_mods & KMOD_LGUI) ibus_mods |= IBUS_SUPER_MASK;
64  if (sdl_mods & KMOD_RGUI) ibus_mods |= IBUS_META_MASK;
65 
66  return ibus_mods;
67 }
68 
69 static const char *
70 IBus_GetVariantText(DBusConnection *conn, DBusMessageIter *iter, SDL_DBusContext *dbus)
71 {
72  /* The text we need is nested weirdly, use dbus-monitor to see the structure better */
73  const char *text = NULL;
74  const char *struct_id = NULL;
75  DBusMessageIter sub1, sub2;
76 
77  if (dbus->message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT) {
78  return NULL;
79  }
80 
81  dbus->message_iter_recurse(iter, &sub1);
82 
83  if (dbus->message_iter_get_arg_type(&sub1) != DBUS_TYPE_STRUCT) {
84  return NULL;
85  }
86 
87  dbus->message_iter_recurse(&sub1, &sub2);
88 
89  if (dbus->message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
90  return NULL;
91  }
92 
93  dbus->message_iter_get_basic(&sub2, &struct_id);
94  if (!struct_id || SDL_strncmp(struct_id, "IBusText", sizeof("IBusText")) != 0) {
95  return NULL;
96  }
97 
98  dbus->message_iter_next(&sub2);
99  dbus->message_iter_next(&sub2);
100 
101  if (dbus->message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
102  return NULL;
103  }
104 
105  dbus->message_iter_get_basic(&sub2, &text);
106 
107  return text;
108 }
109 
110 static size_t
111 IBus_utf8_strlen(const char *str)
112 {
113  size_t utf8_len = 0;
114  const char *p;
115 
116  for (p = str; *p; ++p) {
117  if (!((*p & 0x80) && !(*p & 0x40))) {
118  ++utf8_len;
119  }
120  }
121 
122  return utf8_len;
123 }
124 
125 static DBusHandlerResult
126 IBus_MessageHandler(DBusConnection *conn, DBusMessage *msg, void *user_data)
127 {
128  SDL_DBusContext *dbus = (SDL_DBusContext *)user_data;
129 
130  if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "CommitText")) {
131  DBusMessageIter iter;
132  const char *text;
133 
134  dbus->message_iter_init(msg, &iter);
135 
136  text = IBus_GetVariantText(conn, &iter, dbus);
137  if (text && *text) {
139  size_t text_bytes = SDL_strlen(text), i = 0;
140 
141  while (i < text_bytes) {
142  size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
144 
145  i += sz;
146  }
147  }
148 
149  return DBUS_HANDLER_RESULT_HANDLED;
150  }
151 
152  if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "UpdatePreeditText")) {
153  DBusMessageIter iter;
154  const char *text;
155 
156  dbus->message_iter_init(msg, &iter);
157  text = IBus_GetVariantText(conn, &iter, dbus);
158 
159  if (text) {
161  size_t text_bytes = SDL_strlen(text), i = 0;
162  size_t cursor = 0;
163 
164  do {
165  size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
166  size_t chars = IBus_utf8_strlen(buf);
167 
168  SDL_SendEditingText(buf, cursor, chars);
169 
170  i += sz;
171  cursor += chars;
172  } while (i < text_bytes);
173  }
174 
175  SDL_IBus_UpdateTextRect(NULL);
176 
177  return DBUS_HANDLER_RESULT_HANDLED;
178  }
179 
180  if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "HidePreeditText")) {
181  SDL_SendEditingText("", 0, 0);
182  return DBUS_HANDLER_RESULT_HANDLED;
183  }
184 
185  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
186 }
187 
188 static char *
189 IBus_ReadAddressFromFile(const char *file_path)
190 {
191  char addr_buf[1024];
192  SDL_bool success = SDL_FALSE;
193  FILE *addr_file;
194 
195  addr_file = fopen(file_path, "r");
196  if (!addr_file) {
197  return NULL;
198  }
199 
200  while (fgets(addr_buf, sizeof(addr_buf), addr_file)) {
201  if (SDL_strncmp(addr_buf, "IBUS_ADDRESS=", sizeof("IBUS_ADDRESS=")-1) == 0) {
202  size_t sz = SDL_strlen(addr_buf);
203  if (addr_buf[sz-1] == '\n') addr_buf[sz-1] = 0;
204  if (addr_buf[sz-2] == '\r') addr_buf[sz-2] = 0;
205  success = SDL_TRUE;
206  break;
207  }
208  }
209 
210  fclose(addr_file);
211 
212  if (success) {
213  return SDL_strdup(addr_buf + (sizeof("IBUS_ADDRESS=") - 1));
214  } else {
215  return NULL;
216  }
217 }
218 
219 static char *
220 IBus_GetDBusAddressFilename(void)
221 {
222  SDL_DBusContext *dbus;
223  const char *disp_env;
224  char config_dir[PATH_MAX];
225  char *display = NULL;
226  const char *addr;
227  const char *conf_env;
228  char *key;
229  char file_path[PATH_MAX];
230  const char *host;
231  char *disp_num, *screen_num;
232 
233  if (ibus_addr_file) {
234  return SDL_strdup(ibus_addr_file);
235  }
236 
237  dbus = SDL_DBus_GetContext();
238  if (!dbus) {
239  return NULL;
240  }
241 
242  /* Use this environment variable if it exists. */
243  addr = SDL_getenv("IBUS_ADDRESS");
244  if (addr && *addr) {
245  return SDL_strdup(addr);
246  }
247 
248  /* Otherwise, we have to get the hostname, display, machine id, config dir
249  and look up the address from a filepath using all those bits, eek. */
250  disp_env = SDL_getenv("DISPLAY");
251 
252  if (!disp_env || !*disp_env) {
253  display = SDL_strdup(":0.0");
254  } else {
255  display = SDL_strdup(disp_env);
256  }
257 
258  host = display;
259  disp_num = SDL_strrchr(display, ':');
260  screen_num = SDL_strrchr(display, '.');
261 
262  if (!disp_num) {
263  SDL_free(display);
264  return NULL;
265  }
266 
267  *disp_num = 0;
268  disp_num++;
269 
270  if (screen_num) {
271  *screen_num = 0;
272  }
273 
274  if (!*host) {
275  host = "unix";
276  }
277 
278  SDL_memset(config_dir, 0, sizeof(config_dir));
279 
280  conf_env = SDL_getenv("XDG_CONFIG_HOME");
281  if (conf_env && *conf_env) {
282  SDL_strlcpy(config_dir, conf_env, sizeof(config_dir));
283  } else {
284  const char *home_env = SDL_getenv("HOME");
285  if (!home_env || !*home_env) {
286  SDL_free(display);
287  return NULL;
288  }
289  SDL_snprintf(config_dir, sizeof(config_dir), "%s/.config", home_env);
290  }
291 
292  key = dbus->get_local_machine_id();
293 
294  SDL_memset(file_path, 0, sizeof(file_path));
295  SDL_snprintf(file_path, sizeof(file_path), "%s/ibus/bus/%s-%s-%s",
296  config_dir, key, host, disp_num);
297  dbus->free(key);
298  SDL_free(display);
299 
300  return SDL_strdup(file_path);
301 }
302 
303 static SDL_bool IBus_CheckConnection(SDL_DBusContext *dbus);
304 
305 static void
306 IBus_SetCapabilities(void *data, const char *name, const char *old_val,
307  const char *internal_editing)
308 {
309  SDL_DBusContext *dbus = SDL_DBus_GetContext();
310 
311  if (IBus_CheckConnection(dbus)) {
312 
313  DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
314  input_ctx_path,
315  IBUS_INPUT_INTERFACE,
316  "SetCapabilities");
317  if (msg) {
318  Uint32 caps = IBUS_CAP_FOCUS;
319  if (!(internal_editing && *internal_editing == '1')) {
320  caps |= IBUS_CAP_PREEDIT_TEXT;
321  }
322 
323  dbus->message_append_args(msg,
324  DBUS_TYPE_UINT32, &caps,
325  DBUS_TYPE_INVALID);
326  }
327 
328  if (msg) {
329  if (dbus->connection_send(ibus_conn, msg, NULL)) {
330  dbus->connection_flush(ibus_conn);
331  }
332  dbus->message_unref(msg);
333  }
334  }
335 }
336 
337 
338 static SDL_bool
339 IBus_SetupConnection(SDL_DBusContext *dbus, const char* addr)
340 {
341  const char *path = NULL;
343  DBusMessage *msg;
344  DBusObjectPathVTable ibus_vtable = {0};
345  ibus_vtable.message_function = &IBus_MessageHandler;
346 
347  ibus_conn = dbus->connection_open_private(addr, NULL);
348 
349  if (!ibus_conn) {
350  return SDL_FALSE;
351  }
352 
353  dbus->connection_flush(ibus_conn);
354 
355  if (!dbus->bus_register(ibus_conn, NULL)) {
356  ibus_conn = NULL;
357  return SDL_FALSE;
358  }
359 
360  dbus->connection_flush(ibus_conn);
361 
362  msg = dbus->message_new_method_call(IBUS_SERVICE, IBUS_PATH, IBUS_INTERFACE, "CreateInputContext");
363  if (msg) {
364  const char *client_name = "SDL2_Application";
365  dbus->message_append_args(msg,
366  DBUS_TYPE_STRING, &client_name,
367  DBUS_TYPE_INVALID);
368  }
369 
370  if (msg) {
371  DBusMessage *reply;
372 
373  reply = dbus->connection_send_with_reply_and_block(ibus_conn, msg, 1000, NULL);
374  if (reply) {
375  if (dbus->message_get_args(reply, NULL,
376  DBUS_TYPE_OBJECT_PATH, &path,
377  DBUS_TYPE_INVALID)) {
378  if (input_ctx_path) {
379  SDL_free(input_ctx_path);
380  }
381  input_ctx_path = SDL_strdup(path);
382  result = SDL_TRUE;
383  }
384  dbus->message_unref(reply);
385  }
386  dbus->message_unref(msg);
387  }
388 
389  if (result) {
390  SDL_AddHintCallback(SDL_HINT_IME_INTERNAL_EDITING, &IBus_SetCapabilities, NULL);
391 
392  dbus->bus_add_match(ibus_conn, "type='signal',interface='org.freedesktop.IBus.InputContext'", NULL);
393  dbus->connection_try_register_object_path(ibus_conn, input_ctx_path, &ibus_vtable, dbus, NULL);
394  dbus->connection_flush(ibus_conn);
395  }
396 
397  SDL_IBus_SetFocus(SDL_GetKeyboardFocus() != NULL);
398  SDL_IBus_UpdateTextRect(NULL);
399 
400  return result;
401 }
402 
403 static SDL_bool
404 IBus_CheckConnection(SDL_DBusContext *dbus)
405 {
406  if (!dbus) return SDL_FALSE;
407 
408  if (ibus_conn && dbus->connection_get_is_connected(ibus_conn)) {
409  return SDL_TRUE;
410  }
411 
412  if (inotify_fd > 0 && inotify_wd > 0) {
413  char buf[1024];
414  ssize_t readsize = read(inotify_fd, buf, sizeof(buf));
415  if (readsize > 0) {
416 
417  char *p;
418  SDL_bool file_updated = SDL_FALSE;
419 
420  for (p = buf; p < buf + readsize; /**/) {
421  struct inotify_event *event = (struct inotify_event*) p;
422  if (event->len > 0) {
423  char *addr_file_no_path = SDL_strrchr(ibus_addr_file, '/');
424  if (!addr_file_no_path) return SDL_FALSE;
425 
426  if (SDL_strcmp(addr_file_no_path + 1, event->name) == 0) {
427  file_updated = SDL_TRUE;
428  break;
429  }
430  }
431 
432  p += sizeof(struct inotify_event) + event->len;
433  }
434 
435  if (file_updated) {
436  char *addr = IBus_ReadAddressFromFile(ibus_addr_file);
437  if (addr) {
438  SDL_bool result = IBus_SetupConnection(dbus, addr);
439  SDL_free(addr);
440  return result;
441  }
442  }
443  }
444  }
445 
446  return SDL_FALSE;
447 }
448 
449 SDL_bool
450 SDL_IBus_Init(void)
451 {
452  SDL_bool result = SDL_FALSE;
453  SDL_DBusContext *dbus = SDL_DBus_GetContext();
454 
455  if (dbus) {
456  char *addr_file = IBus_GetDBusAddressFilename();
457  char *addr;
458  char *addr_file_dir;
459 
460  if (!addr_file) {
461  return SDL_FALSE;
462  }
463 
464  /* !!! FIXME: if ibus_addr_file != NULL, this will overwrite it and leak (twice!) */
465  ibus_addr_file = SDL_strdup(addr_file);
466 
467  addr = IBus_ReadAddressFromFile(addr_file);
468  if (!addr) {
469  SDL_free(addr_file);
470  return SDL_FALSE;
471  }
472 
473  if (inotify_fd < 0) {
474  inotify_fd = inotify_init();
475  fcntl(inotify_fd, F_SETFL, O_NONBLOCK);
476  }
477 
478  addr_file_dir = SDL_strrchr(addr_file, '/');
479  if (addr_file_dir) {
480  *addr_file_dir = 0;
481  }
482 
483  inotify_wd = inotify_add_watch(inotify_fd, addr_file, IN_CREATE | IN_MODIFY);
484  SDL_free(addr_file);
485 
486  if (addr) {
487  result = IBus_SetupConnection(dbus, addr);
488  SDL_free(addr);
489  }
490  }
491 
492  return result;
493 }
494 
495 void
496 SDL_IBus_Quit(void)
497 {
498  SDL_DBusContext *dbus;
499 
500  if (input_ctx_path) {
501  SDL_free(input_ctx_path);
502  input_ctx_path = NULL;
503  }
504 
505  if (ibus_addr_file) {
506  SDL_free(ibus_addr_file);
507  ibus_addr_file = NULL;
508  }
509 
510  dbus = SDL_DBus_GetContext();
511 
512  if (dbus && ibus_conn) {
513  dbus->connection_close(ibus_conn);
514  dbus->connection_unref(ibus_conn);
515  }
516 
517  if (inotify_fd > 0 && inotify_wd > 0) {
518  inotify_rm_watch(inotify_fd, inotify_wd);
519  inotify_wd = -1;
520  }
521 
522  SDL_DelHintCallback(SDL_HINT_IME_INTERNAL_EDITING, &IBus_SetCapabilities, NULL);
523 
524  SDL_memset(&ibus_cursor_rect, 0, sizeof(ibus_cursor_rect));
525 }
526 
527 static void
528 IBus_SimpleMessage(const char *method)
529 {
530  SDL_DBusContext *dbus = SDL_DBus_GetContext();
531 
532  if (IBus_CheckConnection(dbus)) {
533  DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
534  input_ctx_path,
535  IBUS_INPUT_INTERFACE,
536  method);
537  if (msg) {
538  if (dbus->connection_send(ibus_conn, msg, NULL)) {
539  dbus->connection_flush(ibus_conn);
540  }
541  dbus->message_unref(msg);
542  }
543  }
544 }
545 
546 void
547 SDL_IBus_SetFocus(SDL_bool focused)
548 {
549  const char *method = focused ? "FocusIn" : "FocusOut";
550  IBus_SimpleMessage(method);
551 }
552 
553 void
554 SDL_IBus_Reset(void)
555 {
556  IBus_SimpleMessage("Reset");
557 }
558 
559 SDL_bool
560 SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
561 {
562  SDL_bool result = SDL_FALSE;
563  SDL_DBusContext *dbus = SDL_DBus_GetContext();
564 
565  if (IBus_CheckConnection(dbus)) {
566  DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
567  input_ctx_path,
568  IBUS_INPUT_INTERFACE,
569  "ProcessKeyEvent");
570  if (msg) {
571  Uint32 mods = IBus_ModState();
572  dbus->message_append_args(msg,
573  DBUS_TYPE_UINT32, &keysym,
574  DBUS_TYPE_UINT32, &keycode,
575  DBUS_TYPE_UINT32, &mods,
576  DBUS_TYPE_INVALID);
577  }
578 
579  if (msg) {
580  DBusMessage *reply;
581 
582  reply = dbus->connection_send_with_reply_and_block(ibus_conn, msg, 300, NULL);
583  if (reply) {
584  if (!dbus->message_get_args(reply, NULL,
585  DBUS_TYPE_BOOLEAN, &result,
586  DBUS_TYPE_INVALID)) {
587  result = SDL_FALSE;
588  }
589  dbus->message_unref(reply);
590  }
591  dbus->message_unref(msg);
592  }
593 
594  }
595 
596  SDL_IBus_UpdateTextRect(NULL);
597 
598  return result;
599 }
600 
601 void
602 SDL_IBus_UpdateTextRect(SDL_Rect *rect)
603 {
604  SDL_Window *focused_win;
605  SDL_SysWMinfo info;
606  int x = 0, y = 0;
607  SDL_DBusContext *dbus;
608 
609  if (rect) {
610  SDL_memcpy(&ibus_cursor_rect, rect, sizeof(ibus_cursor_rect));
611  }
612 
613  focused_win = SDL_GetKeyboardFocus();
614  if (!focused_win) {
615  return;
616  }
617 
618  SDL_VERSION(&info.version);
619  if (!SDL_GetWindowWMInfo(focused_win, &info)) {
620  return;
621  }
622 
623  SDL_GetWindowPosition(focused_win, &x, &y);
624 
625 #if SDL_VIDEO_DRIVER_X11
626  if (info.subsystem == SDL_SYSWM_X11) {
627  SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(focused_win)->driverdata;
628 
629  Display *x_disp = info.info.x11.display;
630  Window x_win = info.info.x11.window;
631  int x_screen = displaydata->screen;
632  Window unused;
633 
634  X11_XTranslateCoordinates(x_disp, x_win, RootWindow(x_disp, x_screen), 0, 0, &x, &y, &unused);
635  }
636 #endif
637 
638  x += ibus_cursor_rect.x;
639  y += ibus_cursor_rect.y;
640 
641  dbus = SDL_DBus_GetContext();
642 
643  if (IBus_CheckConnection(dbus)) {
644  DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
645  input_ctx_path,
646  IBUS_INPUT_INTERFACE,
647  "SetCursorLocation");
648  if (msg) {
649  dbus->message_append_args(msg,
650  DBUS_TYPE_INT32, &x,
651  DBUS_TYPE_INT32, &y,
652  DBUS_TYPE_INT32, &ibus_cursor_rect.w,
653  DBUS_TYPE_INT32, &ibus_cursor_rect.h,
654  DBUS_TYPE_INVALID);
655  }
656 
657  if (msg) {
658  if (dbus->connection_send(ibus_conn, msg, NULL)) {
659  dbus->connection_flush(ibus_conn);
660  }
661  dbus->message_unref(msg);
662  }
663  }
664 }
665 
666 void
667 SDL_IBus_PumpEvents(void)
668 {
669  SDL_DBusContext *dbus = SDL_DBus_GetContext();
670 
671  if (IBus_CheckConnection(dbus)) {
672  dbus->connection_read_write(ibus_conn, 0);
673 
674  while (dbus->connection_dispatch(ibus_conn) == DBUS_DISPATCH_DATA_REMAINS) {
675  /* Do nothing, actual work happens in IBus_MessageHandler */
676  }
677  }
678 }
679 
680 #endif
#define SDL_strlcpy
GLuint64EXT * result
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:155
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1567
SDL_Rect rect
Definition: testrelative.c:27
GLfloat GLfloat p
#define SDL_utf8strlcpy
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
SDL_version version
Definition: SDL_syswm.h:183
SDL_SYSWM_TYPE subsystem
Definition: SDL_syswm.h:184
GLuint const GLchar * name
#define SDL_GetKeyboardFocus
#define SDL_strncmp
GLenum GLsizei len
#define SDL_VERSION(x)
Macro to determine SDL version program was compiled against.
Definition: SDL_version.h:79
SDL_bool
Definition: SDL_stdinc.h:126
#define SDL_memcpy
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1567
int SDL_SendKeyboardText(const char *text)
Definition: SDL_keyboard.c:774
struct _cl_event * event
void SDL_free(void *mem)
GLenum const void * addr
#define SDL_GetWindowPosition
int x
Definition: SDL_rect.h:66
SDL_Cursor * cursor
Definition: testwm2.c:40
GLenum GLuint GLenum GLsizei const GLchar * buf
int w
Definition: SDL_rect.h:67
struct SDL_SysWMinfo::@18::@19 x11
#define SDL_HINT_IME_INTERNAL_EDITING
A variable to control whether certain IMEs should handle text editing internally instead of sending S...
Definition: SDL_hints.h:584
SDL_Keymod
Enumeration of valid key mods (possibly OR&#39;d together).
Definition: SDL_keycode.h:317
#define SDL_getenv
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:42
#define SDL_GetWindowWMInfo
#define NULL
Definition: begin_code.h:143
static char text[MAX_TEXT_LENGTH]
Definition: testime.c:34
SDL_VideoDisplay * SDL_GetDisplayForWindow(SDL_Window *window)
Definition: SDL_video.c:1039
#define SDL_strlen
int h
Definition: SDL_rect.h:67
#define SDL_strdup
The type used to identify a window.
Definition: SDL_sysvideo.h:71
#define SDL_AddHintCallback
#define SDL_DelHintCallback
#define SDL_snprintf
union SDL_SysWMinfo::@18 info
GLsizei const GLchar *const * path
#define SDL_strcmp
#define SDL_strrchr
#define SDL_GetModState
int y
Definition: SDL_rect.h:66
int SDL_SendEditingText(const char *text, int start, int length)
Definition: SDL_keyboard.c:797
#define SDL_memset
A rectangle, with the origin at the upper left.
Definition: SDL_rect.h:64
#define SDL_TEXTEDITINGEVENT_TEXT_SIZE
Definition: SDL_events.h:199