diff --git a/gtk/main.c b/gtk/main.c index 09f443d..bda6be8 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -345,6 +345,8 @@ kpress(GtkIMContext *ctx, GdkEventKey *ev) srvclose(im); return simplefilter(ctx, ev, 0); } + if(im->usepreedit && commit[0] != '\0' && im->prelen > 0) + setpreedit(im, "", 0); if(commit[0] != '\0') g_signal_emit_by_name(ctx, "commit", commit); if(im->usepreedit) diff --git a/ibus.c b/ibus.c index 83c295b..ccff5bd 100644 --- a/ibus.c +++ b/ibus.c @@ -629,6 +629,7 @@ handlekey(DBusConnection *c, DBusMessage *m, Ictx *ctx) dbus_uint32_t sym, code, state; Keyres res; char commit[Maxutf], preedit[Maxutf]; + int restart; dbus_error_init(&err); if(!dbus_message_get_args(m, &err, @@ -645,9 +646,12 @@ handlekey(DBusConnection *c, DBusMessage *m, Ictx *ctx) return handlebool(c, m, 0); stoutf(&res.commit, commit, sizeof commit); stoutf(&res.preedit, preedit, sizeof preedit); + restart = clientpreedit(ctx) && commit[0] != '\0' && preowner == ctx; + if(restart) + emitpreedit(ctx, ""); if(commit[0] != '\0') emitcommit(c, dbus_message_get_path(m), commit); - if(clientpreedit(ctx)) + if(clientpreedit(ctx) && (!restart || preedit[0] != '\0')) emitpreedit(ctx, preedit); return handlebool(c, m, res.eaten); } diff --git a/tests/engine_test.c b/tests/engine_test.c index 25f878e..df3b501 100644 --- a/tests/engine_test.c +++ b/tests/engine_test.c @@ -420,25 +420,38 @@ engine_active_owner_caret(struct ct *t) void engine_commit_contract(struct ct *t) { + static const struct { + Rune key; + char *one; + char *all; + } cases[] = { + { 'z', "ㅋ", "ㅋㅋㅋ" }, + { 'r', "ㄱ", "ㄱㄱㄱ" }, + { 'd', "ㅇ", "ㅇㅇㅇ" }, + { 'k', "ㅏ", "ㅏㅏㅏ" }, + }; Keyres res; Str all, com; char owner; - int i; + int i, j; - init(); - im.l = getlang(LangKO); - sclear(&all); - for(i = 0; i < 3; i++){ - res = ownerrequestcap(&owner, Cclientpreedit, - Keypress, 'z', 0); - CT_CHECK(t, res.eaten); - checkstr(t, "repeated consonant commit", - i == 0 ? "" : "ㅋ", &res.commit); - checkstr(t, "repeated consonant preedit", "ㅋ", &res.preedit); - sappend(&all, &res.commit); + for(j = 0; j < nelem(cases); j++){ + init(); + im.l = getlang(LangKO); + sclear(&all); + for(i = 0; i < 3; i++){ + res = ownerrequestcap(&owner, Cclientpreedit, + Keypress, cases[j].key, 0); + CT_CHECK(t, res.eaten); + checkstr(t, "repeated jamo commit", + i == 0 ? "" : cases[j].one, &res.commit); + checkstr(t, "repeated jamo preedit", cases[j].one, + &res.preedit); + sappend(&all, &res.commit); + } + sappend(&all, &res.preedit); + checkstr(t, "repeated jamo total", cases[j].all, &all); } - sappend(&all, &res.preedit); - checkstr(t, "repeated consonant total", "ㅋㅋㅋ", &all); init(); im.l = getlang(LangJP); diff --git a/tests/gtk_live_test.c b/tests/gtk_live_test.c index 9c4b05a..5f22eb5 100644 --- a/tests/gtk_live_test.c +++ b/tests/gtk_live_test.c @@ -80,7 +80,9 @@ struct Siglog char event[128]; int n; char pre[Ipcfieldmax+1]; + char shown[Ipcfieldmax+1]; char commit[Ipcfieldmax+1]; + int prechanged; }; static int @@ -568,6 +570,8 @@ prechange(GtkIMContext *ctx, Siglog *l) gchar *s; gtk_im_context_get_preedit_string(ctx, &s, NULL, NULL); + if(strcmp(l->pre, s) != 0) + l->prechanged = 1; snprintf(l->pre, sizeof l->pre, "%s", s); g_free(s); logsig(l, 'C'); @@ -585,10 +589,27 @@ commit(GtkIMContext *ctx, gchar *s, Siglog *l) { (void)ctx; snprintf(l->commit, sizeof l->commit, "%s", s); - l->pre[0] = '\0'; logsig(l, 'K'); } +static void +clearevent(Siglog *l) +{ + l->event[0] = '\0'; + l->n = 0; + l->commit[0] = '\0'; + l->prechanged = 0; +} + +static void +applyclient(Siglog *l) +{ + if(l->commit[0] != '\0') + l->shown[0] = '\0'; + if(l->prechanged) + snprintf(l->shown, sizeof l->shown, "%s", l->pre); +} + static void clearlog(Siglog *l) { @@ -748,18 +769,23 @@ main(int argc, char **argv) setpre(&srv, "ㅋ"); clearlog(&log); Check(key(ctx, win, GDK_KEY_z), "first preedit key was not eaten"); - Check(strcmp(log.event, "SC") == 0 && strcmp(log.pre, "ㅋ") == 0, - "first preedit signals were %s (%s)", log.event, log.pre); - clearlog(&log); + applyclient(&log); + Check(strcmp(log.event, "SC") == 0 && strcmp(log.pre, "ㅋ") == 0 && + strcmp(log.shown, "ㅋ") == 0, + "first preedit signals were %s (preedit %s, shown %s)", + log.event, log.pre, log.shown); + clearevent(&log); setreply(&srv, 1, Rcommitpre, 0); Check(key(ctx, win, GDK_KEY_z), "repeated preedit key was not eaten"); - Check(strcmp(log.event, "KC") == 0 && - strcmp(log.commit, "ㅋ") == 0 && strcmp(log.pre, "ㅋ") == 0, - "repeated preedit signals were %s (commit %s, preedit %s)", - log.event, log.commit, log.pre); - Check(g_utf8_strlen(log.commit, -1) + g_utf8_strlen(log.pre, -1) == 2, - "two physical keys produced commit %s and preedit %s", - log.commit, log.pre); + applyclient(&log); + Check(strcmp(log.event, "CEKSC") == 0 && + strcmp(log.commit, "ㅋ") == 0 && strcmp(log.pre, "ㅋ") == 0 && + strcmp(log.shown, "ㅋ") == 0, + "repeated preedit signals were %s (commit %s, preedit %s, shown %s)", + log.event, log.commit, log.pre, log.shown); + Check(g_utf8_strlen(log.commit, -1) + g_utf8_strlen(log.shown, -1) == 2, + "two physical keys produced commit %s and shown preedit %s", + log.commit, log.shown); /* Unconsumed input uses GtkIMContextSimple, including its stateful forms. */ setpre(&srv, ""); diff --git a/tests/ibus_client_smoke.c b/tests/ibus_client_smoke.c index cfcbb2f..7aedd8c 100644 --- a/tests/ibus_client_smoke.c +++ b/tests/ibus_client_smoke.c @@ -21,8 +21,23 @@ struct Log int transfer; int atext; int aclear; + char revent[16]; + int rn; + int repeat; + int rfirst; + int rcommit; + int rdone; }; +static void +revent(Log *log, char c) +{ + if(log->rn + 1 < (int)sizeof log->revent){ + log->revent[log->rn++] = c; + log->revent[log->rn] = '\0'; + } +} + static void legacy(IBusInputContext *ctx, IBusText *text, guint cursor, gboolean visible, void *arg) @@ -36,6 +51,28 @@ legacy(IBusInputContext *ctx, IBusText *text, guint cursor, log = arg; log->legacy++; s = ibus_text_get_text(text); + if(log->repeat != 0){ + revent(log, 'P'); + if(log->repeat == 1){ + if(s[0] == '\0'){ + if(cursor != 0 || visible) + log->invalid = 1; + }else if(strcmp(s, "ㅋ") != 0 || cursor != 1 || !visible) + log->invalid = 1; + else + log->rfirst = 1; + }else if(s[0] == '\0'){ + if(cursor != 0 || visible || log->rcommit) + log->invalid = 1; + }else if(strcmp(s, "ㅋ") != 0 || cursor != 1 || !visible || + !log->rcommit) + log->invalid = 1; + else + log->rdone = 1; + if(log->loop != NULL && log->waiting != NULL && *log->waiting) + g_main_loop_quit(log->loop); + return; + } if(strcmp(s, "k") == 0){ attrs = ibus_text_get_attributes(text); a = attrs == NULL ? NULL : ibus_attr_list_get(attrs, 0); @@ -97,6 +134,17 @@ commit(IBusInputContext *ctx, IBusText *text, void *arg) log->commit++; s = ibus_text_get_text(text); attrs = ibus_text_get_attributes(text); + if(log->repeat != 0){ + revent(log, 'K'); + if(log->repeat != 2 || strcmp(s, "ㅋ") != 0 || attrs == NULL || + ibus_attr_list_get(attrs, 0) != NULL) + log->invalid = 1; + else + log->rcommit = 1; + if(log->loop != NULL && log->waiting != NULL && *log->waiting) + g_main_loop_quit(log->loop); + return; + } if(strcmp(s, "か") != 0 || attrs == NULL || ibus_attr_list_get(attrs, 0) != NULL) log->invalid = 1; @@ -194,10 +242,22 @@ main(int argc, char **argv) waitflag(&log, &log.aclear); ibus_input_context_focus_out(b); } + ibus_input_context_focus_in(a); + ok = ok && ibus_input_context_process_key_event(a, 's', 0, + IBUS_CONTROL_MASK); + log.repeat = 1; + ok = ok && ibus_input_context_process_key_event(a, 'z', 0, 0) && + waitflag(&log, &log.rfirst); + log.repeat = 2; + log.revent[0] = '\0'; + log.rn = 0; + ok = ok && ibus_input_context_process_key_event(a, 'z', 0, 0) && + waitflag(&log, &log.rdone) && strcmp(log.revent, "PKP") == 0; + log.repeat = 0; ibus_input_context_focus_out(a); - if(log.legacy == 0 || log.modern != 0 || log.commit != 1 || + if(log.legacy == 0 || log.modern != 0 || log.commit != 2 || log.invalid || !log.done || !log.atext || !log.aclear || - log.clearctx != a) + log.clearctx != a || !log.rdone) ok = 0; if(b != NULL) g_object_unref(b); @@ -205,9 +265,10 @@ main(int argc, char **argv) g_object_unref(bus); if(!ok){ fprintf(stderr, - "ibus_client_smoke: legacy=%d modern=%d commit=%d invalid=%d preedit=%d committed=%d transfer-text=%d a-clear=%d\n", + "ibus_client_smoke: legacy=%d modern=%d commit=%d invalid=%d preedit=%d committed=%d transfer-text=%d a-clear=%d repeat=%s\n", log.legacy, log.modern, log.commit, log.invalid, - log.sawpreedit, log.sawcommit, log.atext, log.aclear); + log.sawpreedit, log.sawcommit, log.atext, log.aclear, + log.revent); return 1; } printf("official libibus client preedit, commit, and owner clear: ok\n");