[PATCH v2 27/28] keyboard: Fix offsets when deleting text

Jan Arne Petersen jpetersen at openismus.com
Thu Apr 18 07:47:41 PDT 2013


From: Jan Arne Petersen <jpetersen at openismus.com>

Signed-off-by: Jan Arne Petersen <jpetersen at openismus.com>
---
 clients/keyboard.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 85 insertions(+), 5 deletions(-)

diff --git a/clients/keyboard.c b/clients/keyboard.c
index d83ca3c..a2fbded 100644
--- a/clients/keyboard.c
+++ b/clients/keyboard.c
@@ -50,6 +50,7 @@ struct virtual_keyboard {
 	uint32_t content_purpose;
 	char *preferred_language;
 	char *surrounding_text;
+	uint32_t surrounding_cursor;
 	struct keyboard *keyboard;
 };
 
@@ -380,9 +381,24 @@ resize_handler(struct widget *widget,
 	/* struct keyboard *keyboard = data; */
 }
 
+static char *
+insert_text(const char *text, uint32_t offset, const char *insert)
+{
+	char *new_text = malloc(strlen(text) + strlen(insert) + 1);
+
+	strncat(new_text, text, offset);
+	new_text[offset] = '\0';
+	strcat(new_text, insert);
+	strcat(new_text, text + offset);
+
+	return new_text;
+}
+
 static void
 virtual_keyboard_commit_preedit(struct virtual_keyboard *keyboard)
 {
+	char *surrounding_text;
+
 	if (!keyboard->preedit_string ||
 	    strlen(keyboard->preedit_string) == 0)
 		return;
@@ -392,6 +408,19 @@ virtual_keyboard_commit_preedit(struct virtual_keyboard *keyboard)
 	wl_input_method_context_commit_string(keyboard->context,
 					      keyboard->serial,
 					      keyboard->preedit_string);
+
+	if (keyboard->surrounding_text) {
+		surrounding_text = insert_text(keyboard->surrounding_text,
+					       keyboard->surrounding_cursor,
+					       keyboard->preedit_string);
+		free(keyboard->surrounding_text);
+		keyboard->surrounding_text = surrounding_text;
+		keyboard->surrounding_cursor += strlen(keyboard->preedit_string);
+	} else {
+		keyboard->surrounding_text = strdup(keyboard->preedit_string);
+		keyboard->surrounding_cursor = strlen(keyboard->preedit_string);
+	}
+
 	free(keyboard->preedit_string);
 	keyboard->preedit_string = strdup("");
 }
@@ -417,6 +446,59 @@ virtual_keyboard_send_preedit(struct virtual_keyboard *keyboard,
 					       keyboard->preedit_string);
 }
 
+static const char *
+prev_utf8_char(const char *s, const char *p)
+{
+	for (--p; p >= s; --p) {
+		if ((*p & 0xc0) != 0x80)
+			return p;
+	}
+	return NULL;
+}
+
+static const char *
+next_utf8_char(const char *p)
+{
+	if (*p == '\0')
+		return NULL;
+	for (++p; (*p & 0xc0) == 0x80; ++p)
+		;
+	return p;
+}
+
+static void
+delete_before_cursor(struct virtual_keyboard *keyboard)
+{
+	const char *start, *end;
+
+	if (!keyboard->surrounding_text) {
+		fprintf(stderr, "delete_before_cursor: No surrounding text available\n");
+		return;
+	}
+
+	start = prev_utf8_char(keyboard->surrounding_text,
+			       keyboard->surrounding_text + keyboard->surrounding_cursor);
+	if (!start) {
+		fprintf(stderr, "delete_before_cursor: No previous character to delete\n");
+		return;
+	}
+
+	end = next_utf8_char(start);
+
+	wl_input_method_context_delete_surrounding_text(keyboard->context,
+							(start - keyboard->surrounding_text) - keyboard->surrounding_cursor,
+							end - start);
+	wl_input_method_context_commit_string(keyboard->context,
+					      keyboard->serial,
+					      "");
+
+	/* Update surrounding text */
+	keyboard->surrounding_cursor = start - keyboard->surrounding_text;
+	keyboard->surrounding_text[keyboard->surrounding_cursor] = '\0';
+	if (*end)
+		memmove(keyboard->surrounding_text + keyboard->surrounding_cursor, end, strlen(end));
+}
+
 static void
 keyboard_handle_key(struct keyboard *keyboard, uint32_t time, const struct key *key, struct input *input, enum wl_pointer_button_state state)
 {
@@ -438,11 +520,7 @@ keyboard_handle_key(struct keyboard *keyboard, uint32_t time, const struct key *
 				break;
 
 			if (strlen(keyboard->keyboard->preedit_string) == 0) {
-				wl_input_method_context_delete_surrounding_text(keyboard->keyboard->context,
-										-1, 1);
-				wl_input_method_context_commit_string(keyboard->keyboard->context,
-								      keyboard->keyboard->serial,
-								      "");
+				delete_before_cursor(keyboard->keyboard);
 			} else {
 				keyboard->keyboard->preedit_string[strlen(keyboard->keyboard->preedit_string) - 1] = '\0';
 				virtual_keyboard_send_preedit(keyboard->keyboard, -1);
@@ -567,6 +645,8 @@ handle_surrounding_text(void *data,
 
 	free(keyboard->surrounding_text);
 	keyboard->surrounding_text = strdup(text);
+
+	keyboard->surrounding_cursor = cursor;
 }
 
 static void
-- 
1.8.1.4



More information about the wayland-devel mailing list