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 static 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);
110 static DBusHandlerResult
111 IBus_MessageHandler(DBusConnection *conn, DBusMessage *msg,
void *user_data)
113 SDL_DBusContext *dbus = (SDL_DBusContext *)user_data;
115 if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE,
"CommitText")) {
116 DBusMessageIter iter;
119 dbus->message_iter_init(msg, &iter);
121 text = IBus_GetVariantText(conn, &iter, dbus);
126 while (
i < text_bytes) {
134 return DBUS_HANDLER_RESULT_HANDLED;
137 if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE,
"UpdatePreeditText")) {
138 DBusMessageIter iter;
141 dbus->message_iter_init(msg, &iter);
142 text = IBus_GetVariantText(conn, &iter, dbus);
157 }
while (
i < text_bytes);
160 SDL_IBus_UpdateTextRect(
NULL);
162 return DBUS_HANDLER_RESULT_HANDLED;
165 if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE,
"HidePreeditText")) {
167 return DBUS_HANDLER_RESULT_HANDLED;
170 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
174 IBus_ReadAddressFromFile(
const char *file_path)
180 addr_file = fopen(file_path,
"r");
185 while (fgets(addr_buf,
sizeof(addr_buf), addr_file)) {
186 if (
SDL_strncmp(addr_buf,
"IBUS_ADDRESS=",
sizeof(
"IBUS_ADDRESS=")-1) == 0) {
188 if (addr_buf[sz-1] ==
'\n') addr_buf[sz-1] = 0;
189 if (addr_buf[sz-2] ==
'\r') addr_buf[sz-2] = 0;
198 return SDL_strdup(addr_buf + (
sizeof(
"IBUS_ADDRESS=") - 1));
205 IBus_GetDBusAddressFilename(
void)
207 SDL_DBusContext *dbus;
208 const char *disp_env;
209 char config_dir[PATH_MAX];
210 char *display =
NULL;
212 const char *conf_env;
214 char file_path[PATH_MAX];
216 char *disp_num, *screen_num;
218 if (ibus_addr_file) {
222 dbus = SDL_DBus_GetContext();
237 if (!disp_env || !*disp_env) {
263 SDL_memset(config_dir, 0,
sizeof(config_dir));
266 if (conf_env && *conf_env) {
267 SDL_strlcpy(config_dir, conf_env,
sizeof(config_dir));
270 if (!home_env || !*home_env) {
274 SDL_snprintf(config_dir,
sizeof(config_dir),
"%s/.config", home_env);
277 key = dbus->get_local_machine_id();
280 SDL_snprintf(file_path,
sizeof(file_path),
"%s/ibus/bus/%s-%s-%s",
281 config_dir, key, host, disp_num);
288 static SDL_bool IBus_CheckConnection(SDL_DBusContext *dbus);
291 IBus_SetCapabilities(
void *
data,
const char *
name,
const char *old_val,
292 const char *internal_editing)
294 SDL_DBusContext *dbus = SDL_DBus_GetContext();
296 if (IBus_CheckConnection(dbus)) {
297 Uint32 caps = IBUS_CAP_FOCUS;
298 if (!(internal_editing && *internal_editing ==
'1')) {
299 caps |= IBUS_CAP_PREEDIT_TEXT;
302 SDL_DBus_CallVoidMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE,
"SetCapabilities",
303 DBUS_TYPE_UINT32, &caps, DBUS_TYPE_INVALID);
309 IBus_SetupConnection(SDL_DBusContext *dbus,
const char* addr)
311 const char *client_name =
"SDL2_Application";
314 DBusObjectPathVTable ibus_vtable;
317 ibus_vtable.message_function = &IBus_MessageHandler;
319 ibus_conn = dbus->connection_open_private(addr,
NULL);
325 dbus->connection_flush(ibus_conn);
327 if (!dbus->bus_register(ibus_conn,
NULL)) {
332 dbus->connection_flush(ibus_conn);
334 if (SDL_DBus_CallMethodOnConnection(ibus_conn, IBUS_SERVICE, IBUS_PATH, IBUS_INTERFACE,
"CreateInputContext",
335 DBUS_TYPE_STRING, &client_name, DBUS_TYPE_INVALID,
336 DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) {
341 dbus->bus_add_match(ibus_conn,
"type='signal',interface='org.freedesktop.IBus.InputContext'",
NULL);
342 dbus->connection_try_register_object_path(ibus_conn, input_ctx_path, &ibus_vtable, dbus,
NULL);
343 dbus->connection_flush(ibus_conn);
348 SDL_IBus_UpdateTextRect(
NULL);
354 IBus_CheckConnection(SDL_DBusContext *dbus)
358 if (ibus_conn && dbus->connection_get_is_connected(ibus_conn)) {
362 if (inotify_fd > 0 && inotify_wd > 0) {
364 ssize_t readsize = read(inotify_fd, buf,
sizeof(buf));
370 for (p = buf; p < buf + readsize; ) {
371 struct inotify_event *
event = (
struct inotify_event*) p;
372 if (
event->len > 0) {
373 char *addr_file_no_path =
SDL_strrchr(ibus_addr_file,
'/');
374 if (!addr_file_no_path)
return SDL_FALSE;
382 p +=
sizeof(
struct inotify_event) +
event->
len;
386 char *addr = IBus_ReadAddressFromFile(ibus_addr_file);
388 SDL_bool result = IBus_SetupConnection(dbus, addr);
403 SDL_DBusContext *dbus = SDL_DBus_GetContext();
406 char *addr_file = IBus_GetDBusAddressFilename();
417 addr = IBus_ReadAddressFromFile(addr_file);
423 if (inotify_fd < 0) {
424 inotify_fd = inotify_init();
425 fcntl(inotify_fd, F_SETFL, O_NONBLOCK);
433 inotify_wd = inotify_add_watch(inotify_fd, addr_file, IN_CREATE | IN_MODIFY);
437 result = IBus_SetupConnection(dbus, addr);
448 SDL_DBusContext *dbus;
450 if (input_ctx_path) {
452 input_ctx_path =
NULL;
455 if (ibus_addr_file) {
457 ibus_addr_file =
NULL;
460 dbus = SDL_DBus_GetContext();
462 if (dbus && ibus_conn) {
463 dbus->connection_close(ibus_conn);
464 dbus->connection_unref(ibus_conn);
467 if (inotify_fd > 0 && inotify_wd > 0) {
468 inotify_rm_watch(inotify_fd, inotify_wd);
474 SDL_memset(&ibus_cursor_rect, 0,
sizeof(ibus_cursor_rect));
478 IBus_SimpleMessage(
const char *method)
480 SDL_DBusContext *dbus = SDL_DBus_GetContext();
482 if (IBus_CheckConnection(dbus)) {
483 SDL_DBus_CallVoidMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE, method, DBUS_TYPE_INVALID);
490 const char *method = focused ?
"FocusIn" :
"FocusOut";
491 IBus_SimpleMessage(method);
497 IBus_SimpleMessage(
"Reset");
504 SDL_DBusContext *dbus = SDL_DBus_GetContext();
506 if (IBus_CheckConnection(dbus)) {
507 Uint32 mods = IBus_ModState();
508 if (!SDL_DBus_CallMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE,
"ProcessKeyEvent",
509 DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &keycode, DBUS_TYPE_UINT32, &mods, DBUS_TYPE_INVALID,
510 DBUS_TYPE_BOOLEAN, &result, DBUS_TYPE_INVALID)) {
515 SDL_IBus_UpdateTextRect(
NULL);
526 SDL_DBusContext *dbus;
529 SDL_memcpy(&ibus_cursor_rect, rect,
sizeof(ibus_cursor_rect));
544 #if SDL_VIDEO_DRIVER_X11 548 Display *x_disp = info.
info.
x11.display;
549 Window x_win = info.
info.
x11.window;
550 int x_screen = displaydata->
screen;
553 X11_XTranslateCoordinates(x_disp, x_win, RootWindow(x_disp, x_screen), 0, 0, &x, &
y, &unused);
557 x += ibus_cursor_rect.
x;
558 y += ibus_cursor_rect.
y;
560 dbus = SDL_DBus_GetContext();
562 if (IBus_CheckConnection(dbus)) {
563 SDL_DBus_CallVoidMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE,
"SetCursorLocation",
564 DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &
y, DBUS_TYPE_INT32, &ibus_cursor_rect.
w, DBUS_TYPE_INT32, &ibus_cursor_rect.
h, DBUS_TYPE_INVALID);
569 SDL_IBus_PumpEvents(
void)
571 SDL_DBusContext *dbus = SDL_DBus_GetContext();
573 if (IBus_CheckConnection(dbus)) {
574 dbus->connection_read_write(ibus_conn, 0);
576 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
#define SDL_GetKeyboardFocus
GLuint const GLchar * name
#define SDL_VERSION(x)
Macro to determine SDL version program was compiled against.
int SDL_SendKeyboardText(const char *text)
#define SDL_GetWindowPosition
GLint GLint GLint GLint GLint GLint y
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
#define SDL_TEXTINPUTEVENT_TEXT_SIZE
int SDL_SendEditingText(const char *text, int start, int length)
A rectangle, with the origin at the upper left.
#define SDL_TEXTEDITINGEVENT_TEXT_SIZE