| | |
| | | /* |
| | | Simple DirectMedia Layer |
| | | Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org> |
| | | Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> |
| | | |
| | | This software is provided 'as-is', without any express or implied |
| | | warranty. In no event will the authors be held liable for any damages |
| | |
| | | static SDL_Rect ibus_cursor_rect = { 0, 0, 0, 0 }; |
| | | static DBusConnection *ibus_conn = NULL; |
| | | static char *ibus_addr_file = NULL; |
| | | int inotify_fd = -1, inotify_wd = -1; |
| | | static int inotify_fd = -1, inotify_wd = -1; |
| | | |
| | | static Uint32 |
| | | IBus_ModState(void) |
| | |
| | | return text; |
| | | } |
| | | |
| | | static size_t |
| | | IBus_utf8_strlen(const char *str) |
| | | { |
| | | size_t utf8_len = 0; |
| | | const char *p; |
| | | |
| | | for (p = str; *p; ++p) { |
| | | if (!((*p & 0x80) && !(*p & 0x40))) { |
| | | ++utf8_len; |
| | | } |
| | | } |
| | | |
| | | return utf8_len; |
| | | } |
| | | |
| | | static DBusHandlerResult |
| | | IBus_MessageHandler(DBusConnection *conn, DBusMessage *msg, void *user_data) |
| | | { |
| | |
| | | |
| | | text = IBus_GetVariantText(conn, &iter, dbus); |
| | | if (text && *text) { |
| | | char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE]; |
| | | char buf[SDL_TEXTINPUTEVENT_TEXT_SIZE]; |
| | | size_t text_bytes = SDL_strlen(text), i = 0; |
| | | |
| | | while (i < text_bytes) { |
| | |
| | | size_t cursor = 0; |
| | | |
| | | do { |
| | | size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf)); |
| | | size_t chars = IBus_utf8_strlen(buf); |
| | | const size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf)); |
| | | const size_t chars = SDL_utf8strlen(buf); |
| | | |
| | | SDL_SendEditingText(buf, cursor, chars); |
| | | |
| | |
| | | |
| | | static SDL_bool IBus_CheckConnection(SDL_DBusContext *dbus); |
| | | |
| | | static void |
| | | static void SDLCALL |
| | | IBus_SetCapabilities(void *data, const char *name, const char *old_val, |
| | | const char *internal_editing) |
| | | { |
| | | SDL_DBusContext *dbus = SDL_DBus_GetContext(); |
| | | |
| | | if (IBus_CheckConnection(dbus)) { |
| | | Uint32 caps = IBUS_CAP_FOCUS; |
| | | if (!(internal_editing && *internal_editing == '1')) { |
| | | caps |= IBUS_CAP_PREEDIT_TEXT; |
| | | } |
| | | |
| | | DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE, |
| | | input_ctx_path, |
| | | IBUS_INPUT_INTERFACE, |
| | | "SetCapabilities"); |
| | | if (msg) { |
| | | Uint32 caps = IBUS_CAP_FOCUS; |
| | | if (!(internal_editing && *internal_editing == '1')) { |
| | | caps |= IBUS_CAP_PREEDIT_TEXT; |
| | | } |
| | | |
| | | dbus->message_append_args(msg, |
| | | DBUS_TYPE_UINT32, &caps, |
| | | DBUS_TYPE_INVALID); |
| | | } |
| | | |
| | | if (msg) { |
| | | if (dbus->connection_send(ibus_conn, msg, NULL)) { |
| | | dbus->connection_flush(ibus_conn); |
| | | } |
| | | dbus->message_unref(msg); |
| | | } |
| | | SDL_DBus_CallVoidMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE, "SetCapabilities", |
| | | DBUS_TYPE_UINT32, &caps, DBUS_TYPE_INVALID); |
| | | } |
| | | } |
| | | |
| | |
| | | static SDL_bool |
| | | IBus_SetupConnection(SDL_DBusContext *dbus, const char* addr) |
| | | { |
| | | const char *client_name = "SDL2_Application"; |
| | | const char *path = NULL; |
| | | SDL_bool result = SDL_FALSE; |
| | | DBusMessage *msg; |
| | | DBusObjectPathVTable ibus_vtable; |
| | | |
| | | SDL_zero(ibus_vtable); |
| | |
| | | |
| | | dbus->connection_flush(ibus_conn); |
| | | |
| | | msg = dbus->message_new_method_call(IBUS_SERVICE, IBUS_PATH, IBUS_INTERFACE, "CreateInputContext"); |
| | | if (msg) { |
| | | const char *client_name = "SDL2_Application"; |
| | | dbus->message_append_args(msg, |
| | | DBUS_TYPE_STRING, &client_name, |
| | | DBUS_TYPE_INVALID); |
| | | } |
| | | |
| | | if (msg) { |
| | | DBusMessage *reply; |
| | | |
| | | reply = dbus->connection_send_with_reply_and_block(ibus_conn, msg, 1000, NULL); |
| | | if (reply) { |
| | | if (dbus->message_get_args(reply, NULL, |
| | | DBUS_TYPE_OBJECT_PATH, &path, |
| | | DBUS_TYPE_INVALID)) { |
| | | if (input_ctx_path) { |
| | | SDL_free(input_ctx_path); |
| | | } |
| | | input_ctx_path = SDL_strdup(path); |
| | | result = SDL_TRUE; |
| | | } |
| | | dbus->message_unref(reply); |
| | | } |
| | | dbus->message_unref(msg); |
| | | } |
| | | |
| | | if (result) { |
| | | SDL_AddHintCallback(SDL_HINT_IME_INTERNAL_EDITING, &IBus_SetCapabilities, NULL); |
| | | if (SDL_DBus_CallMethodOnConnection(ibus_conn, IBUS_SERVICE, IBUS_PATH, IBUS_INTERFACE, "CreateInputContext", |
| | | DBUS_TYPE_STRING, &client_name, DBUS_TYPE_INVALID, |
| | | DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) { |
| | | SDL_free(input_ctx_path); |
| | | input_ctx_path = SDL_strdup(path); |
| | | SDL_AddHintCallback(SDL_HINT_IME_INTERNAL_EDITING, IBus_SetCapabilities, NULL); |
| | | |
| | | dbus->bus_add_match(ibus_conn, "type='signal',interface='org.freedesktop.IBus.InputContext'", NULL); |
| | | dbus->connection_try_register_object_path(ibus_conn, input_ctx_path, &ibus_vtable, dbus, NULL); |
| | | dbus->connection_flush(ibus_conn); |
| | | result = SDL_TRUE; |
| | | } |
| | | |
| | | SDL_IBus_SetFocus(SDL_GetKeyboardFocus() != NULL); |
| | |
| | | inotify_wd = -1; |
| | | } |
| | | |
| | | SDL_DelHintCallback(SDL_HINT_IME_INTERNAL_EDITING, &IBus_SetCapabilities, NULL); |
| | | SDL_DelHintCallback(SDL_HINT_IME_INTERNAL_EDITING, IBus_SetCapabilities, NULL); |
| | | |
| | | SDL_memset(&ibus_cursor_rect, 0, sizeof(ibus_cursor_rect)); |
| | | } |
| | |
| | | SDL_DBusContext *dbus = SDL_DBus_GetContext(); |
| | | |
| | | if (IBus_CheckConnection(dbus)) { |
| | | DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE, |
| | | input_ctx_path, |
| | | IBUS_INPUT_INTERFACE, |
| | | method); |
| | | if (msg) { |
| | | if (dbus->connection_send(ibus_conn, msg, NULL)) { |
| | | dbus->connection_flush(ibus_conn); |
| | | } |
| | | dbus->message_unref(msg); |
| | | } |
| | | SDL_DBus_CallVoidMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE, method, DBUS_TYPE_INVALID); |
| | | } |
| | | } |
| | | |
| | |
| | | SDL_bool |
| | | SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode) |
| | | { |
| | | SDL_bool result = SDL_FALSE; |
| | | Uint32 result = 0; |
| | | SDL_DBusContext *dbus = SDL_DBus_GetContext(); |
| | | |
| | | if (IBus_CheckConnection(dbus)) { |
| | | DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE, |
| | | input_ctx_path, |
| | | IBUS_INPUT_INTERFACE, |
| | | "ProcessKeyEvent"); |
| | | if (msg) { |
| | | Uint32 mods = IBus_ModState(); |
| | | dbus->message_append_args(msg, |
| | | DBUS_TYPE_UINT32, &keysym, |
| | | DBUS_TYPE_UINT32, &keycode, |
| | | DBUS_TYPE_UINT32, &mods, |
| | | DBUS_TYPE_INVALID); |
| | | Uint32 mods = IBus_ModState(); |
| | | if (!SDL_DBus_CallMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE, "ProcessKeyEvent", |
| | | DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &keycode, DBUS_TYPE_UINT32, &mods, DBUS_TYPE_INVALID, |
| | | DBUS_TYPE_BOOLEAN, &result, DBUS_TYPE_INVALID)) { |
| | | result = 0; |
| | | } |
| | | |
| | | if (msg) { |
| | | DBusMessage *reply; |
| | | |
| | | reply = dbus->connection_send_with_reply_and_block(ibus_conn, msg, 300, NULL); |
| | | if (reply) { |
| | | if (!dbus->message_get_args(reply, NULL, |
| | | DBUS_TYPE_BOOLEAN, &result, |
| | | DBUS_TYPE_INVALID)) { |
| | | result = SDL_FALSE; |
| | | } |
| | | dbus->message_unref(reply); |
| | | } |
| | | dbus->message_unref(msg); |
| | | } |
| | | |
| | | } |
| | | |
| | | SDL_IBus_UpdateTextRect(NULL); |
| | | |
| | | return result; |
| | | return result ? SDL_TRUE : SDL_FALSE; |
| | | } |
| | | |
| | | void |
| | |
| | | dbus = SDL_DBus_GetContext(); |
| | | |
| | | if (IBus_CheckConnection(dbus)) { |
| | | DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE, |
| | | input_ctx_path, |
| | | IBUS_INPUT_INTERFACE, |
| | | "SetCursorLocation"); |
| | | if (msg) { |
| | | dbus->message_append_args(msg, |
| | | 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); |
| | | } |
| | | |
| | | if (msg) { |
| | | if (dbus->connection_send(ibus_conn, msg, NULL)) { |
| | | dbus->connection_flush(ibus_conn); |
| | | } |
| | | dbus->message_unref(msg); |
| | | } |
| | | SDL_DBus_CallVoidMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE, "SetCursorLocation", |
| | | 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); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | #endif |
| | | |
| | | /* vi: set ts=4 sw=4 expandtab: */ |