hanja: separate temporary search mode

This commit is contained in:
2026-08-12 21:23:10 +09:00
parent 4e1c15dde4
commit 136695a900
6 changed files with 216 additions and 195 deletions

View File

@@ -29,7 +29,7 @@ Ctrl+S Korean Hangul
Ctrl+T English passthrough
Ctrl+V Vietnamese Telex compatibility mode
Ctrl+E Emoji and symbol search
Ctrl+H One-shot Hanja search (from Korean mode)
Ctrl+H One-shot Hanja search
Ctrl+P Toggle popup preedit
```
@@ -47,12 +47,13 @@ English aliases or the active language's input rules, including Japanese
Ctrl+E → smile → Enter → 😀
```
Hanja search is available only from Korean mode and returns to Korean mode
after one conversion. Press Ctrl+H, type exactly one Hangul syllable with
the normal 2-beolsik Shift and Caps Lock behavior, then select with Up, Down,
Tab, Enter, or `1`-`9`. Escape cancels the search; when there is no match,
Enter commits the Hangul reading. It does not convert words or text already
surrounding the cursor.
Hanja search is temporary and returns to the active language after one
conversion. Press Ctrl+H and type with that language's normal input rules,
then select with Up, Down, Tab, Enter, or `1`-`9`. The bundled dictionary
currently indexes exactly one modern Hangul syllable. Incomplete jamo,
multiple syllables, and other languages therefore have no candidates; Enter
commits the displayed reading unchanged. Escape cancels the search. It does
not convert words or text already surrounding the cursor.
## Build and test

1
dat.h
View File

@@ -13,6 +13,7 @@ enum
LangJP = 0x0e,
LangJPK = 0x0b,
LangKO = 0x13,
LangHANJA = 0x08,
LangEMOJI = 0x05,
LangVI = 0x16,

View File

@@ -16,20 +16,12 @@ static int maplookup(Trie*, Str*, Str*);
typedef struct Search Search;
struct Search
{
int kind;
int lang;
Str raw;
Str text;
};
static Search search;
enum
{
SearchOff,
SearchEmoji,
SearchHanja,
Hanjakey = 0x08,
};
uvlong
ownernew(void)
{
@@ -47,7 +39,8 @@ Lang langs[] = {
{LangEN, nil, nil, nil, nil, nil, nil, nil},
{LangJP, "hira", "kanji", transmap, backjp, dictqjp, nil, nil},
{LangJPK, "kata", nil, transmap, backjp, dictqjp, nil, nil},
{LangKO, nil, "hanja", transko, backko, nil, nil, nil},
{LangKO, nil, nil, transko, backko, nil, nil, nil},
{LangHANJA, nil, "hanja", nil, nil, nil, nil, nil},
{LangEMOJI, nil, "emoji", nil, nil, nil, nil, nil},
{LangVI, "telex", nil, transvi, backvi, dictqmap, nil, nil},
};
@@ -123,12 +116,12 @@ show(void)
int i, first, n;
sclear(&dc.pre);
if(search.kind)
if(search.lang)
pre = search.text;
else
impre(&pre);
if(popup){
if(search.kind || isjp(&im) || im.l->map == nil ||
if(search.lang || isjp(&im) || im.l->map == nil ||
!mapget(im.l->map, &pre, &dc.pre))
dc.pre = pre;
}
@@ -154,7 +147,7 @@ reset(void)
{
sclear(&im.pre);
sclear(&im.raw);
search.kind = SearchOff;
search.lang = 0;
sclear(&search.raw);
sclear(&search.text);
memset(&caret, 0, sizeof caret);
@@ -511,38 +504,39 @@ hanjaquery(void)
static Dictres res;
Str key;
transstr(getlang(LangKO), &search.raw, &key);
transstr(im.l, &search.raw, &key);
search.text = key;
searchlookup(LangKO, &key, &res);
setkouho(&res);
if(key.n == 1 && key.r[0] >= 0xac00 && key.r[0] <= 0xd7a3){
searchlookup(LangHANJA, &key, &res);
setkouho(&res);
}else
clearkouho();
show();
}
static void
searchquery(void)
{
if(search.kind == SearchEmoji)
if(search.lang == LangEMOJI)
emojiquery();
else if(search.kind == SearchHanja)
else if(search.lang == LangHANJA)
hanjaquery();
}
static int
searchkind(Rune c, u32int mod)
searchlang(Rune c, u32int mod)
{
if(c == LangEMOJI)
return SearchEmoji;
if(mod & (Malt|Msuper))
return SearchOff;
if(c == Hanjakey && im.l->lang == LangKO)
return SearchHanja;
return SearchOff;
return 0;
if(c == LangEMOJI || c == LangHANJA)
return c;
return 0;
}
static void
endsearch(void)
{
search.kind = SearchOff;
search.lang = 0;
sclear(&search.raw);
sclear(&search.text);
clearkouho();
@@ -550,14 +544,14 @@ endsearch(void)
}
static void
startsearch(int kind, Str *com)
startsearch(int lang, Str *com)
{
if(haspre(&im))
commit(com);
sclear(&im.pre);
sclear(&im.raw);
clearkouho();
search.kind = kind;
search.lang = lang;
sclear(&search.raw);
sclear(&search.text);
show();
@@ -636,11 +630,16 @@ searchkey(u32int ks, u32int mod, Str *com)
endsearch();
return 1;
}
if(ks >= Kspec || (ks < ' ' && !(mod & Mctrl)) ||
(mod & (Malt|Msuper))){
commitsearch(com);
return 0;
}
if(mod & Mctrl){
c = ctrlkey(ks);
n = searchkind(c, mod);
if(n != SearchOff){
if(n == search.kind)
n = searchlang(c, mod);
if(n != 0){
if(n == search.lang)
endsearch();
else
startsearch(n, com);
@@ -656,15 +655,11 @@ searchkey(u32int ks, u32int mod, Str *com)
return 1;
return 0;
}
if(ks >= Kspec || ks < ' ' || (mod & (Malt|Msuper))){
commitsearch(com);
return 0;
}
if(search.raw.n >= Maxrunes){
commitsearch(com);
return 0;
}
if(search.kind == SearchHanja)
if(im.l->lang == LangKO)
ks = kokey(ks, mod);
sputr(&search.raw, ks);
searchquery();
@@ -679,7 +674,7 @@ keystroke(u32int ks, u32int mod, Str *com)
if(ismodkey(ks))
return 0;
if(search.kind)
if(search.lang)
return searchkey(ks, mod, com);
if(ks == Kdown || ks == Kup){
if(im.nkouho == 0)
@@ -738,8 +733,8 @@ keystroke(u32int ks, u32int mod, Str *com)
}
if(mod & Mctrl){
c = ctrlkey(ks);
n = searchkind(c, mod);
if(n != SearchOff){
n = searchlang(c, mod);
if(n != 0){
startsearch(n, com);
return 1;
}
@@ -844,7 +839,7 @@ imhandlekey(Keyreq *kr)
break;
}
if(kr->want && kr->owner == activeowner){
if(search.kind)
if(search.lang)
res.preedit = search.text;
else
impre(&res.preedit);
@@ -858,7 +853,7 @@ dictresult(Dictres *res)
Str pre;
impre(&pre);
if(search.kind || res->lang != im.l->lang ||
if(search.lang || res->lang != im.l->lang ||
scmp(&res->key, &pre) != 0)
return;
setkouho(res);

View File

@@ -421,15 +421,17 @@ engine_direct_language_modes(struct ct *t)
CT_EQ_INT(t, 0, im.pre.n);
CT_EQ_INT(t, 0, im.raw.n);
CT_CHECK(t, keystroke('e', Mctrl, &com));
CT_CHECK(t, search.kind);
CT_CHECK(t, search.lang);
CT_EQ_INT(t, LangEN, im.l->lang);
CT_CHECK(t, keystroke(Kesc, 0, &com));
CT_CHECK(t, !search.kind);
CT_CHECK(t, !search.lang);
CT_CHECK(t, keystroke('s', Mctrl, &com));
CT_EQ_INT(t, LangKO, im.l->lang);
CT_EQ_PTR(t, nil, im.l->mapname);
CT_EQ_PTR(t, nil, im.l->map);
CT_EQ_PTR(t, nil, im.l->dictname);
CT_EQ_PTR(t, nil, im.l->dictq);
CT_CHECK(t, strcmp(getlang(LangHANJA)->dictname, "hanja") == 0);
CT_CHECK(t, keystroke('r', 0, &com));
checkstr(t, "Korean without map", "", &im.pre);
CT_CHECK(t, keystroke(Kback, 0, &com));
@@ -509,11 +511,12 @@ engine_language_switch_state(struct ct *t)
vi->map = saved;
}
typedef struct Emojifix Emojifix;
struct Emojifix
typedef struct Searchfix Searchfix;
struct Searchfix
{
Im im;
Search search;
Lang *dictlang;
Hmap *dict;
int popup;
int visible;
@@ -544,33 +547,37 @@ setdict(Hmap **dict, char *key, char *val)
}
static void
emojibegin(Emojifix *f, int showpre)
searchsave(Searchfix *f, int lang)
{
Lang *l;
l = getlang(LangEMOJI);
f->im = im;
f->search = search;
f->dict = l->dict;
f->dictlang = getlang(lang);
f->dict = f->dictlang->dict;
f->popup = popup;
f->visible = visible;
draindraw(nil);
l->dict = hmapalloc(32);
setdict(&l->dict, "a", "A B");
setdict(&l->dict, "", "B C");
setdict(&l->dict, "alpha", "α");
setdict(&l->dict, "smil", "😀 😄");
setdict(&l->dict, "smile", "😀 😄");
setdict(&l->dict, "웃음", "😀 😄 😂");
setdict(&l->dict, "えがお", "😀 😄 😊");
setdict(&l->dict, "エガオ", "😀 😄 😊");
setdict(&l->dict, "heart", "❤️");
setdict(&l->dict, "coffee", "☕️");
setdict(&l->dict, "^", "¹ ² ³ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹ ⁽");
setdict(&l->dict, "^0", "");
setdict(&l->dict, "_", "₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉ ₍");
setdict(&l->dict, "<", "← ≤ ♥ ≠");
setdict(&l->dict, "many",
}
static void
emojibegin(Searchfix *f, int showpre)
{
searchsave(f, LangEMOJI);
f->dictlang->dict = hmapalloc(32);
setdict(&f->dictlang->dict, "a", "A B");
setdict(&f->dictlang->dict, "", "B C");
setdict(&f->dictlang->dict, "alpha", "α");
setdict(&f->dictlang->dict, "smil", "😀 😄");
setdict(&f->dictlang->dict, "smile", "😀 😄");
setdict(&f->dictlang->dict, "웃음", "😀 😄 😂");
setdict(&f->dictlang->dict, "えがお", "😀 😄 😊");
setdict(&f->dictlang->dict, "エガオ", "😀 😄 😊");
setdict(&f->dictlang->dict, "heart", "❤️");
setdict(&f->dictlang->dict, "coffee", "☕️");
setdict(&f->dictlang->dict, "^", "¹ ² ³ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹ ⁽");
setdict(&f->dictlang->dict, "^0", "");
setdict(&f->dictlang->dict, "_", "₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉ ₍");
setdict(&f->dictlang->dict, "<", "← ≤ ♥ ≠");
setdict(&f->dictlang->dict, "many",
"c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12");
init();
im.l = getlang(LangKO);
@@ -578,14 +585,12 @@ emojibegin(Emojifix *f, int showpre)
}
static void
emojiend(Emojifix *f)
searchend(Searchfix *f)
{
Lang *l;
Hmap *dict;
l = getlang(LangEMOJI);
dict = l->dict;
l->dict = f->dict;
dict = f->dictlang->dict;
f->dictlang->dict = f->dict;
hmapfree(dict);
draindraw(nil);
im = f->im;
@@ -594,50 +599,18 @@ emojiend(Emojifix *f)
visible = f->visible;
}
typedef struct Hanjafix Hanjafix;
struct Hanjafix
{
Im im;
Search search;
Hmap *dict;
int popup;
int visible;
};
static void
hanjabegin(Hanjafix *f)
hanjabegin(Searchfix *f, int lang)
{
Lang *l;
l = getlang(LangKO);
f->im = im;
f->search = search;
f->dict = l->dict;
f->popup = popup;
f->visible = visible;
draindraw(nil);
l->dict = hmapalloc(8);
setdict(&l->dict, "", "漢 韓");
setdict(&l->dict, "", "");
searchsave(f, LangHANJA);
f->dictlang->dict = hmapalloc(8);
setdict(&f->dictlang->dict, "", "漢 韓");
setdict(&f->dictlang->dict, "", "");
setdict(&f->dictlang->dict, "", "");
setdict(&f->dictlang->dict, "한글", "");
setdict(&f->dictlang->dict, "", "");
init();
im.l = l;
}
static void
hanjaend(Hanjafix *f)
{
Lang *l;
Hmap *dict;
l = getlang(LangKO);
dict = l->dict;
l->dict = f->dict;
hmapfree(dict);
draindraw(nil);
im = f->im;
search = f->search;
popup = f->popup;
visible = f->visible;
im.l = getlang(lang);
}
static int
@@ -817,7 +790,7 @@ void
engine_emoji_single_candidate(struct ct *t)
{
Drawcmd dc = {0};
Emojifix f;
Searchfix f;
Str com;
emojibegin(&f, 1);
@@ -825,12 +798,12 @@ engine_emoji_single_candidate(struct ct *t)
CT_CHECK(t, keystroke('p', Mctrl, &com));
CT_EQ_INT(t, 0, popup);
CT_CHECK(t, keystroke('e', Mctrl, &com));
CT_CHECK(t, search.kind);
CT_CHECK(t, search.lang);
CT_EQ_INT(t, LangKO, im.l->lang);
if(typekeys(t, "alpha", &com)){
checkstr(t, "no automatic commit", "", &com);
checkstr(t, "raw English query", "alpha", &search.text);
CT_CHECK(t, search.kind);
CT_CHECK(t, search.lang);
CT_EQ_INT(t, 1, im.nkouho);
checkstr(t, "single candidate", "α", &im.kouho[0]);
CT_CHECK(t, draindraw(&dc) > 0);
@@ -838,21 +811,21 @@ engine_emoji_single_candidate(struct ct *t)
CT_EQ_INT(t, 1, dc.nkouho);
CT_CHECK(t, keystroke(Kret, 0, &com));
checkstr(t, "explicit candidate commit", "α", &com);
CT_CHECK(t, !search.kind);
CT_CHECK(t, !search.lang);
CT_EQ_INT(t, LangKO, im.l->lang);
show();
CT_CHECK(t, draindraw(&dc) > 0);
CT_EQ_INT(t, 0, dc.pre.n);
CT_EQ_INT(t, 0, dc.nkouho);
}
emojiend(&f);
searchend(&f);
}
void
engine_emoji_queries(struct ct *t)
{
Drawcmd dc = {0};
Emojifix f;
Searchfix f;
Str com;
emojibegin(&f, 1);
@@ -900,16 +873,16 @@ engine_emoji_queries(struct ct *t)
CT_EQ_INT(t, 3, dc.nkouho);
CT_CHECK(t, keystroke(Kesc, 0, &com));
checkstr(t, "cancel commit", "", &com);
CT_CHECK(t, !search.kind);
CT_CHECK(t, !search.lang);
CT_EQ_INT(t, LangKO, im.l->lang);
}
emojiend(&f);
searchend(&f);
}
void
engine_emoji_japanese_and_multirune(struct ct *t)
{
Emojifix f;
Searchfix f;
Str com;
emojibegin(&f, 0);
@@ -950,7 +923,7 @@ engine_emoji_japanese_and_multirune(struct ct *t)
CT_CHECK(t, keystroke(Kret, 0, &com));
checkstr(t, "multi-codepoint emoji", "☕️", &com);
}
emojiend(&f);
searchend(&f);
}
void
@@ -966,7 +939,7 @@ engine_emoji_digit_aliases(struct ct *t)
{ "_2", '_', '2', "" },
{ "<3", '<', '3', "" },
};
Emojifix f;
Searchfix f;
Str com;
int i;
@@ -978,7 +951,7 @@ engine_emoji_digit_aliases(struct ct *t)
CT_CHECK(t, im.nkouho >= cases[i].digit - '0');
CT_CHECK(t, keystroke(cases[i].digit, 0, &com));
checkstr(t, cases[i].name, cases[i].want, &com);
CT_CHECK(t, !search.kind);
CT_CHECK(t, !search.lang);
CT_EQ_INT(t, LangKO, im.l->lang);
}
@@ -998,19 +971,19 @@ engine_emoji_digit_aliases(struct ct *t)
CT_CHECK(t, keystroke('9', 0, &com));
checkstr(t, "missing number query", "smile9", &search.text);
checkstr(t, "missing number commit", "", &com);
CT_CHECK(t, search.kind);
CT_CHECK(t, search.lang);
CT_EQ_INT(t, 0, im.nkouho);
CT_CHECK(t, keystroke(Kret, 0, &com));
checkstr(t, "missing number text", "smile9", &com);
}
emojiend(&f);
searchend(&f);
}
void
engine_emoji_navigation(struct ct *t)
{
Drawcmd dc = {0};
Emojifix f;
Searchfix f;
Str com;
int i;
@@ -1054,13 +1027,13 @@ engine_emoji_navigation(struct ct *t)
CT_CHECK(t, keystroke(Kret, 0, &com));
checkstr(t, "navigated candidate", "😄", &com);
}
emojiend(&f);
searchend(&f);
}
void
engine_emoji_preedit_languages(struct ct *t)
{
Emojifix f;
Searchfix f;
Str com, shown;
int p;
@@ -1074,26 +1047,26 @@ engine_emoji_preedit_languages(struct ct *t)
checkstr(t, "modifier preserves Japanese", "", &shown);
CT_CHECK(t, keystroke('E', Mctrl|Mshift, &com));
checkstr(t, "committed Japanese preedit", "", &com);
CT_CHECK(t, search.kind);
CT_CHECK(t, search.lang);
CT_EQ_INT(t, LangJP, im.l->lang);
CT_CHECK(t, keystroke('E', Mctrl|Malt, &com));
CT_EQ_INT(t, SearchOff, search.kind);
CT_CHECK(t, !keystroke('E', Mctrl|Malt, &com));
CT_EQ_INT(t, 0, search.lang);
CT_CHECK(t, keystroke('E', Mctrl|Mshift, &com));
CT_CHECK(t, keystroke('E', Mctrl|Msuper, &com));
CT_EQ_INT(t, SearchOff, search.kind);
CT_CHECK(t, !keystroke('E', Mctrl|Msuper, &com));
CT_EQ_INT(t, 0, search.lang);
CT_CHECK(t, keystroke('E', Mctrl|Mshift, &com));
CT_EQ_INT(t, LangJP, im.l->lang);
CT_CHECK(t, keystroke('a', 0, &com));
p = popup;
CT_CHECK(t, !keystroke(Kmodfirst+2, 0, &com));
CT_CHECK(t, search.kind);
CT_CHECK(t, search.lang);
checkstr(t, "modifier preserves search", "a", &search.text);
CT_CHECK(t, keystroke('P', Mctrl|Mshift, &com));
CT_EQ_INT(t, !p, popup);
CT_CHECK(t, search.kind);
CT_CHECK(t, search.lang);
CT_CHECK(t, !keystroke(Kmodfirst+2, 0, &com));
CT_CHECK(t, keystroke('E', Mctrl|Mshift, &com));
CT_CHECK(t, !search.kind);
CT_CHECK(t, !search.lang);
sclear(&com);
if(typekeys(t, "na", &com)){
shown = shownpre(&im);
@@ -1123,7 +1096,7 @@ engine_emoji_preedit_languages(struct ct *t)
CT_CHECK(t, keystroke('e', Mctrl, &com));
checkstr(t, "committed Telex preedit", "á", &com);
CT_CHECK(t, keystroke(Kesc, 0, &com));
CT_CHECK(t, !search.kind);
CT_CHECK(t, !search.lang);
CT_EQ_PTR(t, &testvi, im.l);
sclear(&com);
if(typekeys(t, "as", &com)){
@@ -1132,13 +1105,13 @@ engine_emoji_preedit_languages(struct ct *t)
checkstr(t, "Telex raw resumed", "as", &im.raw);
}
}
emojiend(&f);
searchend(&f);
}
void
engine_emoji_start_and_unknown(struct ct *t)
{
Emojifix f;
Searchfix f;
Str com;
char want[Maxrunes+1];
int i;
@@ -1148,14 +1121,14 @@ engine_emoji_start_and_unknown(struct ct *t)
if(typekeys(t, "dkssud", &com)){
CT_CHECK(t, keystroke('e', Mctrl, &com));
checkstr(t, "committed Korean preedit", "안녕", &com);
CT_CHECK(t, search.kind);
CT_CHECK(t, search.lang);
CT_EQ_INT(t, LangKO, im.l->lang);
if(typekeys(t, "xyz", &com)){
checkstr(t, "unknown displayed query", "xyz", &search.text);
CT_EQ_INT(t, 0, im.nkouho);
CT_CHECK(t, keystroke(Kret, 0, &com));
checkstr(t, "unknown query commit", "안녕xyz", &com);
CT_CHECK(t, !search.kind);
CT_CHECK(t, !search.lang);
CT_EQ_INT(t, LangKO, im.l->lang);
}
}
@@ -1165,7 +1138,7 @@ engine_emoji_start_and_unknown(struct ct *t)
if(typekeys(t, "xyz", &com)){
CT_CHECK(t, !keystroke(Kspec|0x51, 0, &com));
checkstr(t, "special commits shown query", "xyz", &com);
CT_CHECK(t, !search.kind);
CT_CHECK(t, !search.lang);
CT_EQ_INT(t, LangKO, im.l->lang);
}
@@ -1174,20 +1147,20 @@ engine_emoji_start_and_unknown(struct ct *t)
for(i = 0; i < Maxrunes; i++)
CT_CHECK(t, keystroke('q', 0, &com));
CT_EQ_INT(t, Maxrunes, search.raw.n);
CT_CHECK(t, search.kind);
CT_CHECK(t, search.lang);
CT_CHECK(t, !keystroke('z', 0, &com));
memset(want, 'q', Maxrunes);
want[Maxrunes] = '\0';
checkstr(t, "bounded query commit", want, &com);
CT_CHECK(t, !search.kind);
emojiend(&f);
CT_CHECK(t, !search.lang);
searchend(&f);
}
void
engine_emoji_dictionary_identity(struct ct *t)
{
Dictres res;
Emojifix f;
Searchfix f;
emojibegin(&f, 0);
im.pre = mkstr("same");
@@ -1210,31 +1183,31 @@ engine_emoji_dictionary_identity(struct ct *t)
checkstr(t, "wrong preedit ignored", "old", &im.kouho[0]);
res.key = im.pre;
search.kind = SearchEmoji;
search.lang = LangEMOJI;
dictresult(&res);
CT_EQ_INT(t, 1, im.nkouho);
checkstr(t, "search response ignored", "old", &im.kouho[0]);
search.kind = SearchOff;
search.lang = 0;
res.kouho[0] = mkstr("right");
dictresult(&res);
CT_EQ_INT(t, 1, im.nkouho);
CT_EQ_INT(t, -1, im.sel);
checkstr(t, "matching response accepted", "right", &im.kouho[0]);
emojiend(&f);
searchend(&f);
}
void
engine_hanja_search(struct ct *t)
{
Hanjafix f;
Searchfix f;
Str com;
hanjabegin(&f);
hanjabegin(&f, LangKO);
sclear(&com);
if(!CT_CHECK(t, keystroke('h', Mctrl, &com)))
goto cleanup;
CT_EQ_INT(t, SearchHanja, search.kind);
CT_EQ_INT(t, LangHANJA, search.lang);
CT_EQ_INT(t, LangKO, im.l->lang);
if(!typekeys(t, "gks", &com))
goto cleanup;
@@ -1244,19 +1217,19 @@ engine_hanja_search(struct ct *t)
CT_CHECK(t, keystroke(Kdown, 0, &com));
CT_CHECK(t, keystroke(Kret, 0, &com));
checkstr(t, "navigated Hanja", "", &com);
CT_EQ_INT(t, SearchOff, search.kind);
CT_EQ_INT(t, 0, search.lang);
CT_EQ_INT(t, LangKO, im.l->lang);
cleanup:
hanjaend(&f);
searchend(&f);
}
void
engine_hanja_unknown_and_cancel(struct ct *t)
{
Hanjafix f;
Searchfix f;
Str com;
hanjabegin(&f);
hanjabegin(&f, LangKO);
sclear(&com);
if(!CT_CHECK(t, keystroke('h', Mctrl, &com)))
goto cleanup;
@@ -1266,9 +1239,29 @@ engine_hanja_unknown_and_cancel(struct ct *t)
CT_EQ_INT(t, 0, im.nkouho);
CT_CHECK(t, keystroke(Kret, 0, &com));
checkstr(t, "unknown Hanja commit", "", &com);
CT_EQ_INT(t, SearchOff, search.kind);
CT_EQ_INT(t, 0, search.lang);
CT_EQ_INT(t, LangKO, im.l->lang);
sclear(&com);
if(!CT_CHECK(t, keystroke('h', Mctrl, &com)))
goto cleanup;
if(!typekeys(t, "r", &com))
goto cleanup;
checkstr(t, "incomplete Hanja reading", "", &search.text);
CT_EQ_INT(t, 0, im.nkouho);
CT_CHECK(t, keystroke(Kret, 0, &com));
checkstr(t, "incomplete Hanja commit", "", &com);
sclear(&com);
if(!CT_CHECK(t, keystroke('h', Mctrl, &com)))
goto cleanup;
if(!typekeys(t, "gksrmf", &com))
goto cleanup;
checkstr(t, "multiple Hanja syllables", "한글", &search.text);
CT_EQ_INT(t, 0, im.nkouho);
CT_CHECK(t, keystroke(Kret, 0, &com));
checkstr(t, "multiple Hanja syllable commit", "한글", &com);
sclear(&com);
if(!CT_CHECK(t, keystroke('h', Mctrl, &com)))
goto cleanup;
@@ -1277,25 +1270,25 @@ engine_hanja_unknown_and_cancel(struct ct *t)
CT_EQ_INT(t, 2, im.nkouho);
CT_CHECK(t, keystroke(Kesc, 0, &com));
checkstr(t, "cancelled Hanja", "", &com);
CT_EQ_INT(t, SearchOff, search.kind);
CT_EQ_INT(t, 0, search.lang);
CT_EQ_INT(t, LangKO, im.l->lang);
sclear(&com);
CT_CHECK(t, keystroke('h', Mctrl, &com));
CT_EQ_INT(t, SearchHanja, search.kind);
CT_EQ_INT(t, LangHANJA, search.lang);
CT_CHECK(t, keystroke('h', Mctrl, &com));
CT_EQ_INT(t, SearchOff, search.kind);
CT_EQ_INT(t, 0, search.lang);
cleanup:
hanjaend(&f);
searchend(&f);
}
void
engine_hanja_korean_keys(struct ct *t)
{
Hanjafix f;
Searchfix f;
Str com;
hanjabegin(&f);
hanjabegin(&f, LangKO);
sclear(&com);
CT_CHECK(t, keystroke('h', Mctrl, &com));
CT_CHECK(t, keystroke('r', Mshift, &com));
@@ -1309,38 +1302,69 @@ engine_hanja_korean_keys(struct ct *t)
checkstr(t, "Caps Lock Hanja reading", "", &search.text);
CT_EQ_INT(t, 1, im.nkouho);
CT_CHECK(t, keystroke(Kesc, 0, &com));
hanjaend(&f);
searchend(&f);
}
void
engine_hanja_korean_only(struct ct *t)
engine_hanja_input_languages(struct ct *t)
{
Hmap *dict;
Lang *l;
Str com, shown;
Searchfix f;
Str com;
hanjabegin(&f, LangEN);
sclear(&com);
if(!CT_CHECK(t, keystroke('h', Mctrl, &com)))
goto cleanup;
if(!typekeys(t, "gks", &com))
goto cleanup;
checkstr(t, "English Hanja input", "gks", &search.text);
CT_EQ_INT(t, 0, im.nkouho);
CT_EQ_INT(t, LangEN, im.l->lang);
CT_CHECK(t, keystroke(Kret, 0, &com));
checkstr(t, "English Hanja commit", "gks", &com);
CT_EQ_INT(t, LangEN, im.l->lang);
init();
im.l = getlang(LangJP);
sclear(&com);
if(typekeys(t, "ka", &com)){
CT_CHECK(t, !keystroke('h', Mctrl, &com));
CT_CHECK(t, !search.kind);
CT_EQ_INT(t, LangJP, im.l->lang);
shown = shownpre(&im);
checkstr(t, "non-Korean Ctrl-H reset", "", &shown);
checkstr(t, "non-Korean Ctrl-H commit", "", &com);
}
if(!CT_CHECK(t, keystroke('h', Mctrl, &com)))
goto cleanup;
if(!typekeys(t, "ka", &com))
goto cleanup;
checkstr(t, "Japanese Hanja input", "", &search.text);
CT_EQ_INT(t, 0, im.nkouho);
CT_EQ_INT(t, LangJP, im.l->lang);
CT_CHECK(t, keystroke(Kret, 0, &com));
checkstr(t, "Japanese Hanja commit", "", &com);
CT_EQ_INT(t, LangJP, im.l->lang);
l = getlang(LangKO);
dict = l->dict;
l->dict = nil;
init();
im.l = l;
im.l = getlang(LangEN);
sclear(&com);
CT_CHECK(t, keystroke('h', Mctrl, &com));
CT_EQ_INT(t, SearchHanja, search.kind);
CT_CHECK(t, keystroke(Kesc, 0, &com));
l->dict = dict;
CT_CHECK(t, keystroke(L'', 0, &com));
checkstr(t, "direct Hanja input", "", &search.text);
CT_EQ_INT(t, 2, im.nkouho);
CT_CHECK(t, keystroke(Kret, 0, &com));
checkstr(t, "direct Hanja selection", "", &com);
CT_EQ_INT(t, LangEN, im.l->lang);
init();
im.l = getlang(LangJP);
sclear(&com);
CT_CHECK(t, keystroke('h', Mctrl, &com));
if(!typekeys(t, "ka", &com))
goto cleanup;
CT_CHECK(t, !keystroke('e', Mctrl|Malt, &com));
checkstr(t, "modified search boundary", "", &com);
CT_EQ_INT(t, 0, search.lang);
CT_EQ_INT(t, LangJP, im.l->lang);
sclear(&com);
CT_CHECK(t, !keystroke('h', Mctrl|Msuper, &com));
CT_EQ_INT(t, 0, search.lang);
CT_EQ_INT(t, LangJP, im.l->lang);
cleanup:
searchend(&f);
}
static u32int
@@ -1364,7 +1388,7 @@ engine_randomized_stress(struct ct *t)
'u', 'w', 'y', '1', '2', '9', '\'', ' ', L'',
};
static Rune modes[] = { 't', 'n', 'k', 's', 'v' };
Emojifix f;
Searchfix f;
Lang *vi;
Trie *vimap;
Keyres res;
@@ -1452,7 +1476,7 @@ engine_randomized_stress(struct ct *t)
break;
}
}
emojiend(&f);
searchend(&f);
vi->map = vimap;
}

View File

@@ -57,7 +57,7 @@ void engine_emoji_dictionary_identity(struct ct*);
void engine_hanja_search(struct ct*);
void engine_hanja_unknown_and_cancel(struct ct*);
void engine_hanja_korean_keys(struct ct*);
void engine_hanja_korean_only(struct ct*);
void engine_hanja_input_languages(struct ct*);
void engine_randomized_stress(struct ct*);
void engine_full_boundary_passthrough(struct ct*);
void dictionary_candidates(struct ct*);

View File

@@ -111,7 +111,7 @@ static const struct ct_test tests[] = {
{ "engine/hanja-search", engine_hanja_search },
{ "engine/hanja-unknown-cancel", engine_hanja_unknown_and_cancel },
{ "engine/hanja-korean-keys", engine_hanja_korean_keys },
{ "engine/hanja-korean-only", engine_hanja_korean_only },
{ "engine/hanja-input-languages", engine_hanja_input_languages },
{ "engine/randomized-stress", engine_randomized_stress },
{ "engine/full-boundary-passthrough", engine_full_boundary_passthrough },
{ "dict/candidates", dictionary_candidates },