diff --git a/src/core/linux/SDL_fcitx.c b/src/core/linux/SDL_fcitx.c index bab5e88f3..b7a0cfacf 100644 --- a/src/core/linux/SDL_fcitx.c +++ b/src/core/linux/SDL_fcitx.c @@ -85,14 +85,22 @@ GetAppName() } static size_t -Fcitx_GetPreeditString(SDL_DBusContext *dbus, DBusMessage *msg, char **ret) { +Fcitx_GetPreeditString(SDL_DBusContext *dbus, + DBusMessage *msg, + char **ret, + Sint32 *start_pos, + Sint32 *end_pos) +{ char *text = NULL, *subtext; size_t text_bytes = 0; DBusMessageIter iter, array, sub; + Sint32 p_start_pos = -1; + Sint32 p_end_pos = -1; dbus->message_iter_init(msg, &iter); /* Message type is a(si)i, we only need string part */ if (dbus->message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY) { + size_t pos = 0; /* First pass: calculate string length */ dbus->message_iter_recurse(&iter, &array); while (dbus->message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) { @@ -103,7 +111,29 @@ Fcitx_GetPreeditString(SDL_DBusContext *dbus, DBusMessage *msg, char **ret) { text_bytes += SDL_strlen(subtext); } } + dbus->message_iter_next(&sub); + if (dbus->message_iter_get_arg_type(&sub) == DBUS_TYPE_INT32 && p_end_pos == -1) { + /* Type is a bit field defined as follows: */ + /* bit 3: Underline, bit 4: HighLight, bit 5: DontCommit, */ + /* bit 6: Bold, bit 7: Strike, bit 8: Italic */ + Sint32 type; + dbus->message_iter_get_basic(&sub, &type); + /* We only consider highlight */ + if (type & (1 << 4)) { + if (p_start_pos == -1) { + p_start_pos = pos; + } + } else if (p_start_pos != -1 && p_end_pos == -1) { + p_end_pos = pos; + } + } dbus->message_iter_next(&array); + if (subtext && *subtext) { + pos += SDL_utf8strlen(subtext); + } + } + if (p_start_pos != -1 && p_end_pos == -1) { + p_end_pos = pos; } if (text_bytes) { text = SDL_malloc(text_bytes + 1); @@ -129,10 +159,32 @@ Fcitx_GetPreeditString(SDL_DBusContext *dbus, DBusMessage *msg, char **ret) { text_bytes = 0; } } - *ret= text; + + *ret = text; + *start_pos = p_start_pos; + *end_pos = p_end_pos; return text_bytes; } +static Sint32 +Fcitx_GetPreeditCursorByte(SDL_DBusContext *dbus, DBusMessage *msg) +{ + Sint32 byte = -1; + DBusMessageIter iter; + + dbus->message_iter_init(msg, &iter); + + dbus->message_iter_next(&iter); + + if (dbus->message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) { + return -1; + } + + dbus->message_iter_get_basic(&iter, &byte); + + return byte; +} + static DBusHandlerResult DBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -162,20 +214,28 @@ DBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *data) if (dbus->message_is_signal(msg, FCITX_IC_DBUS_INTERFACE, "UpdateFormattedPreedit")) { char *text = NULL; - size_t text_bytes = Fcitx_GetPreeditString(dbus, msg, &text); + Sint32 start_pos, end_pos; + size_t text_bytes = Fcitx_GetPreeditString(dbus, msg, &text, &start_pos, &end_pos); if (text_bytes) { - char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE]; - size_t i = 0; - size_t cursor = 0; + if (SDL_GetHintBoolean(SDL_HINT_IME_SUPPORT_EXTENDED_TEXT, SDL_FALSE)) { + if (start_pos == -1) { + Sint32 byte_pos = Fcitx_GetPreeditCursorByte(dbus, msg); + start_pos = byte_pos >= 0 ? SDL_utf8strnlen(text, byte_pos) : -1; + } + SDL_SendEditingText(text, start_pos, end_pos >= 0 ? end_pos - start_pos : -1); + } else { + char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE]; + size_t i = 0; + size_t cursor = 0; + while (i < text_bytes) { + const size_t sz = SDL_utf8strlcpy(buf, text + i, sizeof(buf)); + const size_t chars = SDL_utf8strlen(buf); - while (i < text_bytes) { - const size_t sz = SDL_utf8strlcpy(buf, text + i, sizeof(buf)); - const size_t chars = SDL_utf8strlen(buf); + SDL_SendEditingText(buf, cursor, chars); - SDL_SendEditingText(buf, cursor, chars); - - i += sz; - cursor += chars; + i += sz; + cursor += chars; + } } SDL_free(text); } else {