hanja: separate temporary search mode
This commit is contained in:
15
README.md
15
README.md
@@ -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
1
dat.h
@@ -13,6 +13,7 @@ enum
|
||||
LangJP = 0x0e,
|
||||
LangJPK = 0x0b,
|
||||
LangKO = 0x13,
|
||||
LangHANJA = 0x08,
|
||||
LangEMOJI = 0x05,
|
||||
LangVI = 0x16,
|
||||
|
||||
|
||||
77
strans.c
77
strans.c
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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*);
|
||||
|
||||
@@ -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 },
|
||||
|
||||
Reference in New Issue
Block a user