engine: route popup preedit by client capability
This commit is contained in:
@@ -15,7 +15,6 @@ Vietnamese Telex is also available as a compatibility mode.
|
||||
| `Ctrl+V` | Vietnamese Telex |
|
||||
| `Ctrl+E` | Emoji and symbol search |
|
||||
| `Ctrl+H` | One-shot Hanja search |
|
||||
| `Ctrl+P` | Toggle popup preedit |
|
||||
|
||||
Use `Up`/`Down` to move through candidates, `Enter` or `1`-`9` to select,
|
||||
`Tab` to cycle temporary search results, and `Esc` to cancel. `0` commits the
|
||||
|
||||
5
dat.h
5
dat.h
@@ -138,6 +138,10 @@ struct Drawcmd
|
||||
typedef struct Keyreq Keyreq;
|
||||
typedef struct Keyres Keyres;
|
||||
enum
|
||||
{
|
||||
Cclientpreedit = 1<<0,
|
||||
};
|
||||
enum
|
||||
{
|
||||
Keypress,
|
||||
Keyreset,
|
||||
@@ -154,6 +158,7 @@ struct Keyres
|
||||
struct Keyreq
|
||||
{
|
||||
void *owner; /* stable until the context's release is acknowledged */
|
||||
int cap;
|
||||
int op;
|
||||
u32int ks;
|
||||
u32int mod;
|
||||
|
||||
1
ibus.c
1
ibus.c
@@ -303,6 +303,7 @@ sendrequest(Ictx *ctx, int op, u32int ks, u32int mod, Keyres *res)
|
||||
|
||||
memset(&kr, 0, sizeof kr);
|
||||
kr.owner = ctx;
|
||||
kr.cap = Cclientpreedit;
|
||||
kr.op = op;
|
||||
kr.ks = ks;
|
||||
kr.mod = mod;
|
||||
|
||||
1
srv.c
1
srv.c
@@ -41,6 +41,7 @@ clientthread(void *arg)
|
||||
reply = chancreate(sizeof(Keyres), 0);
|
||||
kr.reply = reply;
|
||||
kr.owner = &fd;
|
||||
kr.cap = Cclientpreedit;
|
||||
while((want = srvreadkey(fd, &kr)) >= 0){
|
||||
chansend(keyc, &kr);
|
||||
chanrecv(reply, &res);
|
||||
|
||||
17
strans.c
17
strans.c
@@ -2,9 +2,9 @@
|
||||
#include "fn.h"
|
||||
|
||||
static Im im;
|
||||
static int popup = 0;
|
||||
static int visible = 0;
|
||||
static void *activeowner;
|
||||
static int activecap;
|
||||
static Caret caret;
|
||||
static void dictqmap(Im*);
|
||||
static void dictqjp(Im*);
|
||||
@@ -105,7 +105,7 @@ show(void)
|
||||
pre = search.text;
|
||||
else
|
||||
impre(&pre);
|
||||
if(popup){
|
||||
if(!(activecap & Cclientpreedit)){
|
||||
if(search.lang || isjp(&im) || im.l->map == nil ||
|
||||
!mapget(im.l->map, &pre, &dc.pre))
|
||||
dc.pre = pre;
|
||||
@@ -632,11 +632,6 @@ searchkey(u32int ks, u32int mod, Str *com)
|
||||
startsearch(n, com);
|
||||
return 1;
|
||||
}
|
||||
if(c == 0x10){
|
||||
popup = !popup;
|
||||
show();
|
||||
return 1;
|
||||
}
|
||||
endsearch();
|
||||
if(setlang(c))
|
||||
return 1;
|
||||
@@ -725,11 +720,6 @@ keystroke(u32int ks, u32int mod, Str *com)
|
||||
startsearch(n, com);
|
||||
return 1;
|
||||
}
|
||||
if(c == 0x10){
|
||||
popup = !popup;
|
||||
show();
|
||||
return 1;
|
||||
}
|
||||
if(getlang(c) != nil){
|
||||
if(isjp(&im) && haspre(&im))
|
||||
commit(com);
|
||||
@@ -778,6 +768,7 @@ init(void)
|
||||
memset(&search, 0, sizeof search);
|
||||
memset(&caret, 0, sizeof caret);
|
||||
activeowner = nil;
|
||||
activecap = 0;
|
||||
visible = 0;
|
||||
}
|
||||
|
||||
@@ -800,6 +791,7 @@ imhandlekey(Keyreq *kr)
|
||||
if(kr->owner == activeowner){
|
||||
reset();
|
||||
activeowner = nil;
|
||||
activecap = 0;
|
||||
}
|
||||
break;
|
||||
case Keyreset:
|
||||
@@ -818,6 +810,7 @@ imhandlekey(Keyreq *kr)
|
||||
if(kr->owner != activeowner){
|
||||
reset();
|
||||
activeowner = kr->owner;
|
||||
activecap = kr->cap;
|
||||
caret = kr->caret;
|
||||
}else if(kr->caret.valid)
|
||||
caret = kr->caret;
|
||||
|
||||
@@ -192,7 +192,8 @@ engine_dictionary_queue_latest_wins(struct ct *t)
|
||||
}
|
||||
|
||||
static Keyres
|
||||
ownerrequestat(void *owner, int op, Rune key, u32int mod, Caret *caret)
|
||||
ownerrequestatcap(void *owner, int cap, int op, Rune key, u32int mod,
|
||||
Caret *caret)
|
||||
{
|
||||
Channel *reply;
|
||||
Keyreq req;
|
||||
@@ -201,6 +202,7 @@ ownerrequestat(void *owner, int op, Rune key, u32int mod, Caret *caret)
|
||||
reply = chancreate(sizeof(Keyres), 1);
|
||||
memset(&req, 0, sizeof req);
|
||||
req.owner = owner;
|
||||
req.cap = cap;
|
||||
req.op = op;
|
||||
req.ks = key;
|
||||
req.mod = mod;
|
||||
@@ -213,12 +215,24 @@ ownerrequestat(void *owner, int op, Rune key, u32int mod, Caret *caret)
|
||||
return res;
|
||||
}
|
||||
|
||||
static Keyres
|
||||
ownerrequestat(void *owner, int op, Rune key, u32int mod, Caret *caret)
|
||||
{
|
||||
return ownerrequestatcap(owner, 0, op, key, mod, caret);
|
||||
}
|
||||
|
||||
static Keyres
|
||||
ownerrequest(void *owner, int op, Rune key, u32int mod)
|
||||
{
|
||||
return ownerrequestat(owner, op, key, mod, nil);
|
||||
}
|
||||
|
||||
static Keyres
|
||||
ownerrequestcap(void *owner, int cap, int op, Rune key, u32int mod)
|
||||
{
|
||||
return ownerrequestatcap(owner, cap, op, key, mod, nil);
|
||||
}
|
||||
|
||||
void
|
||||
engine_active_owner_lifecycle(struct ct *t)
|
||||
{
|
||||
@@ -566,7 +580,7 @@ struct Searchfix
|
||||
Search search;
|
||||
Lang *dictlang;
|
||||
Hmap *dict;
|
||||
int popup;
|
||||
int activecap;
|
||||
int visible;
|
||||
};
|
||||
|
||||
@@ -601,7 +615,7 @@ searchsave(Searchfix *f, int lang)
|
||||
f->search = search;
|
||||
f->dictlang = getlang(lang);
|
||||
f->dict = f->dictlang->dict;
|
||||
f->popup = popup;
|
||||
f->activecap = activecap;
|
||||
f->visible = visible;
|
||||
draindraw(nil);
|
||||
}
|
||||
@@ -629,7 +643,7 @@ emojibegin(Searchfix *f, int showpre)
|
||||
"c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12");
|
||||
init();
|
||||
im.l = getlang(LangKO);
|
||||
popup = showpre;
|
||||
activecap = showpre ? 0 : Cclientpreedit;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -643,10 +657,54 @@ searchend(Searchfix *f)
|
||||
draindraw(nil);
|
||||
im = f->im;
|
||||
search = f->search;
|
||||
popup = f->popup;
|
||||
activecap = f->activecap;
|
||||
visible = f->visible;
|
||||
}
|
||||
|
||||
void
|
||||
engine_popup_preedit_capability(struct ct *t)
|
||||
{
|
||||
Dictres res;
|
||||
Drawcmd dc;
|
||||
char client, popupowner;
|
||||
|
||||
init();
|
||||
im.l = getlang(LangJP);
|
||||
draindraw(nil);
|
||||
ownerrequestcap(&client, Cclientpreedit, Keypress, 'k', 0);
|
||||
ownerrequestcap(&client, Cclientpreedit, Keypress, 'a', 0);
|
||||
memset(&res, 0, sizeof res);
|
||||
res.lang = LangJP;
|
||||
res.key = mkstr("か");
|
||||
res.kouho[0] = mkstr("家");
|
||||
res.nkouho = 1;
|
||||
dictresult(&res);
|
||||
if(CT_CHECK(t, draindraw(&dc) > 0)){
|
||||
CT_EQ_INT(t, 0, dc.pre.n);
|
||||
CT_EQ_INT(t, 1, dc.nkouho);
|
||||
checkstr(t, "client-preedit candidate", "家", &dc.kouho[0]);
|
||||
}
|
||||
|
||||
ownerrequestcap(&popupowner, 0, Keypress, 'n', 0);
|
||||
if(CT_CHECK(t, draindraw(&dc) > 0)){
|
||||
checkstr(t, "popup preedit", "ん", &dc.pre);
|
||||
CT_EQ_INT(t, 0, dc.nkouho);
|
||||
}
|
||||
memset(&res, 0, sizeof res);
|
||||
res.lang = LangJP;
|
||||
res.key = mkstr("ん");
|
||||
res.kouho[0] = mkstr("ン");
|
||||
res.nkouho = 1;
|
||||
dictresult(&res);
|
||||
if(CT_CHECK(t, draindraw(&dc) > 0)){
|
||||
checkstr(t, "async popup preedit", "ん", &dc.pre);
|
||||
CT_EQ_INT(t, 1, dc.nkouho);
|
||||
checkstr(t, "popup candidate", "ン", &dc.kouho[0]);
|
||||
}
|
||||
ownerrequest(&popupowner, Keyrelease, 0, 0);
|
||||
draindraw(nil);
|
||||
}
|
||||
|
||||
static void
|
||||
hanjabegin(Searchfix *f, int lang)
|
||||
{
|
||||
@@ -841,10 +899,8 @@ engine_emoji_single_candidate(struct ct *t)
|
||||
Searchfix f;
|
||||
Str com;
|
||||
|
||||
emojibegin(&f, 1);
|
||||
emojibegin(&f, 0);
|
||||
sclear(&com);
|
||||
CT_CHECK(t, keystroke('p', Mctrl, &com));
|
||||
CT_EQ_INT(t, 0, popup);
|
||||
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
||||
CT_CHECK(t, search.lang);
|
||||
CT_EQ_INT(t, LangKO, im.l->lang);
|
||||
@@ -1083,7 +1139,6 @@ engine_emoji_preedit_languages(struct ct *t)
|
||||
{
|
||||
Searchfix f;
|
||||
Str com, shown;
|
||||
int p;
|
||||
|
||||
emojibegin(&f, 0);
|
||||
init();
|
||||
@@ -1105,15 +1160,10 @@ engine_emoji_preedit_languages(struct ct *t)
|
||||
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.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.lang);
|
||||
CT_CHECK(t, !keystroke(Kmodfirst+2, 0, &com));
|
||||
CT_CHECK(t, keystroke('E', Mctrl|Mshift, &com));
|
||||
CT_CHECK(t, !keystroke('P', Mctrl|Mshift, &com));
|
||||
CT_CHECK(t, !search.lang);
|
||||
sclear(&com);
|
||||
if(typekeys(t, "na", &com)){
|
||||
|
||||
@@ -238,6 +238,7 @@ nexttrace(struct ct *t, Ibusfix *f, int op, Ictx *ctx)
|
||||
return req;
|
||||
CT_EQ_INT(t, op, req.op);
|
||||
CT_EQ_PTR(t, ctx, req.owner);
|
||||
CT_EQ_INT(t, Cclientpreedit, req.cap);
|
||||
CT_EQ_PTR(t, replyc, req.reply);
|
||||
return req;
|
||||
}
|
||||
|
||||
@@ -149,6 +149,7 @@ nextrequest(struct ct *t, Enginegate *g, int op)
|
||||
memset(&req, 0, sizeof req);
|
||||
chanrecv(g->seen, &req);
|
||||
CT_EQ_INT(t, op, req.op);
|
||||
CT_EQ_INT(t, Cclientpreedit, req.cap);
|
||||
return req;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ void engine_dictionary_queue_latest_wins(struct ct*);
|
||||
void engine_active_owner_lifecycle(struct ct*);
|
||||
void engine_active_owner_reset(struct ct*);
|
||||
void engine_active_owner_caret(struct ct*);
|
||||
void engine_popup_preedit_capability(struct ct*);
|
||||
void engine_commit_contract(struct ct*);
|
||||
void engine_language_switch_state(struct ct*);
|
||||
void engine_telex_history_bound(struct ct*);
|
||||
|
||||
@@ -90,6 +90,7 @@ static const struct ct_test tests[] = {
|
||||
{ "engine/active-owner-lifecycle", engine_active_owner_lifecycle },
|
||||
{ "engine/active-owner-reset", engine_active_owner_reset },
|
||||
{ "engine/active-owner-caret", engine_active_owner_caret },
|
||||
{ "engine/popup-preedit-capability", engine_popup_preedit_capability },
|
||||
{ "engine/commit-contract", engine_commit_contract },
|
||||
{ "engine/language-switch-state", engine_language_switch_state },
|
||||
{ "engine/telex-history-bound", engine_telex_history_bound },
|
||||
|
||||
Reference in New Issue
Block a user