summaryrefslogtreecommitdiff
path: root/clients/keyboard.c
diff options
context:
space:
mode:
authorJan Arne Petersen <jpetersen@openismus.com>2013-04-18 16:47:41 +0200
committerKristian Høgsberg <krh@bitplanet.net>2013-05-06 20:26:20 -0400
commitd8aa3327b3f6a48437b6689e52104a71c4f66d78 (patch)
treeff62040e07b0f93d3fb36031be116a231b225b15 /clients/keyboard.c
parentcc75ec11ca2f6642e499c78f4c2829d788d049d3 (diff)
downloadweston-d8aa3327b3f6a48437b6689e52104a71c4f66d78.tar.gz
weston-d8aa3327b3f6a48437b6689e52104a71c4f66d78.tar.bz2
weston-d8aa3327b3f6a48437b6689e52104a71c4f66d78.zip
keyboard: Fix offsets when deleting text
Signed-off-by: Jan Arne Petersen <jpetersen@openismus.com>
Diffstat (limited to 'clients/keyboard.c')
-rw-r--r--clients/keyboard.c90
1 files changed, 85 insertions, 5 deletions
diff --git a/clients/keyboard.c b/clients/keyboard.c
index d83ca3ca..a2fbded5 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