21 #include "../../SDL_internal.h" 23 #ifdef HAVE_IBUS_IBUS_H 28 #include "../../video/SDL_sysvideo.h" 29 #include "../../events/SDL_keyboard_c.h" 31 #if SDL_VIDEO_DRIVER_X11 32 #include "../../video/x11/SDL_x11video.h" 35 #include <sys/inotify.h> 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";
44 static char *input_ctx_path =
NULL;
45 static SDL_Rect ibus_cursor_rect = { 0, 0, 0, 0 };
46 static DBusConnection *ibus_conn =
NULL;
47 static char *ibus_addr_file =
NULL;
48 int inotify_fd = -1, inotify_wd = -1;
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;
70 IBus_GetVariantText(DBusConnection *conn, DBusMessageIter *iter, SDL_DBusContext *dbus)
74 const char *struct_id =
NULL;
75 DBusMessageIter sub1, sub2;
77 if (dbus->message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT) {
81 dbus->message_iter_recurse(iter, &sub1);
83 if (dbus->message_iter_get_arg_type(&sub1) != DBUS_TYPE_STRUCT) {
87 dbus->message_iter_recurse(&sub1, &sub2);
89 if (dbus->message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
93 dbus->message_iter_get_basic(&sub2, &struct_id);
94 if (!struct_id ||
SDL_strncmp(struct_id,
"IBusText",
sizeof(
"IBusText")) != 0) {
98 dbus->message_iter_next(&sub2);
99 dbus->message_iter_next(&sub2);
101 if (dbus->message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
105 dbus->message_iter_get_basic(&sub2, &text);
111 IBus_utf8_strlen(
const char *str)
116 for (p = str; *
p; ++
p) {
117 if (!((*p & 0x80) && !(*p & 0x40))) {
125 static DBusHandlerResult
126 IBus_MessageHandler(DBusConnection *conn, DBusMessage *msg,
void *user_data)
128 SDL_DBusContext *dbus = (SDL_DBusContext *)user_data;
130 if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE,
"CommitText")) {
131 DBusMessageIter iter;
134 dbus->message_iter_init(msg, &iter);
136 text = IBus_GetVariantText(conn, &iter, dbus);
141 while (
i < text_bytes) {
149 return DBUS_HANDLER_RESULT_HANDLED;
152 if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE,
"UpdatePreeditText")) {
153 DBusMessageIter iter;
156 dbus->message_iter_init(msg, &iter);
157 text = IBus_GetVariantText(conn, &iter, dbus);
166 size_t chars = IBus_utf8_strlen(buf);
172 }
while (
i < text_bytes);
175 SDL_IBus_UpdateTextRect(
NULL);
177 return DBUS_HANDLER_RESULT_HANDLED;
180 if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE,
"HidePreeditText")) {
182 return DBUS_HANDLER_RESULT_HANDLED;
185 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
189 IBus_ReadAddressFromFile(
const char *file_path)
195 addr_file = fopen(file_path,
"r");
200 while (fgets(addr_buf,
sizeof(addr_buf), addr_file)) {
201 if (
SDL_strncmp(addr_buf,
"IBUS_ADDRESS=",
sizeof(
"IBUS_ADDRESS=")-1) == 0) {
203 if (addr_buf[sz-1] ==
'\n') addr_buf[sz-1] = 0;
204 if (addr_buf[sz-2] ==
'\r') addr_buf[sz-2] = 0;
213 return SDL_strdup(addr_buf + (
sizeof(
"IBUS_ADDRESS=") - 1));
220 IBus_GetDBusAddressFilename(
void)
222 SDL_DBusContext *dbus;
223 const char *disp_env;
224 char config_dir[PATH_MAX];
225 char *display =
NULL;
227 const char *conf_env;
229 char file_path[PATH_MAX];
231 char *disp_num, *screen_num;
233 if (ibus_addr_file) {
237 dbus = SDL_DBus_GetContext();
252 if (!disp_env || !*disp_env) {
278 SDL_memset(config_dir, 0,
sizeof(config_dir));
281 if (conf_env && *conf_env) {
282 SDL_strlcpy(config_dir, conf_env,
sizeof(config_dir));
285 if (!home_env || !*home_env) {
289 SDL_snprintf(config_dir,
sizeof(config_dir),
"%s/.config", home_env);
292 key = dbus->get_local_machine_id();
295 SDL_snprintf(file_path,
sizeof(file_path),
"%s/ibus/bus/%s-%s-%s",
296 config_dir, key, host, disp_num);
303 static SDL_bool IBus_CheckConnection(SDL_DBusContext *dbus);
306 IBus_SetCapabilities(
void *
data,
const char *
name,
const char *old_val,
307 const char *internal_editing)
309 SDL_DBusContext *dbus = SDL_DBus_GetContext();
311 if (IBus_CheckConnection(dbus)) {
313 DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
315 IBUS_INPUT_INTERFACE,
318 Uint32 caps = IBUS_CAP_FOCUS;
319 if (!(internal_editing && *internal_editing ==
'1')) {
320 caps |= IBUS_CAP_PREEDIT_TEXT;
323 dbus->message_append_args(msg,
324 DBUS_TYPE_UINT32, &caps,
329 if (dbus->connection_send(ibus_conn, msg,
NULL)) {
330 dbus->connection_flush(ibus_conn);
332 dbus->message_unref(msg);
339 IBus_SetupConnection(SDL_DBusContext *dbus,
const char* addr)
344 DBusObjectPathVTable ibus_vtable;
347 ibus_vtable.message_function = &IBus_MessageHandler;
349 ibus_conn = dbus->connection_open_private(addr,
NULL);
355 dbus->connection_flush(ibus_conn);
357 if (!dbus->bus_register(ibus_conn,
NULL)) {
362 dbus->connection_flush(ibus_conn);
364 msg = dbus->message_new_method_call(IBUS_SERVICE, IBUS_PATH, IBUS_INTERFACE,
"CreateInputContext");
366 const char *client_name =
"SDL2_Application";
367 dbus->message_append_args(msg,
368 DBUS_TYPE_STRING, &client_name,
375 reply = dbus->connection_send_with_reply_and_block(ibus_conn, msg, 1000,
NULL);
377 if (dbus->message_get_args(reply,
NULL,
378 DBUS_TYPE_OBJECT_PATH, &path,
379 DBUS_TYPE_INVALID)) {
380 if (input_ctx_path) {
386 dbus->message_unref(reply);
388 dbus->message_unref(msg);
394 dbus->bus_add_match(ibus_conn,
"type='signal',interface='org.freedesktop.IBus.InputContext'",
NULL);
395 dbus->connection_try_register_object_path(ibus_conn, input_ctx_path, &ibus_vtable, dbus,
NULL);
396 dbus->connection_flush(ibus_conn);
400 SDL_IBus_UpdateTextRect(
NULL);
406 IBus_CheckConnection(SDL_DBusContext *dbus)
410 if (ibus_conn && dbus->connection_get_is_connected(ibus_conn)) {
414 if (inotify_fd > 0 && inotify_wd > 0) {
416 ssize_t readsize = read(inotify_fd, buf,
sizeof(buf));
422 for (p = buf; p < buf + readsize; ) {
423 struct inotify_event *
event = (
struct inotify_event*) p;
424 if (
event->len > 0) {
425 char *addr_file_no_path =
SDL_strrchr(ibus_addr_file,
'/');
426 if (!addr_file_no_path)
return SDL_FALSE;
434 p +=
sizeof(
struct inotify_event) +
event->
len;
438 char *addr = IBus_ReadAddressFromFile(ibus_addr_file);
440 SDL_bool result = IBus_SetupConnection(dbus, addr);
455 SDL_DBusContext *dbus = SDL_DBus_GetContext();
458 char *addr_file = IBus_GetDBusAddressFilename();
469 addr = IBus_ReadAddressFromFile(addr_file);
475 if (inotify_fd < 0) {
476 inotify_fd = inotify_init();
477 fcntl(inotify_fd, F_SETFL, O_NONBLOCK);
485 inotify_wd = inotify_add_watch(inotify_fd, addr_file, IN_CREATE | IN_MODIFY);
489 result = IBus_SetupConnection(dbus, addr);
500 SDL_DBusContext *dbus;
502 if (input_ctx_path) {
504 input_ctx_path =
NULL;
507 if (ibus_addr_file) {
509 ibus_addr_file =
NULL;
512 dbus = SDL_DBus_GetContext();
514 if (dbus && ibus_conn) {
515 dbus->connection_close(ibus_conn);
516 dbus->connection_unref(ibus_conn);
519 if (inotify_fd > 0 && inotify_wd > 0) {
520 inotify_rm_watch(inotify_fd, inotify_wd);
526 SDL_memset(&ibus_cursor_rect, 0,
sizeof(ibus_cursor_rect));
530 IBus_SimpleMessage(
const char *method)
532 SDL_DBusContext *dbus = SDL_DBus_GetContext();
534 if (IBus_CheckConnection(dbus)) {
535 DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
537 IBUS_INPUT_INTERFACE,
540 if (dbus->connection_send(ibus_conn, msg,
NULL)) {
541 dbus->connection_flush(ibus_conn);
543 dbus->message_unref(msg);
551 const char *method = focused ?
"FocusIn" :
"FocusOut";
552 IBus_SimpleMessage(method);
558 IBus_SimpleMessage(
"Reset");
565 SDL_DBusContext *dbus = SDL_DBus_GetContext();
567 if (IBus_CheckConnection(dbus)) {
568 DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
570 IBUS_INPUT_INTERFACE,
573 Uint32 mods = IBus_ModState();
574 dbus->message_append_args(msg,
575 DBUS_TYPE_UINT32, &keysym,
576 DBUS_TYPE_UINT32, &keycode,
577 DBUS_TYPE_UINT32, &mods,
584 reply = dbus->connection_send_with_reply_and_block(ibus_conn, msg, 300,
NULL);
586 if (!dbus->message_get_args(reply,
NULL,
587 DBUS_TYPE_BOOLEAN, &result,
588 DBUS_TYPE_INVALID)) {
591 dbus->message_unref(reply);
593 dbus->message_unref(msg);
598 SDL_IBus_UpdateTextRect(
NULL);
609 SDL_DBusContext *dbus;
612 SDL_memcpy(&ibus_cursor_rect, rect,
sizeof(ibus_cursor_rect));
627 #if SDL_VIDEO_DRIVER_X11 631 Display *x_disp = info.
info.
x11.display;
632 Window x_win = info.
info.
x11.window;
633 int x_screen = displaydata->
screen;
636 X11_XTranslateCoordinates(x_disp, x_win, RootWindow(x_disp, x_screen), 0, 0, &x, &
y, &unused);
640 x += ibus_cursor_rect.
x;
641 y += ibus_cursor_rect.
y;
643 dbus = SDL_DBus_GetContext();
645 if (IBus_CheckConnection(dbus)) {
646 DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
648 IBUS_INPUT_INTERFACE,
649 "SetCursorLocation");
651 dbus->message_append_args(msg,
654 DBUS_TYPE_INT32, &ibus_cursor_rect.
w,
655 DBUS_TYPE_INT32, &ibus_cursor_rect.
h,
660 if (dbus->connection_send(ibus_conn, msg,
NULL)) {
661 dbus->connection_flush(ibus_conn);
663 dbus->message_unref(msg);
669 SDL_IBus_PumpEvents(
void)
671 SDL_DBusContext *dbus = SDL_DBus_GetContext();
673 if (IBus_CheckConnection(dbus)) {
674 dbus->connection_read_write(ibus_conn, 0);
676 while (dbus->connection_dispatch(ibus_conn) == DBUS_DISPATCH_DATA_REMAINS) {
GLint GLint GLint GLint GLint x
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
GLuint const GLchar * name
#define SDL_GetKeyboardFocus
uint32_t Uint32
An unsigned 32-bit integer type.
#define SDL_VERSION(x)
Macro to determine SDL version program was compiled against.
GLint GLint GLint GLint GLint GLint y
int SDL_SendKeyboardText(const char *text)
#define SDL_GetWindowPosition
GLenum GLuint GLenum GLsizei const GLchar * buf
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...
SDL_Keymod
Enumeration of valid key mods (possibly OR'd together).
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)
#define SDL_GetWindowWMInfo
static char text[MAX_TEXT_LENGTH]
SDL_VideoDisplay * SDL_GetDisplayForWindow(SDL_Window *window)
The type used to identify a window.
#define SDL_AddHintCallback
#define SDL_DelHintCallback
union SDL_SysWMinfo::@18 info
GLsizei const GLchar *const * path
int SDL_SendEditingText(const char *text, int start, int length)
A rectangle, with the origin at the upper left.
#define SDL_TEXTEDITINGEVENT_TEXT_SIZE