From e5a3acd6bd0349c585ba7c0e9865cefb4772c00c Mon Sep 17 00:00:00 2001
From: Guldoman <[EMAIL REDACTED]>
Date: Thu, 5 May 2022 04:01:05 +0200
Subject: [PATCH] ime: fcitx: Retrieve cursor position and selection
Also, if `SDL_HINT_IME_SUPPORT_EXTENDED_TEXT` is enabled, make use of
`SDL_TEXTEDITING_EXT` by sending the full preedit string.
---
src/core/linux/SDL_fcitx.c | 90 +++++++++++++++++++++++++++++++-------
1 file changed, 75 insertions(+), 15 deletions(-)
diff --git a/src/core/linux/SDL_fcitx.c b/src/core/linux/SDL_fcitx.c
index bab5e88f350..b7a0cfacf20 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;
-
- 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);
-
- i += sz;
- cursor += chars;
+ 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);
+
+ SDL_SendEditingText(buf, cursor, chars);
+
+ i += sz;
+ cursor += chars;
+ }
}
SDL_free(text);
} else {