engine: no candidate is chosen until the user moves to one; Space converts
A complete Japanese reading showed its candidates with the first row highlighted, yet Enter committed the reading unless the user had moved to a candidate: the highlight lied. Now sel is -1 while nothing is chosen, and it alone says what Enter commits; candidatechosen goes. Every key that ends a composition — Enter, Tab, a language switch, a special key, a modifier chord, typing on — now commits the chosen candidate through one flush; before, only Enter and Tab did, and Ctrl+S after choosing 漢字 committed かんじ. Space in a Japanese mode is the conversion key, as in every other Japanese IME: it steps through the candidates (Shift+Space backwards, both wrapping) and commits a reading that has none, without typing a space. Backspace and Escape on a chosen candidate go back to the reading first. Tab in a search wraps through the same cyclekouho. reset() no longer forgets the caret: a chosen candidate confirmed by typing on would otherwise redraw the next reading at the pointer.
This commit is contained in:
@@ -116,6 +116,9 @@ engine_backspace_clears_candidates(struct ct *t)
|
||||
im.nkouho = 1;
|
||||
im.sel = 0;
|
||||
CT_CHECK(t, keystroke(Kback, 0, &com));
|
||||
CT_EQ_INT(t, -1, im.sel);
|
||||
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);
|
||||
impre(&im, &shown);
|
||||
@@ -162,7 +165,7 @@ engine_candidate_shortcut_modifiers(struct ct *t)
|
||||
init();
|
||||
im.kouho[9] = mkstr("must-not-select");
|
||||
im.nkouho = 10;
|
||||
im.sel = 9;
|
||||
im.sel = -1;
|
||||
selected = im.kouho[9];
|
||||
sclear(&com);
|
||||
CT_CHECK(t, !keystroke('1', mods[i], &com));
|
||||
@@ -277,7 +280,6 @@ engine_active_owner_reset(struct ct *t)
|
||||
CT_EQ_PTR(t, &owner, activeowner);
|
||||
checkstr(t, "reset hands the reading back", "か", &res.commit);
|
||||
CT_EQ_INT(t, 0, res.preedit.n);
|
||||
CT_CHECK(t, !caret.valid);
|
||||
res = ownerrequest(&owner, Keypress, 'n', 0);
|
||||
checkstr(t, "same owner after reset", "ん", &res.preedit);
|
||||
}
|
||||
@@ -633,7 +635,7 @@ engine_language_switch_state(struct ct *t)
|
||||
if(steps[i].stale){
|
||||
im.kouho[0] = mkstr("stale");
|
||||
im.nkouho = 1;
|
||||
im.sel = 0;
|
||||
im.sel = -1;
|
||||
}
|
||||
sclear(&com);
|
||||
eaten = keystroke(steps[i].key, steps[i].mod, &com);
|
||||
@@ -693,7 +695,6 @@ struct Searchfix
|
||||
Trie *dict;
|
||||
int activecap;
|
||||
Drawcmd lastdraw;
|
||||
int candidatechosen;
|
||||
};
|
||||
|
||||
static int
|
||||
@@ -723,7 +724,6 @@ setcandidates(int n)
|
||||
im.kouho[i] = mkstr(name);
|
||||
}
|
||||
im.nkouho = n;
|
||||
selectfirst();
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -873,6 +873,7 @@ engine_candidate_completion(struct ct *t)
|
||||
im.pre = mkstr("reading");
|
||||
sclear(&com);
|
||||
CT_CHECK(t, keystroke(Kdown, 0, &com));
|
||||
CT_CHECK(t, keystroke(Kdown, 0, &com));
|
||||
CT_CHECK(t, keystroke(Kret, 0, &com));
|
||||
checkstr(t, "explicit candidate", "c2", &com);
|
||||
|
||||
@@ -888,13 +889,14 @@ engine_candidate_completion(struct ct *t)
|
||||
CT_CHECK(t, keystroke(Kret, 0, &com));
|
||||
checkstr(t, "Enter without candidates", "reading", &com);
|
||||
|
||||
/* A digit with no such row on the page is an ordinary key. */
|
||||
/* A digit with no such row on the page is an ordinary key: it
|
||||
* confirms the candidate paged to and passes on. */
|
||||
candidatebegin(32);
|
||||
im.pre = mkstr("reading");
|
||||
im.sel = 27;
|
||||
sclear(&com);
|
||||
CT_CHECK(t, !keystroke('9', 0, &com));
|
||||
checkstr(t, "unavailable short-page digit", "reading", &com);
|
||||
checkstr(t, "unavailable short-page digit", "c28", &com);
|
||||
CT_EQ_INT(t, 0, im.nkouho);
|
||||
}
|
||||
|
||||
@@ -913,7 +915,6 @@ searchsave(Searchfix *f, int lang)
|
||||
f->dict = f->dictlang->dict;
|
||||
f->activecap = activecap;
|
||||
f->lastdraw = lastdraw;
|
||||
f->candidatechosen = candidatechosen;
|
||||
draindraw(nil);
|
||||
}
|
||||
|
||||
@@ -956,7 +957,6 @@ searchend(Searchfix *f)
|
||||
search = f->search;
|
||||
activecap = f->activecap;
|
||||
lastdraw = f->lastdraw;
|
||||
candidatechosen = f->candidatechosen;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -982,7 +982,7 @@ engine_popup_preedit_capability(struct ct *t)
|
||||
if(CT_CHECK(t, draindraw(&dc) > 0)){
|
||||
CT_EQ_INT(t, 0, dc.pre.n);
|
||||
CT_EQ_INT(t, 1, dc.nkouho);
|
||||
CT_EQ_INT(t, 0, dc.sel);
|
||||
CT_EQ_INT(t, -1, dc.sel);
|
||||
checkstr(t, "client-preedit candidate", "家", &dc.kouho[0]);
|
||||
}
|
||||
|
||||
@@ -992,11 +992,11 @@ engine_popup_preedit_capability(struct ct *t)
|
||||
if(CT_CHECK(t, draindraw(&dc) > 0)){
|
||||
checkstr(t, "popup preedit", "か", &dc.pre);
|
||||
CT_EQ_INT(t, 1, dc.nkouho);
|
||||
CT_EQ_INT(t, 0, dc.sel);
|
||||
CT_EQ_INT(t, -1, dc.sel);
|
||||
checkstr(t, "popup candidate", "家", &dc.kouho[0]);
|
||||
}
|
||||
CT_EQ_INT(t, 1, im.nkouho);
|
||||
CT_EQ_INT(t, 0, im.sel);
|
||||
CT_EQ_INT(t, -1, im.sel);
|
||||
checkstr(t, "retained popup candidate", "家", &im.kouho[0]);
|
||||
|
||||
kres = ownerrequestcap(&client, 0, Keycap, 0, 0);
|
||||
@@ -1016,11 +1016,11 @@ engine_popup_preedit_capability(struct ct *t)
|
||||
if(CT_CHECK(t, draindraw(&dc) > 0)){
|
||||
CT_EQ_INT(t, 0, dc.pre.n);
|
||||
CT_EQ_INT(t, 1, dc.nkouho);
|
||||
CT_EQ_INT(t, 0, dc.sel);
|
||||
CT_EQ_INT(t, -1, dc.sel);
|
||||
checkstr(t, "restored client candidate", "家", &dc.kouho[0]);
|
||||
}
|
||||
CT_EQ_INT(t, 1, im.nkouho);
|
||||
CT_EQ_INT(t, 0, im.sel);
|
||||
CT_EQ_INT(t, -1, im.sel);
|
||||
checkstr(t, "retained client candidate", "家", &im.kouho[0]);
|
||||
kres = ownerrequestcap(&client, Cclientpreedit, Keycap, 0, 0);
|
||||
CT_CHECK(t, kres.eaten);
|
||||
@@ -1116,14 +1116,64 @@ engine_japanese_candidates(struct ct *t)
|
||||
checkstr(t, "complete Japanese reading", "かんじ", &shown);
|
||||
if(!CT_EQ_INT(t, 2, im.nkouho))
|
||||
goto cleanup;
|
||||
CT_EQ_INT(t, 0, im.sel);
|
||||
CT_EQ_INT(t, -1, im.sel);
|
||||
checkstr(t, "candidate one", "漢字", &im.kouho[0]);
|
||||
checkstr(t, "candidate two", "幹事", &im.kouho[1]);
|
||||
CT_CHECK(t, keystroke(Kdown, 0, &com));
|
||||
CT_EQ_INT(t, 0, im.sel);
|
||||
CT_CHECK(t, keystroke(Kdown, 0, &com));
|
||||
CT_EQ_INT(t, 1, im.sel);
|
||||
CT_CHECK(t, keystroke(Kret, 0, &com));
|
||||
checkstr(t, "selected Kanji", "幹事", &com);
|
||||
CT_EQ_INT(t, 0, im.nkouho);
|
||||
/* Space converts: it steps through the candidates and wraps;
|
||||
* typing on takes the chosen one; Backspace goes back. */
|
||||
if(!typekeys(t, "kanji", &com))
|
||||
goto cleanup;
|
||||
sclear(&com);
|
||||
CT_CHECK(t, keystroke(' ', 0, &com));
|
||||
CT_EQ_INT(t, 0, im.sel);
|
||||
CT_CHECK(t, keystroke(' ', 0, &com));
|
||||
CT_EQ_INT(t, 1, 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_CHECK(t, keystroke(Kback, 0, &com));
|
||||
CT_EQ_INT(t, -1, im.sel);
|
||||
CT_EQ_INT(t, 2, im.nkouho);
|
||||
CT_CHECK(t, keystroke(' ', 0, &com));
|
||||
CT_CHECK(t, keystroke('w', 0, &com));
|
||||
CT_CHECK(t, keystroke('o', 0, &com));
|
||||
checkstr(t, "typing on takes the candidate", "漢字", &com);
|
||||
impre(&im, &shown);
|
||||
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);
|
||||
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;
|
||||
/* Backspace looks a complete shorter reading up again. */
|
||||
setdict(jp->dict, "かん", "缶");
|
||||
if(!typekeys(t, "kanji", &com))
|
||||
@@ -1179,8 +1229,8 @@ engine_japanese_backspace_and_boundaries(struct ct *t)
|
||||
im.l = getlang(LangJP);
|
||||
sclear(&com);
|
||||
if(typekeys(t, "kanji", &com)){
|
||||
CT_CHECK(t, keystroke(' ', 0, &com));
|
||||
checkstr(t, "real input boundary", "かんじ ", &com);
|
||||
CT_CHECK(t, keystroke(L'日', 0, &com));
|
||||
checkstr(t, "real input boundary", "かんじ日", &com);
|
||||
}
|
||||
|
||||
init();
|
||||
@@ -1960,7 +2010,7 @@ engine_full_boundary_passthrough(struct ct *t)
|
||||
im.pre.r[i] = L'あ';
|
||||
im.pre.n = Maxrunes;
|
||||
sclear(&com);
|
||||
CT_CHECK(t, !keystroke(' ', 0, &com));
|
||||
CT_CHECK(t, !keystroke(L'日', 0, &com));
|
||||
CT_EQ_INT(t, Maxrunes, com.n);
|
||||
for(i = 0; i < Maxrunes; i++)
|
||||
CT_EQ_UINT(t, L'あ', com.r[i]);
|
||||
@@ -1973,9 +2023,9 @@ engine_full_boundary_passthrough(struct ct *t)
|
||||
im.pre.r[i] = L'あ';
|
||||
im.pre.n = Maxrunes-1;
|
||||
sclear(&com);
|
||||
CT_CHECK(t, keystroke(' ', 0, &com));
|
||||
CT_CHECK(t, keystroke(L'日', 0, &com));
|
||||
CT_EQ_INT(t, Maxrunes, com.n);
|
||||
CT_EQ_UINT(t, ' ', com.r[Maxrunes-1]);
|
||||
CT_EQ_UINT(t, L'日', com.r[Maxrunes-1]);
|
||||
|
||||
/* Typing on at the limit commits the kana and keeps the syllable. */
|
||||
init();
|
||||
|
||||
Reference in New Issue
Block a user