fix(engine): make composition transitions deterministic
This commit is contained in:
187
strans.c
187
strans.c
@@ -7,6 +7,7 @@ static void *activeowner;
|
|||||||
static int activecap;
|
static int activecap;
|
||||||
static Caret caret;
|
static Caret caret;
|
||||||
static u32int dictseq;
|
static u32int dictseq;
|
||||||
|
static int candidatechosen;
|
||||||
static void dictqmap(Im*);
|
static void dictqmap(Im*);
|
||||||
static void dictqjp(Im*);
|
static void dictqjp(Im*);
|
||||||
static void backjp(Im*);
|
static void backjp(Im*);
|
||||||
@@ -38,6 +39,7 @@ clearkouho(void)
|
|||||||
dictseq++;
|
dictseq++;
|
||||||
im.nkouho = 0;
|
im.nkouho = 0;
|
||||||
im.sel = -1;
|
im.sel = -1;
|
||||||
|
candidatechosen = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -83,6 +85,7 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -154,36 +157,43 @@ setkouho(Dictres *res)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
show(void)
|
snapshot(Drawcmd *dc)
|
||||||
{
|
{
|
||||||
static Drawcmd old;
|
|
||||||
Drawcmd dc;
|
|
||||||
Str pre;
|
Str pre;
|
||||||
int i, first, n;
|
int i, first, n;
|
||||||
|
|
||||||
sclear(&dc.pre);
|
memset(dc, 0, sizeof *dc);
|
||||||
if(search.lang)
|
if(search.lang)
|
||||||
pre = search.text;
|
pre = search.text;
|
||||||
else
|
else
|
||||||
impre(&pre);
|
impre(&pre);
|
||||||
if(!(activecap & Cclientpreedit)){
|
if(!(activecap & Cclientpreedit)){
|
||||||
if(search.lang || isjp(&im) || im.l->map == nil ||
|
if(search.lang || isjp(&im) || im.l->map == nil ||
|
||||||
!mapget(im.l->map, &pre, &dc.pre))
|
!mapget(im.l->map, &pre, &dc->pre))
|
||||||
dc.pre = pre;
|
dc->pre = pre;
|
||||||
}
|
}
|
||||||
first = pagefirst();
|
first = pagefirst();
|
||||||
n = im.nkouho - first;
|
n = im.nkouho - first;
|
||||||
if(n > Maxdisp) n = Maxdisp;
|
if(n > Maxdisp) n = Maxdisp;
|
||||||
dc.nkouho = n;
|
dc->nkouho = n;
|
||||||
dc.sel = im.sel >= 0 ? im.sel - first : -1;
|
dc->sel = im.sel >= 0 ? im.sel - first : -1;
|
||||||
dc.first = first;
|
dc->first = first;
|
||||||
dc.total = im.nkouho;
|
dc->total = im.nkouho;
|
||||||
dc.caret = caret;
|
dc->caret = caret;
|
||||||
for(i = 0; i < n; i++)
|
for(i = 0; i < n; i++)
|
||||||
dc.kouho[i] = im.kouho[first + i];
|
dc->kouho[i] = im.kouho[first + i];
|
||||||
if(dc.pre.n == 0 && n == 0 && !visible)
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
redraw(void)
|
||||||
|
{
|
||||||
|
static Drawcmd old;
|
||||||
|
Drawcmd dc;
|
||||||
|
|
||||||
|
snapshot(&dc);
|
||||||
|
if(dc.pre.n == 0 && dc.nkouho == 0 && !visible)
|
||||||
return;
|
return;
|
||||||
visible = dc.pre.n != 0 || n != 0;
|
visible = dc.pre.n != 0 || dc.nkouho != 0;
|
||||||
/* imthread is the sole producer; keep only the newest pending draw. */
|
/* imthread is the sole producer; keep only the newest pending draw. */
|
||||||
while(channbrecv(drawc, &old) > 0)
|
while(channbrecv(drawc, &old) > 0)
|
||||||
;
|
;
|
||||||
@@ -200,7 +210,6 @@ reset(void)
|
|||||||
sclear(&search.text);
|
sclear(&search.text);
|
||||||
memset(&caret, 0, sizeof caret);
|
memset(&caret, 0, sizeof caret);
|
||||||
clearkouho();
|
clearkouho();
|
||||||
show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -227,7 +236,6 @@ dictqmap(Im *im)
|
|||||||
Str dict;
|
Str dict;
|
||||||
|
|
||||||
clearkouho();
|
clearkouho();
|
||||||
show();
|
|
||||||
if(im->l->map == nil)
|
if(im->l->map == nil)
|
||||||
return;
|
return;
|
||||||
if(!mapget(im->l->map, &im->pre, &dict))
|
if(!mapget(im->l->map, &im->pre, &dict))
|
||||||
@@ -241,7 +249,6 @@ dictqjp(Im *im)
|
|||||||
Str reading;
|
Str reading;
|
||||||
|
|
||||||
clearkouho();
|
clearkouho();
|
||||||
show();
|
|
||||||
if(im->l->dict == nil || !jpreading(im, &reading) || reading.n == 0)
|
if(im->l->dict == nil || !jpreading(im, &reading) || reading.n == 0)
|
||||||
return;
|
return;
|
||||||
dictsend(im, &reading);
|
dictsend(im, &reading);
|
||||||
@@ -260,19 +267,25 @@ setlang(int c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
commit(Str *com)
|
commitim(Im *p, Str *com)
|
||||||
{
|
{
|
||||||
Str val;
|
Str val;
|
||||||
|
|
||||||
if(isjp(&im)){
|
if(isjp(p)){
|
||||||
jpreading(&im, &val);
|
jpreading(p, &val);
|
||||||
sappend(com, &val);
|
sappend(com, &val);
|
||||||
}else if(im.l->map != nil && mapget(im.l->map, &im.pre, &val))
|
}else if(p->l->map != nil && mapget(p->l->map, &p->pre, &val))
|
||||||
sappend(com, &val);
|
sappend(com, &val);
|
||||||
else
|
else
|
||||||
sappend(com, &im.pre);
|
sappend(com, &p->pre);
|
||||||
sclear(&im.pre);
|
sclear(&p->pre);
|
||||||
sclear(&im.raw);
|
sclear(&p->raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
commit(Str *com)
|
||||||
|
{
|
||||||
|
commitim(&im, com);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -302,43 +315,39 @@ keeptail(Str *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
dotransjp(Rune c, Str *com)
|
transjp(Im *p, Rune c, Str *com)
|
||||||
{
|
{
|
||||||
Str key, mapped;
|
Str key, mapped;
|
||||||
|
|
||||||
if(c == '\'' && im.raw.n == 1 && im.raw.r[0] == 'n'){
|
if(c == '\'' && p->raw.n == 1 && p->raw.r[0] == 'n'){
|
||||||
if(mapget(im.l->map, &im.raw, &mapped))
|
if(mapget(p->l->map, &p->raw, &mapped))
|
||||||
sappend(&im.pre, &mapped);
|
sappend(&p->pre, &mapped);
|
||||||
sclear(&im.raw);
|
sclear(&p->raw);
|
||||||
dictqjp(&im);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
key = im.raw;
|
key = p->raw;
|
||||||
if(key.n < Maxrunes)
|
if(key.n < Maxrunes)
|
||||||
sputr(&key, c);
|
sputr(&key, c);
|
||||||
sclear(&mapped);
|
sclear(&mapped);
|
||||||
if(maplookup(im.l->map, &key, &mapped)){
|
if(maplookup(p->l->map, &key, &mapped)){
|
||||||
im.raw = key;
|
p->raw = key;
|
||||||
if(issmalltsu(&mapped)){
|
if(issmalltsu(&mapped)){
|
||||||
sappend(&im.pre, &mapped);
|
sappend(&p->pre, &mapped);
|
||||||
keeptail(&im.raw);
|
keeptail(&p->raw);
|
||||||
}
|
}
|
||||||
dictqjp(&im);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if(im.raw.n != 0 && mapget(im.l->map, &im.raw, &mapped)){
|
if(p->raw.n != 0 && mapget(p->l->map, &p->raw, &mapped)){
|
||||||
sappend(&im.pre, &mapped);
|
sappend(&p->pre, &mapped);
|
||||||
sclear(&im.raw);
|
sclear(&p->raw);
|
||||||
sclear(&key);
|
sclear(&key);
|
||||||
sputr(&key, c);
|
sputr(&key, c);
|
||||||
if(maplookup(im.l->map, &key, &mapped)){
|
if(maplookup(p->l->map, &key, &mapped)){
|
||||||
im.raw = key;
|
p->raw = key;
|
||||||
dictqjp(&im);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
commit(com);
|
commitim(p, com);
|
||||||
clearkouho();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,8 +357,14 @@ dotrans(Rune c, Str *com)
|
|||||||
Emit e;
|
Emit e;
|
||||||
Str mapped;
|
Str mapped;
|
||||||
|
|
||||||
if(isjp(&im))
|
if(isjp(&im)){
|
||||||
return dotransjp(c, com);
|
e.eat = transjp(&im, c, com);
|
||||||
|
if(e.eat)
|
||||||
|
dictqjp(&im);
|
||||||
|
else
|
||||||
|
clearkouho();
|
||||||
|
return e.eat;
|
||||||
|
}
|
||||||
e = im.l->trans(&im, c);
|
e = im.l->trans(&im, c);
|
||||||
if(im.l->lang == LangVI){
|
if(im.l->lang == LangVI){
|
||||||
if(e.s.n > 0 || !e.eat)
|
if(e.s.n > 0 || !e.eat)
|
||||||
@@ -470,7 +485,7 @@ foldascii(Str *s)
|
|||||||
static void
|
static void
|
||||||
transstr(Lang *l, Str *raw, Str *out)
|
transstr(Lang *l, Str *raw, Str *out)
|
||||||
{
|
{
|
||||||
static Im q;
|
Im q;
|
||||||
Emit e;
|
Emit e;
|
||||||
Str mapped;
|
Str mapped;
|
||||||
int i;
|
int i;
|
||||||
@@ -482,6 +497,14 @@ transstr(Lang *l, Str *raw, Str *out)
|
|||||||
}
|
}
|
||||||
memset(&q, 0, sizeof q);
|
memset(&q, 0, sizeof q);
|
||||||
q.l = l;
|
q.l = l;
|
||||||
|
if(isjp(&q)){
|
||||||
|
for(i = 0; i < raw->n; i++)
|
||||||
|
if(!transjp(&q, raw->r[i], out) && out->n < Maxrunes)
|
||||||
|
sputr(out, raw->r[i]);
|
||||||
|
if(haspre(&q))
|
||||||
|
commitim(&q, out);
|
||||||
|
return;
|
||||||
|
}
|
||||||
for(i = 0; i < raw->n; i++){
|
for(i = 0; i < raw->n; i++){
|
||||||
e = l->trans(&q, raw->r[i]);
|
e = l->trans(&q, raw->r[i]);
|
||||||
sappend(out, &e.s);
|
sappend(out, &e.s);
|
||||||
@@ -546,7 +569,6 @@ emojiquery(void)
|
|||||||
}
|
}
|
||||||
search.text = rawhit || !localhit ? raw : local;
|
search.text = rawhit || !localhit ? raw : local;
|
||||||
selectfirst();
|
selectfirst();
|
||||||
show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -562,7 +584,6 @@ hanjaquery(void)
|
|||||||
setkouho(&res);
|
setkouho(&res);
|
||||||
}else
|
}else
|
||||||
clearkouho();
|
clearkouho();
|
||||||
show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -591,7 +612,6 @@ endsearch(void)
|
|||||||
sclear(&search.raw);
|
sclear(&search.raw);
|
||||||
sclear(&search.text);
|
sclear(&search.text);
|
||||||
clearkouho();
|
clearkouho();
|
||||||
show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -605,7 +625,6 @@ startsearch(int lang, Str *com)
|
|||||||
search.lang = lang;
|
search.lang = lang;
|
||||||
sclear(&search.raw);
|
sclear(&search.raw);
|
||||||
sclear(&search.text);
|
sclear(&search.text);
|
||||||
show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -638,7 +657,6 @@ searchkey(u32int ks, u32int mod, Str *com)
|
|||||||
if(im.nkouho == 0)
|
if(im.nkouho == 0)
|
||||||
return 1;
|
return 1;
|
||||||
movekouho(n);
|
movekouho(n);
|
||||||
show();
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
n = numberedkouho(ks, mod);
|
n = numberedkouho(ks, mod);
|
||||||
@@ -658,7 +676,6 @@ searchkey(u32int ks, u32int mod, Str *com)
|
|||||||
im.sel = 0;
|
im.sel = 0;
|
||||||
else
|
else
|
||||||
im.sel++;
|
im.sel++;
|
||||||
show();
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if(ks == Kret){
|
if(ks == Kret){
|
||||||
@@ -712,7 +729,7 @@ searchkey(u32int ks, u32int mod, Str *com)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
keystroke(u32int ks, u32int mod, Str *com)
|
transition(u32int ks, u32int mod, Str *com)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
Rune c;
|
Rune c;
|
||||||
@@ -726,7 +743,6 @@ keystroke(u32int ks, u32int mod, Str *com)
|
|||||||
if(im.nkouho == 0)
|
if(im.nkouho == 0)
|
||||||
return 0;
|
return 0;
|
||||||
movekouho(n);
|
movekouho(n);
|
||||||
show();
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
n = numberedkouho(ks, mod);
|
n = numberedkouho(ks, mod);
|
||||||
@@ -736,7 +752,7 @@ keystroke(u32int ks, u32int mod, Str *com)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if(ks == Ktab || ks == Kret){
|
if(ks == Ktab || ks == Kret){
|
||||||
if(im.sel >= 0 && im.sel < im.nkouho){
|
if(candidatechosen && im.sel >= 0 && im.sel < im.nkouho){
|
||||||
sappend(com, &im.kouho[im.sel]);
|
sappend(com, &im.kouho[im.sel]);
|
||||||
reset();
|
reset();
|
||||||
return 1;
|
return 1;
|
||||||
@@ -779,12 +795,14 @@ keystroke(u32int ks, u32int mod, Str *com)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if(getlang(c) != nil){
|
if(getlang(c) != nil){
|
||||||
if(isjp(&im) && haspre(&im))
|
if(haspre(&im))
|
||||||
commit(com);
|
commit(com);
|
||||||
reset();
|
reset();
|
||||||
setlang(c);
|
setlang(c);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
if(haspre(&im))
|
||||||
|
commit(com);
|
||||||
reset();
|
reset();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -814,10 +832,33 @@ keystroke(u32int ks, u32int mod, Str *com)
|
|||||||
if(im.l->lang == LangKO)
|
if(im.l->lang == LangKO)
|
||||||
ks = kokey(ks, mod);
|
ks = kokey(ks, mod);
|
||||||
n = dotrans(ks, com);
|
n = dotrans(ks, com);
|
||||||
show();
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
keystrokeforce(u32int ks, u32int mod, Str *com, int force)
|
||||||
|
{
|
||||||
|
Im oldim;
|
||||||
|
Search oldsearch;
|
||||||
|
int eaten, ncom;
|
||||||
|
|
||||||
|
oldim = im;
|
||||||
|
oldsearch = search;
|
||||||
|
ncom = com->n;
|
||||||
|
eaten = transition(ks, mod, com);
|
||||||
|
if(force || eaten || com->n != ncom ||
|
||||||
|
memcmp(&oldim, &im, sizeof im) != 0 ||
|
||||||
|
memcmp(&oldsearch, &search, sizeof search) != 0)
|
||||||
|
redraw();
|
||||||
|
return eaten;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
keystroke(u32int ks, u32int mod, Str *com)
|
||||||
|
{
|
||||||
|
return keystrokeforce(ks, mod, com, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
init(void)
|
init(void)
|
||||||
{
|
{
|
||||||
@@ -829,6 +870,7 @@ init(void)
|
|||||||
activeowner = nil;
|
activeowner = nil;
|
||||||
activecap = 0;
|
activecap = 0;
|
||||||
dictseq = 0;
|
dictseq = 0;
|
||||||
|
candidatechosen = 0;
|
||||||
visible = 0;
|
visible = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -854,6 +896,7 @@ imhandlekey(Keyreq *kr)
|
|||||||
{
|
{
|
||||||
Keyres res;
|
Keyres res;
|
||||||
void *oldowner;
|
void *oldowner;
|
||||||
|
int changed;
|
||||||
|
|
||||||
oldowner = activeowner;
|
oldowner = activeowner;
|
||||||
sclear(&res.commit);
|
sclear(&res.commit);
|
||||||
@@ -865,16 +908,19 @@ imhandlekey(Keyreq *kr)
|
|||||||
reset();
|
reset();
|
||||||
activeowner = nil;
|
activeowner = nil;
|
||||||
activecap = 0;
|
activecap = 0;
|
||||||
|
redraw();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Keyreset:
|
case Keyreset:
|
||||||
if(kr->owner == activeowner)
|
if(kr->owner == activeowner){
|
||||||
reset();
|
reset();
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case Keycaret:
|
case Keycaret:
|
||||||
if(kr->owner == activeowner){
|
if(kr->owner == activeowner){
|
||||||
caret = kr->caret;
|
caret = kr->caret;
|
||||||
show();
|
redraw();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Keycap:
|
case Keycap:
|
||||||
@@ -882,24 +928,33 @@ imhandlekey(Keyreq *kr)
|
|||||||
if(activeowner != nil && kr->owner == activeowner){
|
if(activeowner != nil && kr->owner == activeowner){
|
||||||
res.eaten = 1;
|
res.eaten = 1;
|
||||||
if(setactivecap(kr->cap))
|
if(setactivecap(kr->cap))
|
||||||
show();
|
redraw();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Keypress:
|
case Keypress:
|
||||||
res.eaten = 0;
|
res.eaten = 0;
|
||||||
|
changed = 0;
|
||||||
if(activeowner != nil && kr->owner == activeowner &&
|
if(activeowner != nil && kr->owner == activeowner &&
|
||||||
setactivecap(kr->cap))
|
setactivecap(kr->cap))
|
||||||
show();
|
changed = 1;
|
||||||
if(meaningful(kr)){
|
if(meaningful(kr)){
|
||||||
if(kr->owner != activeowner){
|
if(kr->owner != activeowner){
|
||||||
reset();
|
reset();
|
||||||
activeowner = kr->owner;
|
activeowner = kr->owner;
|
||||||
activecap = kr->cap & Cclientpreedit;
|
activecap = kr->cap & Cclientpreedit;
|
||||||
caret = kr->caret;
|
caret = kr->caret;
|
||||||
}else if(kr->caret.valid)
|
changed = 1;
|
||||||
|
}else if(kr->caret.valid){
|
||||||
caret = kr->caret;
|
caret = kr->caret;
|
||||||
res.eaten = keystroke(kr->ks, kr->mod, &res.commit);
|
changed = 1;
|
||||||
}
|
}
|
||||||
|
if(changed)
|
||||||
|
res.eaten = keystrokeforce(kr->ks, kr->mod,
|
||||||
|
&res.commit, 1);
|
||||||
|
else
|
||||||
|
res.eaten = keystroke(kr->ks, kr->mod, &res.commit);
|
||||||
|
}else if(changed)
|
||||||
|
redraw();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(activeowner != oldowner)
|
if(activeowner != oldowner)
|
||||||
@@ -923,7 +978,7 @@ dictresult(Dictres *res)
|
|||||||
scmp(&res->key, &pre) != 0)
|
scmp(&res->key, &pre) != 0)
|
||||||
return;
|
return;
|
||||||
setkouho(res);
|
setkouho(res);
|
||||||
show();
|
redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ int checkstr(struct ct*, char*, char*, Str*);
|
|||||||
Str shownpre(Im*);
|
Str shownpre(Im*);
|
||||||
|
|
||||||
static int typekeys(struct ct*, char*, Str*);
|
static int typekeys(struct ct*, char*, Str*);
|
||||||
|
static int draindraw(Drawcmd*);
|
||||||
|
|
||||||
void
|
void
|
||||||
testengineinit(int lang)
|
testengineinit(int lang)
|
||||||
@@ -417,7 +418,8 @@ engine_commit_contract(struct ct *t)
|
|||||||
im.kouho[0] = mkstr("c1");
|
im.kouho[0] = mkstr("c1");
|
||||||
im.kouho[1] = mkstr("c2");
|
im.kouho[1] = mkstr("c2");
|
||||||
im.nkouho = 2;
|
im.nkouho = 2;
|
||||||
im.sel = 1;
|
im.sel = 0;
|
||||||
|
CT_CHECK(t, keystroke(Kdown, 0, &com));
|
||||||
CT_CHECK(t, keystroke(Kret, 0, &com));
|
CT_CHECK(t, keystroke(Kret, 0, &com));
|
||||||
checkstr(t, "selected candidate", "c2", &com);
|
checkstr(t, "selected candidate", "c2", &com);
|
||||||
CT_EQ_INT(t, 0, im.pre.n);
|
CT_EQ_INT(t, 0, im.pre.n);
|
||||||
@@ -484,6 +486,7 @@ engine_korean_modifiers_and_backspace(struct ct *t)
|
|||||||
{ 'w', "ㅈ", "ㅉ" }, { 'o', "ㅐ", "ㅒ" },
|
{ 'w', "ㅈ", "ㅉ" }, { 'o', "ㅐ", "ㅒ" },
|
||||||
{ 'p', "ㅔ", "ㅖ" },
|
{ 'p', "ㅔ", "ㅖ" },
|
||||||
};
|
};
|
||||||
|
Drawcmd dc;
|
||||||
Str com;
|
Str com;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -518,8 +521,11 @@ engine_korean_modifiers_and_backspace(struct ct *t)
|
|||||||
sclear(&com);
|
sclear(&com);
|
||||||
if(typekeys(t, "rkr", &com)){
|
if(typekeys(t, "rkr", &com)){
|
||||||
checkstr(t, "Korean engine preedit", "각", &im.pre);
|
checkstr(t, "Korean engine preedit", "각", &im.pre);
|
||||||
|
draindraw(nil);
|
||||||
CT_CHECK(t, keystroke(Kback, 0, &com));
|
CT_CHECK(t, keystroke(Kback, 0, &com));
|
||||||
checkstr(t, "Korean final backspace", "가", &im.pre);
|
checkstr(t, "Korean final backspace", "가", &im.pre);
|
||||||
|
if(CT_CHECK(t, draindraw(&dc) == 1))
|
||||||
|
checkstr(t, "Korean backspace redraw", "가", &dc.pre);
|
||||||
CT_CHECK(t, keystroke(Kback, 0, &com));
|
CT_CHECK(t, keystroke(Kback, 0, &com));
|
||||||
checkstr(t, "Korean vowel backspace", "ㄱ", &im.pre);
|
checkstr(t, "Korean vowel backspace", "ㄱ", &im.pre);
|
||||||
CT_CHECK(t, keystroke(Kback, 0, &com));
|
CT_CHECK(t, keystroke(Kback, 0, &com));
|
||||||
@@ -578,10 +584,10 @@ engine_language_switch_state(struct ct *t)
|
|||||||
{ "select Vietnamese", 'v', Mctrl, LangVI, "", "", "", 0 },
|
{ "select Vietnamese", 'v', Mctrl, LangVI, "", "", "", 0 },
|
||||||
{ "Vietnamese a", 'a', 0, LangVI, "a", "a", "", 0 },
|
{ "Vietnamese a", 'a', 0, LangVI, "a", "a", "", 0 },
|
||||||
{ "Vietnamese tone", 's', 0, LangVI, "as", "as", "", 0 },
|
{ "Vietnamese tone", 's', 0, LangVI, "as", "as", "", 0 },
|
||||||
{ "switch to Korean", 's', Mctrl, LangKO, "", "", "", 1 },
|
{ "switch to Korean", 's', Mctrl, LangKO, "", "", "á", 1 },
|
||||||
{ "Korean initial", 'r', 0, LangKO, "ㄱ", "", "", 0 },
|
{ "Korean initial", 'r', 0, LangKO, "ㄱ", "", "", 0 },
|
||||||
{ "Korean syllable", 'k', 0, LangKO, "가", "", "", 0 },
|
{ "Korean syllable", 'k', 0, LangKO, "가", "", "", 0 },
|
||||||
{ "switch to Vietnamese", 'v', Mctrl, LangVI, "", "", "", 0 },
|
{ "switch to Vietnamese", 'v', Mctrl, LangVI, "", "", "가", 0 },
|
||||||
{ "Vietnamese a again", 'a', 0, LangVI, "a", "a", "", 0 },
|
{ "Vietnamese a again", 'a', 0, LangVI, "a", "a", "", 0 },
|
||||||
{ "Vietnamese tone again", 's', 0, LangVI, "as", "as", "", 0 },
|
{ "Vietnamese tone again", 's', 0, LangVI, "as", "as", "", 0 },
|
||||||
{ "commit Vietnamese", Kret, 0, LangVI, "", "", "á", 0 },
|
{ "commit Vietnamese", Kret, 0, LangVI, "", "", "á", 0 },
|
||||||
@@ -632,6 +638,24 @@ engine_language_switch_state(struct ct *t)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
init();
|
||||||
|
im.l = getlang(LangKO);
|
||||||
|
sclear(&com);
|
||||||
|
if(typekeys(t, "rk", &com)){
|
||||||
|
CT_CHECK(t, !keystroke('p', Mctrl, &com));
|
||||||
|
checkstr(t, "Korean Ctrl passthrough", "가", &com);
|
||||||
|
CT_EQ_INT(t, 0, im.pre.n);
|
||||||
|
}
|
||||||
|
init();
|
||||||
|
im.l = &testvi;
|
||||||
|
sclear(&com);
|
||||||
|
if(typekeys(t, "as", &com)){
|
||||||
|
CT_CHECK(t, !keystroke('p', Mctrl, &com));
|
||||||
|
checkstr(t, "Vietnamese Ctrl passthrough", "á", &com);
|
||||||
|
CT_EQ_INT(t, 0, im.pre.n);
|
||||||
|
CT_EQ_INT(t, 0, im.raw.n);
|
||||||
|
}
|
||||||
vi->map = saved;
|
vi->map = saved;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -644,6 +668,7 @@ struct Searchfix
|
|||||||
Hmap *dict;
|
Hmap *dict;
|
||||||
int activecap;
|
int activecap;
|
||||||
int visible;
|
int visible;
|
||||||
|
int candidatechosen;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -691,7 +716,7 @@ checkcandidatepage(struct ct *t, char *where, int first, int n, int sel)
|
|||||||
Drawcmd dc;
|
Drawcmd dc;
|
||||||
char want[8];
|
char want[8];
|
||||||
|
|
||||||
show();
|
redraw();
|
||||||
if(!CT_CHECK(t, draindraw(&dc) > 0))
|
if(!CT_CHECK(t, draindraw(&dc) > 0))
|
||||||
return 0;
|
return 0;
|
||||||
if(!CT_EQ_INT(t, n, dc.nkouho) || !CT_EQ_INT(t, sel, dc.sel) ||
|
if(!CT_EQ_INT(t, n, dc.nkouho) || !CT_EQ_INT(t, sel, dc.sel) ||
|
||||||
@@ -732,10 +757,10 @@ engine_candidate_page_metadata(struct ct *t)
|
|||||||
|
|
||||||
/* A clearing draw is the observable zero-candidate snapshot. */
|
/* A clearing draw is the observable zero-candidate snapshot. */
|
||||||
candidatebegin(1);
|
candidatebegin(1);
|
||||||
show();
|
redraw();
|
||||||
draindraw(nil);
|
draindraw(nil);
|
||||||
setcandidates(0);
|
setcandidates(0);
|
||||||
show();
|
redraw();
|
||||||
if(CT_CHECK(t, draindraw(&dc) > 0)){
|
if(CT_CHECK(t, draindraw(&dc) > 0)){
|
||||||
CT_EQ_INT(t, 0, dc.nkouho);
|
CT_EQ_INT(t, 0, dc.nkouho);
|
||||||
CT_EQ_INT(t, -1, dc.sel);
|
CT_EQ_INT(t, -1, dc.sel);
|
||||||
@@ -761,7 +786,7 @@ engine_candidate_page_snapshots(struct ct *t)
|
|||||||
candidatebegin(totals[i]);
|
candidatebegin(totals[i]);
|
||||||
CT_EQ_INT(t, totals[i] == 0 ? -1 : 0, im.sel);
|
CT_EQ_INT(t, totals[i] == 0 ? -1 : 0, im.sel);
|
||||||
if(totals[i] == 0){
|
if(totals[i] == 0){
|
||||||
show();
|
redraw();
|
||||||
CT_EQ_INT(t, 0, draindraw(nil));
|
CT_EQ_INT(t, 0, draindraw(nil));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -815,17 +840,39 @@ engine_candidate_page_movement(struct ct *t)
|
|||||||
void
|
void
|
||||||
engine_candidate_completion(struct ct *t)
|
engine_candidate_completion(struct ct *t)
|
||||||
{
|
{
|
||||||
|
static Rune keys[] = { Kret, Ktab };
|
||||||
|
Dictres res;
|
||||||
Str com;
|
Str com;
|
||||||
|
int arrived, i;
|
||||||
|
|
||||||
|
for(i = 0; i < nelem(keys); i++)
|
||||||
|
for(arrived = 0; arrived < 2; arrived++){
|
||||||
|
init();
|
||||||
|
im.l = getlang(LangJP);
|
||||||
|
im.pre = mkstr("reading");
|
||||||
|
memset(&res, 0, sizeof res);
|
||||||
|
res.key = im.pre;
|
||||||
|
res.lang = LangJP;
|
||||||
|
res.seq = dictseq;
|
||||||
|
res.kouho[0] = mkstr("candidate");
|
||||||
|
res.nkouho = 1;
|
||||||
|
if(arrived)
|
||||||
|
dictresult(&res);
|
||||||
|
sclear(&com);
|
||||||
|
CT_CHECK(t, keystroke(keys[i], 0, &com));
|
||||||
|
if(!arrived)
|
||||||
|
dictresult(&res);
|
||||||
|
checkstr(t, "unselected candidate commits reading",
|
||||||
|
"reading", &com);
|
||||||
|
CT_EQ_INT(t, 0, im.nkouho);
|
||||||
|
}
|
||||||
|
|
||||||
candidatebegin(2);
|
candidatebegin(2);
|
||||||
|
im.pre = mkstr("reading");
|
||||||
sclear(&com);
|
sclear(&com);
|
||||||
|
CT_CHECK(t, keystroke(Kdown, 0, &com));
|
||||||
CT_CHECK(t, keystroke(Kret, 0, &com));
|
CT_CHECK(t, keystroke(Kret, 0, &com));
|
||||||
checkstr(t, "default candidate", "c1", &com);
|
checkstr(t, "explicit candidate", "c2", &com);
|
||||||
|
|
||||||
candidatebegin(2);
|
|
||||||
sclear(&com);
|
|
||||||
CT_CHECK(t, keystroke(Ktab, 0, &com));
|
|
||||||
checkstr(t, "ordinary Tab candidate", "c1", &com);
|
|
||||||
|
|
||||||
candidatebegin(2);
|
candidatebegin(2);
|
||||||
im.pre = mkstr("reading");
|
im.pre = mkstr("reading");
|
||||||
@@ -866,6 +913,7 @@ searchsave(Searchfix *f, int lang)
|
|||||||
f->dict = f->dictlang->dict;
|
f->dict = f->dictlang->dict;
|
||||||
f->activecap = activecap;
|
f->activecap = activecap;
|
||||||
f->visible = visible;
|
f->visible = visible;
|
||||||
|
f->candidatechosen = candidatechosen;
|
||||||
draindraw(nil);
|
draindraw(nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -908,6 +956,7 @@ searchend(Searchfix *f)
|
|||||||
search = f->search;
|
search = f->search;
|
||||||
activecap = f->activecap;
|
activecap = f->activecap;
|
||||||
visible = f->visible;
|
visible = f->visible;
|
||||||
|
candidatechosen = f->candidatechosen;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -931,7 +980,7 @@ engine_popup_preedit_capability(struct ct *t)
|
|||||||
res.nkouho = 1;
|
res.nkouho = 1;
|
||||||
dictresult(&res);
|
dictresult(&res);
|
||||||
im.sel = 0;
|
im.sel = 0;
|
||||||
show();
|
redraw();
|
||||||
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);
|
||||||
@@ -1018,7 +1067,15 @@ engine_japanese_readings(struct ct *t)
|
|||||||
{ "nnya", "んにゃ" },
|
{ "nnya", "んにゃ" },
|
||||||
{ "kin'youbi", "きんようび" },
|
{ "kin'youbi", "きんようび" },
|
||||||
};
|
};
|
||||||
Str com, shown;
|
static const struct {
|
||||||
|
char *raw;
|
||||||
|
char *want;
|
||||||
|
} replay[] = {
|
||||||
|
{ "kitte", "きって" },
|
||||||
|
{ "kanj", "かんj" },
|
||||||
|
{ "n'ya", "んや" },
|
||||||
|
};
|
||||||
|
Str com, raw, shown;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 0; i < nelem(cases); i++){
|
for(i = 0; i < nelem(cases); i++){
|
||||||
@@ -1033,6 +1090,11 @@ engine_japanese_readings(struct ct *t)
|
|||||||
CT_CHECK(t, keystroke(Kret, 0, &com));
|
CT_CHECK(t, keystroke(Kret, 0, &com));
|
||||||
checkstr(t, "committed reading", cases[i].want, &com);
|
checkstr(t, "committed reading", cases[i].want, &com);
|
||||||
}
|
}
|
||||||
|
for(i = 0; i < nelem(replay); i++){
|
||||||
|
raw = mkstr(replay[i].raw);
|
||||||
|
transstr(getlang(LangJP), &raw, &shown);
|
||||||
|
checkstr(t, replay[i].raw, replay[i].want, &shown);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -1194,7 +1256,7 @@ engine_emoji_single_candidate(struct ct *t)
|
|||||||
checkstr(t, "explicit candidate commit", "α", &com);
|
checkstr(t, "explicit candidate commit", "α", &com);
|
||||||
CT_CHECK(t, !search.lang);
|
CT_CHECK(t, !search.lang);
|
||||||
CT_EQ_INT(t, LangKO, im.l->lang);
|
CT_EQ_INT(t, LangKO, im.l->lang);
|
||||||
show();
|
redraw();
|
||||||
CT_CHECK(t, draindraw(&dc) > 0);
|
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, 0, dc.nkouho);
|
CT_EQ_INT(t, 0, dc.nkouho);
|
||||||
|
|||||||
Reference in New Issue
Block a user