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:
20
README.md
20
README.md
@@ -16,14 +16,18 @@ Vietnamese Telex is also available as a compatibility mode.
|
|||||||
| `Ctrl+E` | Emoji and symbol search |
|
| `Ctrl+E` | Emoji and symbol search |
|
||||||
| `Ctrl+H` | One-shot Hanja search |
|
| `Ctrl+H` | One-shot Hanja search |
|
||||||
|
|
||||||
Use `Up`/`Down` to move through candidates and `PageUp`/`PageDown` to move by
|
A complete Japanese reading shows its Kanji candidates with none chosen.
|
||||||
nine without wrapping. An unmodified `1`-`9` selects that row on the current
|
`Space` chooses the first and then steps on, wrapping (`Shift+Space` steps
|
||||||
page. `Enter` and `Tab` commit a candidate you have moved to; otherwise they
|
back); `Up`/`Down` and `PageUp`/`PageDown` move without wrapping. An
|
||||||
commit the reading, as `0` always does. Japanese consumes the confirming key;
|
unmodified `1`-`9` commits that row of the current page. `Enter` and `Tab`
|
||||||
Korean and Vietnamese pass it on to the application. In a temporary Emoji or
|
commit the chosen candidate, or the reading when none is chosen, as `0`
|
||||||
Hanja search, `Enter` commits the highlighted result and `Tab`/`Shift-Tab`
|
always does; so does typing on, or any key that ends the composition.
|
||||||
wrap through the results. Leaving the field or clicking elsewhere commits
|
Japanese consumes the confirming key; Korean and Vietnamese pass it on to
|
||||||
what is pending; `Esc` cancels it.
|
the application. `Space` on a reading without candidates commits it and
|
||||||
|
types nothing. `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 it.
|
||||||
|
|
||||||
Hiragana mode composes a complete reading before offering Kanji candidates.
|
Hiragana mode composes a complete reading before offering Kanji candidates.
|
||||||
Katakana mode does not perform Kanji conversion. Emoji and Hanja searches
|
Katakana mode does not perform Kanji conversion. Emoji and Hanja searches
|
||||||
|
|||||||
138
strans.c
138
strans.c
@@ -5,7 +5,6 @@ static Im im;
|
|||||||
static void *activeowner;
|
static void *activeowner;
|
||||||
static int activecap;
|
static int activecap;
|
||||||
static Caret caret;
|
static Caret caret;
|
||||||
static int candidatechosen;
|
|
||||||
static Drawcmd lastdraw;
|
static Drawcmd lastdraw;
|
||||||
static Emit transjp(Im*, Rune);
|
static Emit transjp(Im*, Rune);
|
||||||
static void backjp(Im*);
|
static void backjp(Im*);
|
||||||
@@ -54,12 +53,12 @@ mapget(Trie *t, Str *key, Str *out)
|
|||||||
return mapmatch(t, key, out) == TrieExact;
|
return mapmatch(t, key, out) == TrieExact;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* sel is the chosen candidate; -1 while the user has not moved to one. */
|
||||||
static void
|
static void
|
||||||
clearkouho(void)
|
clearkouho(void)
|
||||||
{
|
{
|
||||||
im.nkouho = 0;
|
im.nkouho = 0;
|
||||||
im.sel = -1;
|
im.sel = -1;
|
||||||
candidatechosen = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -99,7 +98,16 @@ movekouho(int delta)
|
|||||||
im.sel = 0;
|
im.sel = 0;
|
||||||
if(im.sel >= im.nkouho)
|
if(im.sel >= im.nkouho)
|
||||||
im.sel = im.nkouho - 1;
|
im.sel = im.nkouho - 1;
|
||||||
candidatechosen = 1;
|
}
|
||||||
|
|
||||||
|
/* Space and Tab step through the candidates and wrap around. */
|
||||||
|
static void
|
||||||
|
cyclekouho(int delta)
|
||||||
|
{
|
||||||
|
if(im.sel < 0)
|
||||||
|
im.sel = delta > 0 ? 0 : im.nkouho - 1;
|
||||||
|
else
|
||||||
|
im.sel = (im.sel + delta + im.nkouho) % im.nkouho;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -230,7 +238,7 @@ redraw(void)
|
|||||||
channbsend(drawc, &dc);
|
channbsend(drawc, &dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Kanji candidates for a complete reading. */
|
/* Kanji candidates for a complete reading; none is chosen yet. */
|
||||||
static void
|
static void
|
||||||
dictqjp(void)
|
dictqjp(void)
|
||||||
{
|
{
|
||||||
@@ -240,7 +248,6 @@ dictqjp(void)
|
|||||||
if(!jpreading(im.l->map, &im.pre, &im.raw, &reading) || reading.n == 0)
|
if(!jpreading(im.l->map, &im.pre, &im.raw, &reading) || reading.n == 0)
|
||||||
return;
|
return;
|
||||||
im.nkouho = dictlookup(im.l, &reading, im.kouho, Maxkouho);
|
im.nkouho = dictlookup(im.l, &reading, im.kouho, Maxkouho);
|
||||||
selectfirst();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -269,12 +276,6 @@ commitim(Im *p, Str *com)
|
|||||||
sclear(&p->raw);
|
sclear(&p->raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
commit(Str *com)
|
|
||||||
{
|
|
||||||
commitim(&im, com);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
backjp(Im *p)
|
backjp(Im *p)
|
||||||
{
|
{
|
||||||
@@ -542,10 +543,7 @@ searchlang(Rune c)
|
|||||||
static void
|
static void
|
||||||
endsearch(void)
|
endsearch(void)
|
||||||
{
|
{
|
||||||
search.lang = 0;
|
memset(&search, 0, sizeof search);
|
||||||
sclear(&search.seed);
|
|
||||||
sclear(&search.raw);
|
|
||||||
sclear(&search.text);
|
|
||||||
clearkouho();
|
clearkouho();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -555,14 +553,23 @@ reset(void)
|
|||||||
sclear(&im.pre);
|
sclear(&im.pre);
|
||||||
sclear(&im.raw);
|
sclear(&im.raw);
|
||||||
endsearch();
|
endsearch();
|
||||||
memset(&caret, 0, sizeof caret);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Whatever is pending becomes committed text: the search query, a chosen
|
||||||
|
* candidate, else the reading. Enter does this, and so do a reset and a
|
||||||
|
* lost focus.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
commitsearch(Str *com)
|
flush(Str *com)
|
||||||
{
|
{
|
||||||
sappend(com, &search.text);
|
if(search.lang)
|
||||||
endsearch();
|
sappend(com, &search.text);
|
||||||
|
else if(im.sel >= 0)
|
||||||
|
sappend(com, &im.kouho[im.sel]);
|
||||||
|
else
|
||||||
|
commitim(&im, com);
|
||||||
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -572,36 +579,18 @@ commitsearch(Str *com)
|
|||||||
static void
|
static void
|
||||||
startsearch(int lang, Str *com)
|
startsearch(int lang, Str *com)
|
||||||
{
|
{
|
||||||
Str pending;
|
Str seed;
|
||||||
|
|
||||||
impre(&im, &pending);
|
sclear(&seed);
|
||||||
if(lang == LangHANJA){
|
if(lang == LangHANJA && !search.lang && im.sel < 0)
|
||||||
sclear(&im.pre);
|
impre(&im, &seed);
|
||||||
sclear(&im.raw);
|
|
||||||
}else
|
|
||||||
commit(com);
|
|
||||||
commitsearch(com);
|
|
||||||
search.lang = lang;
|
|
||||||
if(lang == LangHANJA){
|
|
||||||
search.seed = pending;
|
|
||||||
searchquery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Whatever is pending becomes committed text, a moved-to candidate
|
|
||||||
* first: Enter does this, and so do a reset and a lost focus.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
flush(Str *com)
|
|
||||||
{
|
|
||||||
if(search.lang)
|
|
||||||
commitsearch(com);
|
|
||||||
else if(candidatechosen && im.sel >= 0 && im.sel < im.nkouho)
|
|
||||||
sappend(com, &im.kouho[im.sel]);
|
|
||||||
else
|
else
|
||||||
commit(com);
|
flush(com);
|
||||||
reset();
|
reset();
|
||||||
|
search.lang = lang;
|
||||||
|
search.seed = seed;
|
||||||
|
if(lang == LangHANJA)
|
||||||
|
searchquery();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -630,24 +619,15 @@ searchkey(u32int ks, u32int mod, Str *com)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if(ks == Ktab){
|
if(ks == Ktab){
|
||||||
if(im.nkouho == 0)
|
if(im.nkouho != 0)
|
||||||
return 1;
|
cyclekouho(mod & Mshift ? -1 : 1);
|
||||||
if(mod & Mshift){
|
|
||||||
if(im.sel <= 0)
|
|
||||||
im.sel = im.nkouho - 1;
|
|
||||||
else
|
|
||||||
im.sel--;
|
|
||||||
}else if(im.sel >= im.nkouho - 1)
|
|
||||||
im.sel = 0;
|
|
||||||
else
|
|
||||||
im.sel++;
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if(ks == Kret){
|
if(ks == Kret){
|
||||||
if(im.nkouho > 0)
|
if(im.nkouho > 0)
|
||||||
picksearch(max(im.sel, 0), com);
|
picksearch(max(im.sel, 0), com);
|
||||||
else
|
else
|
||||||
commitsearch(com);
|
flush(com);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if(ks == Kback){
|
if(ks == Kback){
|
||||||
@@ -668,7 +648,7 @@ searchkey(u32int ks, u32int mod, Str *com)
|
|||||||
}
|
}
|
||||||
if(ks >= Kspec || (ks < ' ' && !(mod & Mctrl)) ||
|
if(ks >= Kspec || (ks < ' ' && !(mod & Mctrl)) ||
|
||||||
(mod & (Malt|Msuper))){
|
(mod & (Malt|Msuper))){
|
||||||
commitsearch(com);
|
flush(com);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if(mod & Mctrl){
|
if(mod & Mctrl){
|
||||||
@@ -678,11 +658,11 @@ searchkey(u32int ks, u32int mod, Str *com)
|
|||||||
startsearch(n, com);
|
startsearch(n, com);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
commitsearch(com);
|
flush(com);
|
||||||
return n != 0 || setlang(c);
|
return n != 0 || setlang(c);
|
||||||
}
|
}
|
||||||
if(search.raw.n >= Maxrunes){
|
if(search.raw.n >= Maxrunes){
|
||||||
commitsearch(com);
|
flush(com);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
sputr(&search.raw, ks);
|
sputr(&search.raw, ks);
|
||||||
@@ -715,6 +695,15 @@ transition(u32int ks, u32int mod, Str *com)
|
|||||||
reset();
|
reset();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
if(ks == ' ' && isjp(&im) && haspre(&im) && !(mod & ~Mshift)){
|
||||||
|
/* Space converts: it steps through the candidates, or
|
||||||
|
* commits a reading that has none. */
|
||||||
|
if(im.nkouho != 0)
|
||||||
|
cyclekouho(mod & Mshift ? -1 : 1);
|
||||||
|
else
|
||||||
|
flush(com);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
if(ks == Ktab || ks == Kret){
|
if(ks == Ktab || ks == Kret){
|
||||||
if(!haspre(&im))
|
if(!haspre(&im))
|
||||||
return 0;
|
return 0;
|
||||||
@@ -725,6 +714,10 @@ transition(u32int ks, u32int mod, Str *com)
|
|||||||
if(ks == Kback){
|
if(ks == Kback){
|
||||||
if(!haspre(&im))
|
if(!haspre(&im))
|
||||||
return 0;
|
return 0;
|
||||||
|
if(im.sel >= 0){
|
||||||
|
im.sel = -1; /* back from the candidate to the reading */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
im.l->back(&im);
|
im.l->back(&im);
|
||||||
if(!haspre(&im)){
|
if(!haspre(&im)){
|
||||||
reset();
|
reset();
|
||||||
@@ -739,12 +732,14 @@ transition(u32int ks, u32int mod, Str *com)
|
|||||||
if(ks == Kesc){
|
if(ks == Kesc){
|
||||||
if(!haspre(&im))
|
if(!haspre(&im))
|
||||||
return 0;
|
return 0;
|
||||||
reset();
|
if(im.sel >= 0)
|
||||||
|
im.sel = -1;
|
||||||
|
else
|
||||||
|
reset();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if(ks >= Kspec || (mod & (Malt|Msuper))){
|
if(ks >= Kspec || (mod & (Malt|Msuper))){
|
||||||
commit(com);
|
flush(com);
|
||||||
reset();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if(mod & Mctrl){
|
if(mod & Mctrl){
|
||||||
@@ -754,20 +749,18 @@ transition(u32int ks, u32int mod, Str *com)
|
|||||||
startsearch(n, com);
|
startsearch(n, com);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
commit(com);
|
flush(com);
|
||||||
reset();
|
|
||||||
return setlang(c);
|
return setlang(c);
|
||||||
}
|
}
|
||||||
if(ks == '0' && im.nkouho > 0){
|
if(ks == '0' && im.nkouho > 0){
|
||||||
commit(com);
|
im.sel = -1;
|
||||||
reset();
|
flush(com);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if(ks > 0x7f || ks == ' '){
|
if(ks > 0x7f || ks == ' '){
|
||||||
if(!haspre(&im))
|
if(!haspre(&im))
|
||||||
return 0;
|
return 0;
|
||||||
commit(com);
|
flush(com);
|
||||||
reset();
|
|
||||||
if(com->n >= Maxrunes)
|
if(com->n >= Maxrunes)
|
||||||
return 0;
|
return 0;
|
||||||
sputr(com, ks);
|
sputr(com, ks);
|
||||||
@@ -775,13 +768,15 @@ transition(u32int ks, u32int mod, Str *com)
|
|||||||
}
|
}
|
||||||
if(im.l->trans == nil)
|
if(im.l->trans == nil)
|
||||||
return 0;
|
return 0;
|
||||||
|
if(im.sel >= 0)
|
||||||
|
flush(com); /* typing on takes the chosen candidate */
|
||||||
if(im.pre.n >= Maxrunes ||
|
if(im.pre.n >= Maxrunes ||
|
||||||
(isjp(&im) && im.pre.n + im.raw.n >= Maxrunes)){
|
(isjp(&im) && im.pre.n + im.raw.n >= Maxrunes)){
|
||||||
/* A full reading commits; a pending romaji syllable stays. */
|
/* A full reading commits; a pending romaji syllable stays. */
|
||||||
if(isjp(&im))
|
if(isjp(&im))
|
||||||
sappend(com, &im.pre);
|
sappend(com, &im.pre);
|
||||||
else
|
else
|
||||||
commit(com);
|
commitim(&im, com);
|
||||||
sclear(&im.pre);
|
sclear(&im.pre);
|
||||||
clearkouho();
|
clearkouho();
|
||||||
}
|
}
|
||||||
@@ -798,7 +793,6 @@ init(void)
|
|||||||
memset(&caret, 0, sizeof caret);
|
memset(&caret, 0, sizeof caret);
|
||||||
activeowner = nil;
|
activeowner = nil;
|
||||||
activecap = 0;
|
activecap = 0;
|
||||||
candidatechosen = 0;
|
|
||||||
memset(&lastdraw, 0, sizeof lastdraw);
|
memset(&lastdraw, 0, sizeof lastdraw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -116,6 +116,9 @@ engine_backspace_clears_candidates(struct ct *t)
|
|||||||
im.nkouho = 1;
|
im.nkouho = 1;
|
||||||
im.sel = 0;
|
im.sel = 0;
|
||||||
CT_CHECK(t, keystroke(Kback, 0, &com));
|
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, "backspace commit", "", &com);
|
||||||
checkstr(t, "pending romaji after backspace", "n", &im.raw);
|
checkstr(t, "pending romaji after backspace", "n", &im.raw);
|
||||||
impre(&im, &shown);
|
impre(&im, &shown);
|
||||||
@@ -162,7 +165,7 @@ engine_candidate_shortcut_modifiers(struct ct *t)
|
|||||||
init();
|
init();
|
||||||
im.kouho[9] = mkstr("must-not-select");
|
im.kouho[9] = mkstr("must-not-select");
|
||||||
im.nkouho = 10;
|
im.nkouho = 10;
|
||||||
im.sel = 9;
|
im.sel = -1;
|
||||||
selected = im.kouho[9];
|
selected = im.kouho[9];
|
||||||
sclear(&com);
|
sclear(&com);
|
||||||
CT_CHECK(t, !keystroke('1', mods[i], &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);
|
CT_EQ_PTR(t, &owner, activeowner);
|
||||||
checkstr(t, "reset hands the reading back", "か", &res.commit);
|
checkstr(t, "reset hands the reading back", "か", &res.commit);
|
||||||
CT_EQ_INT(t, 0, res.preedit.n);
|
CT_EQ_INT(t, 0, res.preedit.n);
|
||||||
CT_CHECK(t, !caret.valid);
|
|
||||||
res = ownerrequest(&owner, Keypress, 'n', 0);
|
res = ownerrequest(&owner, Keypress, 'n', 0);
|
||||||
checkstr(t, "same owner after reset", "ん", &res.preedit);
|
checkstr(t, "same owner after reset", "ん", &res.preedit);
|
||||||
}
|
}
|
||||||
@@ -633,7 +635,7 @@ engine_language_switch_state(struct ct *t)
|
|||||||
if(steps[i].stale){
|
if(steps[i].stale){
|
||||||
im.kouho[0] = mkstr("stale");
|
im.kouho[0] = mkstr("stale");
|
||||||
im.nkouho = 1;
|
im.nkouho = 1;
|
||||||
im.sel = 0;
|
im.sel = -1;
|
||||||
}
|
}
|
||||||
sclear(&com);
|
sclear(&com);
|
||||||
eaten = keystroke(steps[i].key, steps[i].mod, &com);
|
eaten = keystroke(steps[i].key, steps[i].mod, &com);
|
||||||
@@ -693,7 +695,6 @@ struct Searchfix
|
|||||||
Trie *dict;
|
Trie *dict;
|
||||||
int activecap;
|
int activecap;
|
||||||
Drawcmd lastdraw;
|
Drawcmd lastdraw;
|
||||||
int candidatechosen;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -723,7 +724,6 @@ setcandidates(int n)
|
|||||||
im.kouho[i] = mkstr(name);
|
im.kouho[i] = mkstr(name);
|
||||||
}
|
}
|
||||||
im.nkouho = n;
|
im.nkouho = n;
|
||||||
selectfirst();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -873,6 +873,7 @@ engine_candidate_completion(struct ct *t)
|
|||||||
im.pre = mkstr("reading");
|
im.pre = mkstr("reading");
|
||||||
sclear(&com);
|
sclear(&com);
|
||||||
CT_CHECK(t, keystroke(Kdown, 0, &com));
|
CT_CHECK(t, keystroke(Kdown, 0, &com));
|
||||||
|
CT_CHECK(t, keystroke(Kdown, 0, &com));
|
||||||
CT_CHECK(t, keystroke(Kret, 0, &com));
|
CT_CHECK(t, keystroke(Kret, 0, &com));
|
||||||
checkstr(t, "explicit candidate", "c2", &com);
|
checkstr(t, "explicit candidate", "c2", &com);
|
||||||
|
|
||||||
@@ -888,13 +889,14 @@ engine_candidate_completion(struct ct *t)
|
|||||||
CT_CHECK(t, keystroke(Kret, 0, &com));
|
CT_CHECK(t, keystroke(Kret, 0, &com));
|
||||||
checkstr(t, "Enter without candidates", "reading", &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);
|
candidatebegin(32);
|
||||||
im.pre = mkstr("reading");
|
im.pre = mkstr("reading");
|
||||||
im.sel = 27;
|
im.sel = 27;
|
||||||
sclear(&com);
|
sclear(&com);
|
||||||
CT_CHECK(t, !keystroke('9', 0, &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);
|
CT_EQ_INT(t, 0, im.nkouho);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -913,7 +915,6 @@ searchsave(Searchfix *f, int lang)
|
|||||||
f->dict = f->dictlang->dict;
|
f->dict = f->dictlang->dict;
|
||||||
f->activecap = activecap;
|
f->activecap = activecap;
|
||||||
f->lastdraw = lastdraw;
|
f->lastdraw = lastdraw;
|
||||||
f->candidatechosen = candidatechosen;
|
|
||||||
draindraw(nil);
|
draindraw(nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -956,7 +957,6 @@ searchend(Searchfix *f)
|
|||||||
search = f->search;
|
search = f->search;
|
||||||
activecap = f->activecap;
|
activecap = f->activecap;
|
||||||
lastdraw = f->lastdraw;
|
lastdraw = f->lastdraw;
|
||||||
candidatechosen = f->candidatechosen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -982,7 +982,7 @@ engine_popup_preedit_capability(struct ct *t)
|
|||||||
if(CT_CHECK(t, draindraw(&dc) > 0)){
|
if(CT_CHECK(t, draindraw(&dc) > 0)){
|
||||||
CT_EQ_INT(t, 0, dc.pre.n);
|
CT_EQ_INT(t, 0, dc.pre.n);
|
||||||
CT_EQ_INT(t, 1, dc.nkouho);
|
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]);
|
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)){
|
if(CT_CHECK(t, draindraw(&dc) > 0)){
|
||||||
checkstr(t, "popup preedit", "か", &dc.pre);
|
checkstr(t, "popup preedit", "か", &dc.pre);
|
||||||
CT_EQ_INT(t, 1, dc.nkouho);
|
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]);
|
checkstr(t, "popup candidate", "家", &dc.kouho[0]);
|
||||||
}
|
}
|
||||||
CT_EQ_INT(t, 1, im.nkouho);
|
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]);
|
checkstr(t, "retained popup candidate", "家", &im.kouho[0]);
|
||||||
|
|
||||||
kres = ownerrequestcap(&client, 0, Keycap, 0, 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)){
|
if(CT_CHECK(t, draindraw(&dc) > 0)){
|
||||||
CT_EQ_INT(t, 0, dc.pre.n);
|
CT_EQ_INT(t, 0, dc.pre.n);
|
||||||
CT_EQ_INT(t, 1, dc.nkouho);
|
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]);
|
checkstr(t, "restored client candidate", "家", &dc.kouho[0]);
|
||||||
}
|
}
|
||||||
CT_EQ_INT(t, 1, im.nkouho);
|
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]);
|
checkstr(t, "retained client candidate", "家", &im.kouho[0]);
|
||||||
kres = ownerrequestcap(&client, Cclientpreedit, Keycap, 0, 0);
|
kres = ownerrequestcap(&client, Cclientpreedit, Keycap, 0, 0);
|
||||||
CT_CHECK(t, kres.eaten);
|
CT_CHECK(t, kres.eaten);
|
||||||
@@ -1116,14 +1116,64 @@ engine_japanese_candidates(struct ct *t)
|
|||||||
checkstr(t, "complete Japanese reading", "かんじ", &shown);
|
checkstr(t, "complete Japanese reading", "かんじ", &shown);
|
||||||
if(!CT_EQ_INT(t, 2, im.nkouho))
|
if(!CT_EQ_INT(t, 2, im.nkouho))
|
||||||
goto cleanup;
|
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 one", "漢字", &im.kouho[0]);
|
||||||
checkstr(t, "candidate two", "幹事", &im.kouho[1]);
|
checkstr(t, "candidate two", "幹事", &im.kouho[1]);
|
||||||
CT_CHECK(t, keystroke(Kdown, 0, &com));
|
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_EQ_INT(t, 1, im.sel);
|
||||||
CT_CHECK(t, keystroke(Kret, 0, &com));
|
CT_CHECK(t, keystroke(Kret, 0, &com));
|
||||||
checkstr(t, "selected Kanji", "幹事", &com);
|
checkstr(t, "selected Kanji", "幹事", &com);
|
||||||
CT_EQ_INT(t, 0, im.nkouho);
|
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. */
|
/* Backspace looks a complete shorter reading up again. */
|
||||||
setdict(jp->dict, "かん", "缶");
|
setdict(jp->dict, "かん", "缶");
|
||||||
if(!typekeys(t, "kanji", &com))
|
if(!typekeys(t, "kanji", &com))
|
||||||
@@ -1179,8 +1229,8 @@ engine_japanese_backspace_and_boundaries(struct ct *t)
|
|||||||
im.l = getlang(LangJP);
|
im.l = getlang(LangJP);
|
||||||
sclear(&com);
|
sclear(&com);
|
||||||
if(typekeys(t, "kanji", &com)){
|
if(typekeys(t, "kanji", &com)){
|
||||||
CT_CHECK(t, keystroke(' ', 0, &com));
|
CT_CHECK(t, keystroke(L'日', 0, &com));
|
||||||
checkstr(t, "real input boundary", "かんじ ", &com);
|
checkstr(t, "real input boundary", "かんじ日", &com);
|
||||||
}
|
}
|
||||||
|
|
||||||
init();
|
init();
|
||||||
@@ -1960,7 +2010,7 @@ engine_full_boundary_passthrough(struct ct *t)
|
|||||||
im.pre.r[i] = L'あ';
|
im.pre.r[i] = L'あ';
|
||||||
im.pre.n = Maxrunes;
|
im.pre.n = Maxrunes;
|
||||||
sclear(&com);
|
sclear(&com);
|
||||||
CT_CHECK(t, !keystroke(' ', 0, &com));
|
CT_CHECK(t, !keystroke(L'日', 0, &com));
|
||||||
CT_EQ_INT(t, Maxrunes, com.n);
|
CT_EQ_INT(t, Maxrunes, com.n);
|
||||||
for(i = 0; i < Maxrunes; i++)
|
for(i = 0; i < Maxrunes; i++)
|
||||||
CT_EQ_UINT(t, L'あ', com.r[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.r[i] = L'あ';
|
||||||
im.pre.n = Maxrunes-1;
|
im.pre.n = Maxrunes-1;
|
||||||
sclear(&com);
|
sclear(&com);
|
||||||
CT_CHECK(t, keystroke(' ', 0, &com));
|
CT_CHECK(t, keystroke(L'日', 0, &com));
|
||||||
CT_EQ_INT(t, Maxrunes, com.n);
|
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. */
|
/* Typing on at the limit commits the kana and keeps the syllable. */
|
||||||
init();
|
init();
|
||||||
|
|||||||
Reference in New Issue
Block a user