diff --git a/README.md b/README.md index 85edc4b..366c67b 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,9 @@ 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` always does; so does typing on, or any key that ends the composition. Japanese consumes the confirming key; Korean and Vietnamese pass it on to -the application. `Space` on a reading without candidates commits it and -types nothing. `Backspace` and `Esc` on a chosen candidate go back to the +the application. `Space` adds the reading in Katakana as the last +candidate, so a word the dictionary lacks converts to Katakana with one +`Space`. `Backspace` and `Esc` on a chosen candidate go back to the reading. In a temporary Emoji or Hanja search, `Enter` commits the highlighted result and `Tab`/`Shift-Tab` wrap through the results. Leaving the field or clicking elsewhere commits what is pending. `Esc` cancels a diff --git a/strans.c b/strans.c index 257f2d7..0076964 100644 --- a/strans.c +++ b/strans.c @@ -313,6 +313,23 @@ dictqjp(void) dictqokuri(&reading); } +/* The reading in Katakana is the last candidate, as in every IME. */ +static void +katakouho(void) +{ + Str reading, k; + int i; + + if(!jpreading(im.l->map, &im.pre, &im.raw, &reading)) + return; + k = reading; + for(i = 0; i < k.n; i++) + if(k.r[i] >= L'ぁ' && k.r[i] <= L'ゖ') + k.r[i] += L'ァ' - L'ぁ'; + if(scmp(&k, &reading) != 0) + addkouho(&k); +} + static int setlang(int c) { @@ -755,8 +772,9 @@ transition(u32int ks, u32int mod, Str *com) return 1; } if(ks == ' ' && isjp(&im) && haspre(&im) && !(mod & ~Mshift)){ - /* Space converts: it steps through the candidates, or - * commits a reading that has none. */ + /* Space converts: it steps through the candidates, Katakana + * last; a reading with none is committed. */ + katakouho(); if(im.nkouho != 0) cyclekouho(mod & Mshift ? -1 : 1); else @@ -811,8 +829,8 @@ transition(u32int ks, u32int mod, Str *com) flush(com); return setlang(c); } - if(ks == '0' && im.nkouho > 0){ - im.sel = -1; + if(ks == '0' && isjp(&im) && haspre(&im)){ + im.sel = -1; /* 0 commits the reading, as 1-9 pick candidates */ flush(com); return 1; } diff --git a/tests/engine_test.c b/tests/engine_test.c index 4df825d..05c1475 100644 --- a/tests/engine_test.c +++ b/tests/engine_test.c @@ -1146,12 +1146,14 @@ engine_japanese_candidates(struct ct *t) CT_CHECK(t, keystroke(' ', 0, &com)); CT_EQ_INT(t, 1, im.sel); CT_CHECK(t, keystroke(' ', 0, &com)); + CT_EQ_INT(t, 2, im.sel); + CT_CHECK(t, keystroke(' ', 0, &com)); CT_EQ_INT(t, 0, im.sel); CT_CHECK(t, keystroke(' ', Mshift, &com)); - CT_EQ_INT(t, 1, im.sel); + CT_EQ_INT(t, 2, im.sel); CT_CHECK(t, keystroke(Kback, 0, &com)); CT_EQ_INT(t, -1, im.sel); - CT_EQ_INT(t, 2, im.nkouho); + CT_EQ_INT(t, 3, im.nkouho); CT_CHECK(t, keystroke(' ', 0, &com)); CT_CHECK(t, keystroke('w', 0, &com)); CT_CHECK(t, keystroke('o', 0, &com)); @@ -1160,45 +1162,22 @@ engine_japanese_candidates(struct ct *t) checkstr(t, "reading after the candidate", "を", &shown); sclear(&com); CT_CHECK(t, keystroke(' ', 0, &com)); - checkstr(t, "Space commits a reading without candidates", "を", &com); - CT_EQ_INT(t, 0, im.pre.n); - CT_EQ_INT(t, 0, im.raw.n); + if(CT_EQ_INT(t, 1, im.nkouho)) + checkstr(t, "Space offers Katakana without candidates", "ヲ", + &im.kouho[0]); + CT_EQ_INT(t, 0, im.sel); + CT_CHECK(t, keystroke(Kret, 0, &com)); + checkstr(t, "Katakana committed", "ヲ", &com); CT_CHECK(t, !keystroke(' ', 0, &com)); sclear(&com); if(!typekeys(t, "kanji", &com)) goto cleanup; - CT_CHECK(t, keystroke(' ', 0, &com)); - CT_CHECK(t, keystroke(Kesc, 0, &com)); - CT_EQ_INT(t, -1, im.sel); - impre(&im, &shown); - checkstr(t, "Escape goes back to the reading", "かんじ", &shown); - CT_CHECK(t, keystroke(Kesc, 0, &com)); - CT_EQ_INT(t, 0, im.pre.n); - CT_EQ_INT(t, 0, im.raw.n); - CT_EQ_INT(t, 0, im.nkouho); - sclear(&com); - if(!typekeys(t, "kanji", &com)) - goto cleanup; - CT_CHECK(t, keystroke(Kdown, 0, &com)); - CT_CHECK(t, keystroke('s', Mctrl, &com)); - checkstr(t, "language switch takes the candidate", "漢字", &com); - CT_EQ_INT(t, LangKO, im.l->lang); - im.l = jp; - /* A romaji typo stays in the reading for Backspace to mend. */ - sclear(&com); - if(!typekeys(t, "kanjr", &com)) - goto cleanup; - impre(&im, &shown); - checkstr(t, "typo kept", "かんjr", &shown); - CT_CHECK(t, keystroke(Kback, 0, &com)); - impre(&im, &shown); - checkstr(t, "typo half mended", "かんj", &shown); - CT_CHECK(t, keystroke(Kback, 0, &com)); - if(!typekeys(t, "ji", &com)) - goto cleanup; - impre(&im, &shown); - checkstr(t, "typo mended", "かんじ", &shown); CT_EQ_INT(t, 2, im.nkouho); + CT_CHECK(t, keystroke(' ', 0, &com)); + if(CT_EQ_INT(t, 3, im.nkouho)) + checkstr(t, "Katakana after the candidates", "カンジ", + &im.kouho[2]); + CT_CHECK(t, keystroke(Kesc, 0, &com)); CT_CHECK(t, keystroke(Kesc, 0, &com)); /* SKK's okuri-ari entries convert verbs: stem plus okurigana. */ setdict(jp->dict, "かk", "書 描"); @@ -1226,6 +1205,47 @@ engine_japanese_candidates(struct ct *t) checkstr(t, "sokuon written in kana", "行った", &im.kouho[1]); } CT_CHECK(t, keystroke(Kesc, 0, &com)); + /* A romaji typo stays in the reading for Backspace to mend. */ + if(!typekeys(t, "kanjr", &com)) + goto cleanup; + impre(&im, &shown); + checkstr(t, "typo kept", "かんjr", &shown); + CT_CHECK(t, keystroke(Kback, 0, &com)); + impre(&im, &shown); + checkstr(t, "typo half mended", "かんj", &shown); + CT_CHECK(t, keystroke(Kback, 0, &com)); + if(!typekeys(t, "ji", &com)) + goto cleanup; + impre(&im, &shown); + checkstr(t, "typo mended", "かんじ", &shown); + CT_EQ_INT(t, 2, im.nkouho); + CT_CHECK(t, keystroke('0', 0, &com)); + checkstr(t, "0 commits the reading", "かんじ", &com); + sclear(&com); + if(!typekeys(t, "wo", &com)) + goto cleanup; + CT_CHECK(t, keystroke('0', 0, &com)); + checkstr(t, "0 commits a reading without candidates", "を", &com); + sclear(&com); + if(!typekeys(t, "kanji", &com)) + goto cleanup; + CT_CHECK(t, keystroke(' ', 0, &com)); + CT_CHECK(t, keystroke(Kesc, 0, &com)); + CT_EQ_INT(t, -1, im.sel); + impre(&im, &shown); + checkstr(t, "Escape goes back to the reading", "かんじ", &shown); + CT_CHECK(t, keystroke(Kesc, 0, &com)); + CT_EQ_INT(t, 0, im.pre.n); + CT_EQ_INT(t, 0, im.raw.n); + CT_EQ_INT(t, 0, im.nkouho); + sclear(&com); + if(!typekeys(t, "kanji", &com)) + goto cleanup; + CT_CHECK(t, keystroke(Kdown, 0, &com)); + CT_CHECK(t, keystroke('s', Mctrl, &com)); + checkstr(t, "language switch takes the candidate", "漢字", &com); + CT_EQ_INT(t, LangKO, im.l->lang); + im.l = jp; /* Backspace looks a complete shorter reading up again. */ setdict(jp->dict, "かん", "缶"); if(!typekeys(t, "kanji", &com))