From e32cea3296d6526f02e9acdca6776bac87c08270 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Mon, 17 Aug 2026 01:55:25 +0900 Subject: [PATCH] engine: Backspace deletes the last kana shown; Tab converts like Space MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backspace undid a keystroke: な became ん, かんじ became かんj, きゃ became ky. Like every Japanese IME it now deletes the last kana as shown — な goes, かんじ becomes かん, きゃ becomes き — while a romaji letter that never became kana still goes one at a time. Tab stepped through candidates in a search and committed in Japanese; it steps through them there too, with Space, and Shift+Tab steps back. --- README.md | 9 ++++---- strans.c | 20 ++++++++++++----- tests/engine_test.c | 54 +++++++++++++++++++++++++++------------------ 3 files changed, 51 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index d8d5c34..b6beddc 100644 --- a/README.md +++ b/README.md @@ -24,11 +24,12 @@ or `Super` held it commits what is pending and goes to the application, so `Ctrl+Shift+V` still pastes. A complete Japanese reading shows its Kanji candidates with none chosen. -`Space` chooses the first and then steps on, wrapping (`Shift+Space` steps -back); `Up`/`Down` and `PageUp`/`PageDown` move without wrapping. An -unmodified `1`-`9` commits that row of the current page. `Enter` and `Tab` -commit the chosen candidate, or the reading when none is chosen, as `0` +`Space` or `Tab` chooses the first and then steps on, wrapping (with +`Shift`, back); `Up`/`Down` and `PageUp`/`PageDown` move without wrapping. +An unmodified `1`-`9` commits that row of the current page. `Enter` +commits the chosen candidate, or the reading when none is chosen, as `0` always does; so does typing on, or any key that ends the composition. +`Backspace` deletes the last kana shown. Japanese consumes the confirming key; Korean and Vietnamese pass it on to the application. `Space` adds the reading in Katakana as the last candidate, so a word the dictionary lacks converts to Katakana with one diff --git a/strans.c b/strans.c index ea9ba16..2480bdf 100644 --- a/strans.c +++ b/strans.c @@ -356,13 +356,20 @@ commitim(Im *p, Str *com) sclear(&p->raw); } +/* Deletes the last kana as shown, not the last key: kya loses ゃ. */ static void backjp(Im *p) { - if(p->raw.n != 0) - spopr(&p->raw); - else + Str v; + + if(p->raw.n == 0) spopr(&p->pre); + else if(mapget(p->l->map, &p->raw, &v)){ + spopr(&v); + sappend(&p->pre, &v); + sclear(&p->raw); + }else + spopr(&p->raw); } /* @@ -800,9 +807,10 @@ transition(u32int ks, u32int mod, Str *com) reset(); return 1; } - if(ks == ' ' && isjp(&im) && haspre(&im) && !(mod & ~Mshift)){ - /* Space converts: it steps through the candidates, Katakana - * last; a reading with none is committed. */ + if((ks == ' ' || ks == Ktab) && isjp(&im) && haspre(&im) && + !(mod & ~Mshift)){ + /* Space and Tab convert: they step through the candidates, + * Katakana last; a reading with none is committed. */ katakouho(); if(im.nkouho != 0) cyclekouho(mod & Mshift ? -1 : 1); diff --git a/tests/engine_test.c b/tests/engine_test.c index ecec12a..8ff3067 100644 --- a/tests/engine_test.c +++ b/tests/engine_test.c @@ -120,9 +120,9 @@ engine_backspace_clears_candidates(struct ct *t) checkstr(t, "chosen candidate backspace", "na", &im.raw); CT_CHECK(t, keystroke(Kback, 0, &com)); checkstr(t, "backspace commit", "", &com); - checkstr(t, "pending romaji after backspace", "n", &im.raw); + checkstr(t, "backspace deletes the kana shown", "", &im.raw); impre(&im, &shown); - checkstr(t, "shown preedit after backspace", "ん", &shown); + checkstr(t, "shown preedit after backspace", "", &shown); CT_EQ_INT(t, 0, im.nkouho); CT_EQ_INT(t, -1, im.sel); } @@ -852,21 +852,28 @@ engine_candidate_page_movement(struct ct *t) void engine_candidate_completion(struct ct *t) { - static Rune keys[] = { Kret, Ktab }; Str com; - int i; - for(i = 0; i < nelem(keys); i++){ - init(); - im.l = getlang(LangJP); - im.pre = mkstr("reading"); - setcandidates(1); - sclear(&com); - CT_CHECK(t, keystroke(keys[i], 0, &com)); - checkstr(t, "unselected candidate commits reading", - "reading", &com); - CT_EQ_INT(t, 0, im.nkouho); - } + init(); + im.l = getlang(LangJP); + im.pre = mkstr("reading"); + setcandidates(1); + sclear(&com); + CT_CHECK(t, keystroke(Kret, 0, &com)); + checkstr(t, "unselected candidate commits reading", "reading", &com); + CT_EQ_INT(t, 0, im.nkouho); + + init(); + im.l = getlang(LangJP); + im.pre = mkstr("reading"); + setcandidates(2); + sclear(&com); + CT_CHECK(t, keystroke(Ktab, 0, &com)); + CT_EQ_INT(t, 0, im.sel); + CT_CHECK(t, keystroke(Ktab, Mshift, &com)); + CT_EQ_INT(t, 1, im.sel); + CT_CHECK(t, keystroke(Kret, 0, &com)); + checkstr(t, "Tab steps through the candidates", "c2", &com); candidatebegin(2); im.pre = mkstr("reading"); @@ -1250,8 +1257,6 @@ engine_japanese_candidates(struct ct *t) if(!typekeys(t, "kanji", &com)) goto cleanup; CT_CHECK(t, keystroke(Kback, 0, &com)); - CT_EQ_INT(t, 0, im.nkouho); - CT_CHECK(t, keystroke(Kback, 0, &com)); if(CT_EQ_INT(t, 1, im.nkouho)) checkstr(t, "shorter reading candidate", "缶", &im.kouho[0]); cleanup: @@ -1270,13 +1275,18 @@ engine_japanese_backspace_and_boundaries(struct ct *t) if(typekeys(t, "kanji", &com)){ CT_CHECK(t, keystroke(Kback, 0, &com)); impre(&im, &shown); - checkstr(t, "backspace pending i", "かんj", &shown); + checkstr(t, "backspace deletes じ", "かん", &shown); CT_CHECK(t, keystroke(Kback, 0, &com)); impre(&im, &shown); - checkstr(t, "backspace pending j", "かん", &shown); - CT_CHECK(t, keystroke(Kback, 0, &com)); - impre(&im, &shown); - checkstr(t, "backspace accumulated kana", "か", &shown); + checkstr(t, "backspace deletes ん", "か", &shown); + if(typekeys(t, "kyu", &com)){ + CT_CHECK(t, keystroke(Kback, 0, &com)); + impre(&im, &shown); + checkstr(t, "backspace deletes ゅ", "かき", &shown); + CT_CHECK(t, keystroke(Kback, 0, &com)); + CT_CHECK(t, keystroke(Kback, 0, &com)); + CT_CHECK(t, !haspre(&im)); + } } init();