emoji: repair one-shot candidate selection
This commit is contained in:
1
Makefile
1
Makefile
@@ -43,5 +43,6 @@ test:
|
|||||||
verify-map:
|
verify-map:
|
||||||
python3 map/mktelex.py | cmp - map/telex.map
|
python3 map/mktelex.py | cmp - map/telex.map
|
||||||
python3 -B map/mkemoji | cmp - map/emoji.dict
|
python3 -B map/mkemoji | cmp - map/emoji.dict
|
||||||
|
python3 -B tests/mkemoji_test.py
|
||||||
|
|
||||||
.PHONY: all check test verify-map clean xim bench
|
.PHONY: all check test verify-map clean xim bench
|
||||||
|
|||||||
22
README.md
22
README.md
@@ -29,9 +29,9 @@ mirrors must provide the same sibling; initialize it after cloning with
|
|||||||
|
|
||||||
The suite covers the fixed-size UTF-8 string, hash table, trie fixtures,
|
The suite covers the fixed-size UTF-8 string, hash table, trie fixtures,
|
||||||
Japanese/Hangul/Telex state transitions, dictionary candidates, engine
|
Japanese/Hangul/Telex state transitions, dictionary candidates, engine
|
||||||
selection state, and production map loading. Tests use explicit case tables,
|
selection state, IPC request fields, and production map loading. Tests use
|
||||||
boundary values, and small regressions for repaired core contracts. IPC and GUI
|
explicit case tables, boundary values, and small regressions for repaired core
|
||||||
protocol stacks are outside this suite and require separate integration checks.
|
contracts. Full IPC and GUI protocol stacks require separate integration checks.
|
||||||
|
|
||||||
## Run
|
## Run
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ Switch input modes with Ctrl + key:
|
|||||||
P Toggle preedit echo
|
P Toggle preedit echo
|
||||||
|
|
||||||
Type romanized input. Select candidates with 1-9 or arrow keys.
|
Type romanized input. Select candidates with 1-9 or arrow keys.
|
||||||
Tab or Enter to commit.
|
Outside one-shot search, Tab or Enter commits.
|
||||||
|
|
||||||
### Emoji and symbols
|
### Emoji and symbols
|
||||||
|
|
||||||
@@ -82,13 +82,17 @@ preedit echo.
|
|||||||
안녕 → Ctrl+E → smile → Enter → 😀
|
안녕 → Ctrl+E → smile → Enter → 😀
|
||||||
|
|
||||||
There is no auto-insert. Enter commits the first candidate (or the current
|
There is no auto-insert. Enter commits the first candidate (or the current
|
||||||
one); arrows and Tab move, Alt+1 through Alt+9 select, Esc cancels. Plain
|
one); arrows and Tab move, and Esc cancels. Bare 1 through 9 select an existing
|
||||||
digits are part of the query.
|
numbered row; a bare digit with no such row and 0 remain query text. Digit
|
||||||
|
aliases are kept in matching slots, so `^1`, `_2`, and `<3` produce `¹`, `₂`,
|
||||||
|
and `♥`.
|
||||||
|
|
||||||
`map/emoji.src` is the source of truth: each UTF-8 TSV row is a result followed
|
`map/emoji.src` is the source of truth: each UTF-8 TSV row is a result followed
|
||||||
by one or more tab-separated aliases. Aliases may be multilingual. Run
|
by one or more tab-separated aliases. Aliases may be multilingual and ASCII
|
||||||
`map/mkemoji > map/emoji.dict` after editing it; `make verify-map` checks the
|
letters are case-insensitive. Results and aliases are limited to 64 Unicode
|
||||||
generated dictionary and the Telex map.
|
code points; results cannot contain whitespace. Run `map/mkemoji > map/emoji.dict`
|
||||||
|
after editing it; `make verify-map` checks the generated dictionary and the
|
||||||
|
Telex map.
|
||||||
|
|
||||||
😀 웃음 웃다 스마일 smile grin
|
😀 웃음 웃다 스마일 smile grin
|
||||||
|
|
||||||
|
|||||||
2
ipc.c
2
ipc.c
@@ -38,7 +38,7 @@ ipcunpackreq(const unsigned char req[Ipcreqsz], int *want, unsigned int *mod,
|
|||||||
unsigned int *key)
|
unsigned int *key)
|
||||||
{
|
{
|
||||||
*want = req[0] != 0;
|
*want = req[0] != 0;
|
||||||
*mod = req[1];
|
*mod = req[1] & Mmask;
|
||||||
*key = (unsigned int)req[2] |
|
*key = (unsigned int)req[2] |
|
||||||
((unsigned int)req[3] << 8) |
|
((unsigned int)req[3] << 8) |
|
||||||
((unsigned int)req[4] << 16) |
|
((unsigned int)req[4] << 16) |
|
||||||
|
|||||||
6
ipc.h
6
ipc.h
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Request: [want-preedit, modifiers, key byte 0, ..., key byte 3].
|
* Request: [want-preedit, modifiers, key byte 0, ..., key byte 3].
|
||||||
|
* Only Mmask modifier bits are retained.
|
||||||
* Response: [eaten, commit-length-low, commit-length-high, commit...],
|
* Response: [eaten, commit-length-low, commit-length-high, commit...],
|
||||||
* followed, when requested, by
|
* followed, when requested, by
|
||||||
* [preedit-length-low, preedit-length-high, preedit...].
|
* [preedit-length-low, preedit-length-high, preedit...].
|
||||||
@@ -22,13 +23,14 @@ enum
|
|||||||
Kesc = Kspec|0x1b,
|
Kesc = Kspec|0x1b,
|
||||||
Kup = Kspec|0x52,
|
Kup = Kspec|0x52,
|
||||||
Kdown = Kspec|0x54,
|
Kdown = Kspec|0x54,
|
||||||
Kshift = Kspec|0xe1,
|
Kmodfirst = Kspec|0xe1,
|
||||||
Ksuper = Kspec|0xeb,
|
Kmodlast = Kspec|0xee,
|
||||||
|
|
||||||
Mshift = 1<<0,
|
Mshift = 1<<0,
|
||||||
Mctrl = 1<<2,
|
Mctrl = 1<<2,
|
||||||
Malt = 1<<3,
|
Malt = 1<<3,
|
||||||
Msuper = 1<<6,
|
Msuper = 1<<6,
|
||||||
|
Mmask = Mshift|Mctrl|Malt|Msuper,
|
||||||
|
|
||||||
Ipcreqsz = 6,
|
Ipcreqsz = 6,
|
||||||
Ipclensz = 2,
|
Ipclensz = 2,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
: ☹ ☺
|
: ☹ ☺
|
||||||
:( ☹
|
:( ☹
|
||||||
:) ☺
|
:) ☺
|
||||||
< ← ≤ ≠ ♥
|
< ← ≤ ♥ ≠
|
||||||
<- ←
|
<- ←
|
||||||
<3 ♥
|
<3 ♥
|
||||||
<= ≤
|
<= ≤
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
=> ⇒
|
=> ⇒
|
||||||
> ≥
|
> ≥
|
||||||
>= ≥
|
>= ≥
|
||||||
^ ⁽ ⁾ ⁺ ⁻ ⁼ ⁰ ¹ ² ³ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹ ⁱ ⁿ
|
^ ¹ ² ³ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹ ⁽ ⁾ ⁺ ⁻ ⁼ ⁰ ⁱ ⁿ
|
||||||
^( ⁽
|
^( ⁽
|
||||||
^) ⁾
|
^) ⁾
|
||||||
^+ ⁺
|
^+ ⁺
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
^= ⁼
|
^= ⁼
|
||||||
^i ⁱ
|
^i ⁱ
|
||||||
^n ⁿ
|
^n ⁿ
|
||||||
_ ₍ ₎ ₊ ₋ ₌ ₀ ₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉ ₐ ₑ ₒ ₓ
|
_ ₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉ ₍ ₎ ₊ ₋ ₌ ₀ ₐ ₑ ₒ ₓ
|
||||||
_( ₍
|
_( ₍
|
||||||
_) ₎
|
_) ₎
|
||||||
_+ ₊
|
_+ ₊
|
||||||
|
|||||||
@@ -8,12 +8,34 @@
|
|||||||
÷ ./
|
÷ ./
|
||||||
☹ :(
|
☹ :(
|
||||||
☺ :)
|
☺ :)
|
||||||
|
|
||||||
|
# Bare 1-9 choose prefix candidates; keep digit aliases in matching slots.
|
||||||
← <-
|
← <-
|
||||||
≤ <=
|
≤ <=
|
||||||
|
♥ <3
|
||||||
≠ <> !=
|
≠ <> !=
|
||||||
≡ ==
|
≡ ==
|
||||||
⇒ =>
|
⇒ =>
|
||||||
≥ >=
|
≥ >=
|
||||||
|
¹ ^1
|
||||||
|
² ^2
|
||||||
|
³ ^3
|
||||||
|
⁴ ^4
|
||||||
|
⁵ ^5
|
||||||
|
⁶ ^6
|
||||||
|
⁷ ^7
|
||||||
|
⁸ ^8
|
||||||
|
⁹ ^9
|
||||||
|
₁ _1
|
||||||
|
₂ _2
|
||||||
|
₃ _3
|
||||||
|
₄ _4
|
||||||
|
₅ _5
|
||||||
|
₆ _6
|
||||||
|
₇ _7
|
||||||
|
₈ _8
|
||||||
|
₉ _9
|
||||||
|
|
||||||
⁽ ^(
|
⁽ ^(
|
||||||
⁾ ^)
|
⁾ ^)
|
||||||
⁺ ^+
|
⁺ ^+
|
||||||
@@ -27,25 +49,6 @@
|
|||||||
≈ ~=
|
≈ ~=
|
||||||
⁰ ^0
|
⁰ ^0
|
||||||
₀ _0
|
₀ _0
|
||||||
¹ ^1
|
|
||||||
₁ _1
|
|
||||||
² ^2
|
|
||||||
₂ _2
|
|
||||||
♥ <3
|
|
||||||
³ ^3
|
|
||||||
₃ _3
|
|
||||||
⁴ ^4
|
|
||||||
₄ _4
|
|
||||||
⁵ ^5
|
|
||||||
₅ _5
|
|
||||||
⁶ ^6
|
|
||||||
₆ _6
|
|
||||||
⁷ ^7
|
|
||||||
₇ _7
|
|
||||||
⁸ ^8
|
|
||||||
₈ _8
|
|
||||||
⁹ ^9
|
|
||||||
₉ _9
|
|
||||||
ₐ _a
|
ₐ _a
|
||||||
α alpha
|
α alpha
|
||||||
β beta
|
β beta
|
||||||
|
|||||||
15
map/mkemoji
15
map/mkemoji
@@ -7,6 +7,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
|
|
||||||
SOURCE = Path(__file__).with_name("emoji.src")
|
SOURCE = Path(__file__).with_name("emoji.src")
|
||||||
|
MAXRUNES = 64
|
||||||
|
|
||||||
|
|
||||||
def fold(s):
|
def fold(s):
|
||||||
@@ -14,22 +15,30 @@ def fold(s):
|
|||||||
return unicodedata.normalize("NFC", s)
|
return unicodedata.normalize("NFC", s)
|
||||||
|
|
||||||
|
|
||||||
|
def hascontrol(s):
|
||||||
|
return any(unicodedata.category(c) == "Cc" for c in s)
|
||||||
|
|
||||||
|
|
||||||
def read(path):
|
def read(path):
|
||||||
entries = []
|
entries = []
|
||||||
with path.open(encoding="utf-8") as src:
|
with path.open(encoding="utf-8") as src:
|
||||||
for lineno, raw in enumerate(src, 1):
|
for lineno, raw in enumerate(src, 1):
|
||||||
line = raw.rstrip("\r\n")
|
line = raw.rstrip("\r\n")
|
||||||
if not line.strip() or line.lstrip().startswith("#"):
|
if not line.strip():
|
||||||
|
continue
|
||||||
|
if "\t" not in line and line.lstrip().startswith("#"):
|
||||||
continue
|
continue
|
||||||
fields = line.split("\t")
|
fields = line.split("\t")
|
||||||
if len(fields) < 2:
|
if len(fields) < 2:
|
||||||
raise ValueError(f"{path}:{lineno}: need a result and an alias")
|
raise ValueError(f"{path}:{lineno}: need a result and an alias")
|
||||||
result = unicodedata.normalize("NFC", fields[0])
|
result = unicodedata.normalize("NFC", fields[0])
|
||||||
if not result or any(c.isspace() for c in result):
|
if (not result or len(result) > MAXRUNES or hascontrol(result)
|
||||||
|
or any(c.isspace() for c in result)):
|
||||||
raise ValueError(f"{path}:{lineno}: bad result")
|
raise ValueError(f"{path}:{lineno}: bad result")
|
||||||
for field in fields[1:]:
|
for field in fields[1:]:
|
||||||
alias = fold(field)
|
alias = fold(field)
|
||||||
if not alias or alias != alias.strip():
|
if (not alias or len(alias) > MAXRUNES or hascontrol(alias)
|
||||||
|
or alias != alias.strip()):
|
||||||
raise ValueError(f"{path}:{lineno}: bad alias")
|
raise ValueError(f"{path}:{lineno}: bad alias")
|
||||||
entries.append((result, alias))
|
entries.append((result, alias))
|
||||||
return entries
|
return entries
|
||||||
|
|||||||
40
strans.c
40
strans.c
@@ -53,6 +53,7 @@ setkouho(Dictres *res)
|
|||||||
static void
|
static void
|
||||||
show(void)
|
show(void)
|
||||||
{
|
{
|
||||||
|
static Drawcmd old;
|
||||||
Drawcmd dc;
|
Drawcmd dc;
|
||||||
Str *pre;
|
Str *pre;
|
||||||
int i, first, n;
|
int i, first, n;
|
||||||
@@ -73,7 +74,10 @@ show(void)
|
|||||||
if(dc.pre.n == 0 && n == 0 && !visible)
|
if(dc.pre.n == 0 && n == 0 && !visible)
|
||||||
return;
|
return;
|
||||||
visible = dc.pre.n != 0 || n != 0;
|
visible = dc.pre.n != 0 || n != 0;
|
||||||
chansend(drawc, &dc);
|
/* imthread is the sole producer; keep only the newest pending draw. */
|
||||||
|
while(channbrecv(drawc, &old) > 0)
|
||||||
|
;
|
||||||
|
channbsend(drawc, &dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -227,11 +231,19 @@ transmap(Im *im, Rune c)
|
|||||||
static Rune
|
static Rune
|
||||||
ctrlkey(Rune c)
|
ctrlkey(Rune c)
|
||||||
{
|
{
|
||||||
|
if(c >= 'A' && c <= 'Z')
|
||||||
|
c += 'a' - 'A';
|
||||||
if(c >= 'a' && c <= 'z')
|
if(c >= 'a' && c <= 'z')
|
||||||
return c - 'a' + 1;
|
return c - 'a' + 1;
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ismodkey(u32int ks)
|
||||||
|
{
|
||||||
|
return ks >= Kmodfirst && ks <= Kmodlast;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
foldascii(Str *s)
|
foldascii(Str *s)
|
||||||
{
|
{
|
||||||
@@ -369,8 +381,8 @@ searchkey(u32int ks, u32int mod, Str *com)
|
|||||||
int n, off;
|
int n, off;
|
||||||
Rune c;
|
Rune c;
|
||||||
|
|
||||||
if(ks == Ksuper || ks == Kshift)
|
if(ismodkey(ks))
|
||||||
return 1;
|
return 0;
|
||||||
if(ks == Kdown || ks == Kup){
|
if(ks == Kdown || ks == Kup){
|
||||||
if(im.nkouho == 0)
|
if(im.nkouho == 0)
|
||||||
return 1;
|
return 1;
|
||||||
@@ -383,7 +395,7 @@ searchkey(u32int ks, u32int mod, Str *com)
|
|||||||
}
|
}
|
||||||
n = ks - '1';
|
n = ks - '1';
|
||||||
off = im.sel >= Maxdisp ? im.sel - Maxdisp + 1 : 0;
|
off = im.sel >= Maxdisp ? im.sel - Maxdisp + 1 : 0;
|
||||||
if((mod & Malt) && n >= 0 && n < Maxdisp){
|
if(n >= 0 && n < Maxdisp && off + n < im.nkouho && mod == 0){
|
||||||
pickemoji(off + n, com);
|
pickemoji(off + n, com);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -454,8 +466,8 @@ keystroke(u32int ks, u32int mod, Str *com)
|
|||||||
int n, off;
|
int n, off;
|
||||||
Rune c;
|
Rune c;
|
||||||
|
|
||||||
if(ks == Ksuper || ks == Kshift)
|
if(ismodkey(ks))
|
||||||
return 1;
|
return 0;
|
||||||
if(search.on)
|
if(search.on)
|
||||||
return searchkey(ks, mod, com);
|
return searchkey(ks, mod, com);
|
||||||
if(ks == Kdown || ks == Kup){
|
if(ks == Kdown || ks == Kup){
|
||||||
@@ -568,6 +580,16 @@ imhandlekey(Keyreq *kr)
|
|||||||
chansend(kr->reply, &res);
|
chansend(kr->reply, &res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dictresult(Dictres *res)
|
||||||
|
{
|
||||||
|
if(search.on || res->lang != im.l->lang ||
|
||||||
|
scmp(&res->key, &im.pre) != 0)
|
||||||
|
return;
|
||||||
|
setkouho(res);
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
imthread(void*)
|
imthread(void*)
|
||||||
{
|
{
|
||||||
@@ -587,11 +609,7 @@ imthread(void*)
|
|||||||
imhandlekey(&kr);
|
imhandlekey(&kr);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if(!search.on && res.lang == im.l->lang &&
|
dictresult(&res);
|
||||||
scmp(&res.key, &im.pre) == 0){
|
|
||||||
setkouho(&res);
|
|
||||||
show();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ LIBS = -lthread -lbio
|
|||||||
|
|
||||||
PROG = unit_test
|
PROG = unit_test
|
||||||
TESTSRC = unit_test.c test_util.c str_test.c hash_test.c trie_test.c \
|
TESTSRC = unit_test.c test_util.c str_test.c hash_test.c trie_test.c \
|
||||||
ko_test.c vi_test.c engine_test.c dict_test.c
|
ko_test.c vi_test.c engine_test.c dict_test.c ipc_test.c
|
||||||
TESTOBJ = $(TESTSRC:.c=.o)
|
TESTOBJ = $(TESTSRC:.c=.o)
|
||||||
PARENTSRC = str.c hash.c trie.c dict.c ko.c vi.c
|
PARENTSRC = str.c hash.c trie.c dict.c ko.c vi.c ipc.c
|
||||||
PARENTOBJ = $(PARENTSRC:%.c=unit_%.o)
|
PARENTOBJ = $(PARENTSRC:%.c=unit_%.o)
|
||||||
OBJS = $(TESTOBJ) $(PARENTOBJ)
|
OBJS = $(TESTOBJ) $(PARENTOBJ)
|
||||||
|
|
||||||
|
|||||||
@@ -302,11 +302,19 @@ emojibegin(Emojifix *f, int showpre)
|
|||||||
f->popup = popup;
|
f->popup = popup;
|
||||||
f->visible = visible;
|
f->visible = visible;
|
||||||
draindraw(nil);
|
draindraw(nil);
|
||||||
l->dict = hmapalloc(8);
|
l->dict = hmapalloc(32);
|
||||||
|
setemoji(&l->dict, "a", "A B");
|
||||||
|
setemoji(&l->dict, "ㅁ", "B C");
|
||||||
setemoji(&l->dict, "alpha", "α");
|
setemoji(&l->dict, "alpha", "α");
|
||||||
setemoji(&l->dict, "smil", "😀 😄");
|
setemoji(&l->dict, "smil", "😀 😄");
|
||||||
setemoji(&l->dict, "smile", "😀 😄");
|
setemoji(&l->dict, "smile", "😀 😄");
|
||||||
setemoji(&l->dict, "웃음", "😀 😄 😂");
|
setemoji(&l->dict, "웃음", "😀 😄 😂");
|
||||||
|
setemoji(&l->dict, "^", "¹ ² ³ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹ ⁽");
|
||||||
|
setemoji(&l->dict, "^0", "⁰");
|
||||||
|
setemoji(&l->dict, "_", "₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉ ₍");
|
||||||
|
setemoji(&l->dict, "<", "← ≤ ♥ ≠");
|
||||||
|
setemoji(&l->dict, "many",
|
||||||
|
"c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12");
|
||||||
init();
|
init();
|
||||||
im.l = getlang(LangKO);
|
im.l = getlang(LangKO);
|
||||||
popup = showpre;
|
popup = showpre;
|
||||||
@@ -345,8 +353,10 @@ engine_emoji_single_candidate(struct ct *t)
|
|||||||
Emojifix f;
|
Emojifix f;
|
||||||
Str com;
|
Str com;
|
||||||
|
|
||||||
emojibegin(&f, 0);
|
emojibegin(&f, 1);
|
||||||
sclear(&com);
|
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, keystroke('e', Mctrl, &com));
|
||||||
CT_CHECK(t, search.on);
|
CT_CHECK(t, search.on);
|
||||||
CT_EQ_INT(t, LangKO, im.l->lang);
|
CT_EQ_INT(t, LangKO, im.l->lang);
|
||||||
@@ -363,6 +373,10 @@ engine_emoji_single_candidate(struct ct *t)
|
|||||||
checkstr(t, "explicit candidate commit", "α", &com);
|
checkstr(t, "explicit candidate commit", "α", &com);
|
||||||
CT_CHECK(t, !search.on);
|
CT_CHECK(t, !search.on);
|
||||||
CT_EQ_INT(t, LangKO, im.l->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);
|
emojiend(&f);
|
||||||
}
|
}
|
||||||
@@ -376,6 +390,18 @@ engine_emoji_queries(struct ct *t)
|
|||||||
|
|
||||||
emojibegin(&f, 1);
|
emojibegin(&f, 1);
|
||||||
sclear(&com);
|
sclear(&com);
|
||||||
|
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
||||||
|
CT_CHECK(t, keystroke('a', 0, &com));
|
||||||
|
checkstr(t, "raw query wins", "a", &search.text);
|
||||||
|
CT_EQ_INT(t, 3, im.nkouho);
|
||||||
|
checkstr(t, "raw candidate", "A", &im.kouho[0]);
|
||||||
|
checkstr(t, "deduplicated candidate", "B", &im.kouho[1]);
|
||||||
|
checkstr(t, "local candidate", "C", &im.kouho[2]);
|
||||||
|
CT_CHECK(t, draindraw(&dc) > 0);
|
||||||
|
checkstr(t, "prefix popup query", "a", &dc.pre);
|
||||||
|
CT_EQ_INT(t, 3, dc.nkouho);
|
||||||
|
CT_CHECK(t, keystroke(Kesc, 0, &com));
|
||||||
|
|
||||||
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
||||||
if(typekeys(t, "smile", &com)){
|
if(typekeys(t, "smile", &com)){
|
||||||
checkstr(t, "English alias", "smile", &search.text);
|
checkstr(t, "English alias", "smile", &search.text);
|
||||||
@@ -384,11 +410,19 @@ engine_emoji_queries(struct ct *t)
|
|||||||
checkstr(t, "backspaced query", "smil", &search.text);
|
checkstr(t, "backspaced query", "smil", &search.text);
|
||||||
CT_EQ_INT(t, 2, im.nkouho);
|
CT_EQ_INT(t, 2, im.nkouho);
|
||||||
CT_CHECK(t, keystroke('e', 0, &com));
|
CT_CHECK(t, keystroke('e', 0, &com));
|
||||||
CT_CHECK(t, keystroke('2', Malt, &com));
|
CT_CHECK(t, keystroke('2', 0, &com));
|
||||||
checkstr(t, "selected English alias", "😄", &com);
|
checkstr(t, "selected English alias", "😄", &com);
|
||||||
CT_EQ_INT(t, LangKO, im.l->lang);
|
CT_EQ_INT(t, LangKO, im.l->lang);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sclear(&com);
|
||||||
|
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
||||||
|
if(typekeys(t, "SMILE", &com)){
|
||||||
|
checkstr(t, "folded English alias", "smile", &search.text);
|
||||||
|
CT_EQ_INT(t, 2, im.nkouho);
|
||||||
|
CT_CHECK(t, keystroke(Kesc, 0, &com));
|
||||||
|
}
|
||||||
|
|
||||||
sclear(&com);
|
sclear(&com);
|
||||||
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
||||||
if(typekeys(t, "dntdma", &com)){
|
if(typekeys(t, "dntdma", &com)){
|
||||||
@@ -405,11 +439,187 @@ engine_emoji_queries(struct ct *t)
|
|||||||
emojiend(&f);
|
emojiend(&f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
engine_emoji_digit_aliases(struct ct *t)
|
||||||
|
{
|
||||||
|
static const struct {
|
||||||
|
char *name;
|
||||||
|
Rune prefix;
|
||||||
|
Rune digit;
|
||||||
|
char *want;
|
||||||
|
} cases[] = {
|
||||||
|
{ "^1", '^', '1', "¹" },
|
||||||
|
{ "_2", '_', '2', "₂" },
|
||||||
|
{ "<3", '<', '3', "♥" },
|
||||||
|
};
|
||||||
|
Emojifix f;
|
||||||
|
Str com;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
emojibegin(&f, 0);
|
||||||
|
for(i = 0; i < nelem(cases); i++){
|
||||||
|
sclear(&com);
|
||||||
|
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
||||||
|
CT_CHECK(t, keystroke(cases[i].prefix, Mshift, &com));
|
||||||
|
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.on);
|
||||||
|
CT_EQ_INT(t, LangKO, im.l->lang);
|
||||||
|
}
|
||||||
|
|
||||||
|
sclear(&com);
|
||||||
|
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
||||||
|
CT_CHECK(t, keystroke('^', Mshift, &com));
|
||||||
|
CT_CHECK(t, keystroke('0', 0, &com));
|
||||||
|
checkstr(t, "zero query", "^0", &search.text);
|
||||||
|
checkstr(t, "zero does not commit", "", &com);
|
||||||
|
CT_EQ_INT(t, 1, im.nkouho);
|
||||||
|
CT_CHECK(t, keystroke(Kret, 0, &com));
|
||||||
|
checkstr(t, "zero alias", "⁰", &com);
|
||||||
|
|
||||||
|
sclear(&com);
|
||||||
|
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
||||||
|
if(typekeys(t, "smile", &com)){
|
||||||
|
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.on);
|
||||||
|
CT_EQ_INT(t, 0, im.nkouho);
|
||||||
|
CT_CHECK(t, keystroke(Kret, 0, &com));
|
||||||
|
checkstr(t, "missing number text", "smile9", &com);
|
||||||
|
}
|
||||||
|
emojiend(&f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
engine_emoji_navigation(struct ct *t)
|
||||||
|
{
|
||||||
|
Drawcmd dc = {0};
|
||||||
|
Emojifix f;
|
||||||
|
Str com;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
emojibegin(&f, 0);
|
||||||
|
sclear(&com);
|
||||||
|
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
||||||
|
if(typekeys(t, "many", &com)){
|
||||||
|
CT_EQ_INT(t, 12, im.nkouho);
|
||||||
|
for(i = 0; i < Maxdisp+1; i++)
|
||||||
|
CT_CHECK(t, keystroke(Kdown, 0, &com));
|
||||||
|
CT_EQ_INT(t, Maxdisp, im.sel);
|
||||||
|
CT_CHECK(t, draindraw(&dc) > 0);
|
||||||
|
checkstr(t, "scrolled first row", "c2", &dc.kouho[0]);
|
||||||
|
checkstr(t, "scrolled ninth row", "c10", &dc.kouho[8]);
|
||||||
|
CT_EQ_INT(t, 8, dc.sel);
|
||||||
|
CT_CHECK(t, keystroke('1', 0, &com));
|
||||||
|
checkstr(t, "scrolled row one", "c2", &com);
|
||||||
|
}
|
||||||
|
|
||||||
|
sclear(&com);
|
||||||
|
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
||||||
|
if(typekeys(t, "many", &com)){
|
||||||
|
for(i = 0; i < 12; i++)
|
||||||
|
CT_CHECK(t, keystroke(Kdown, 0, &com));
|
||||||
|
CT_EQ_INT(t, 11, im.sel);
|
||||||
|
CT_CHECK(t, keystroke('9', 0, &com));
|
||||||
|
checkstr(t, "scrolled row nine", "c12", &com);
|
||||||
|
}
|
||||||
|
|
||||||
|
sclear(&com);
|
||||||
|
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
||||||
|
if(typekeys(t, "smile", &com)){
|
||||||
|
CT_CHECK(t, keystroke(Ktab, 0, &com));
|
||||||
|
CT_EQ_INT(t, 0, im.sel);
|
||||||
|
CT_CHECK(t, keystroke(Kdown, 0, &com));
|
||||||
|
CT_EQ_INT(t, 1, im.sel);
|
||||||
|
CT_CHECK(t, keystroke(Kup, 0, &com));
|
||||||
|
CT_EQ_INT(t, 0, im.sel);
|
||||||
|
CT_CHECK(t, keystroke(Ktab, Mshift, &com));
|
||||||
|
CT_EQ_INT(t, 1, im.sel);
|
||||||
|
CT_CHECK(t, keystroke(Kret, 0, &com));
|
||||||
|
checkstr(t, "navigated candidate", "😄", &com);
|
||||||
|
}
|
||||||
|
emojiend(&f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
engine_emoji_preedit_languages(struct ct *t)
|
||||||
|
{
|
||||||
|
Emojifix f;
|
||||||
|
Str com, shown;
|
||||||
|
int p;
|
||||||
|
|
||||||
|
emojibegin(&f, 0);
|
||||||
|
init();
|
||||||
|
im.l = getlang(LangJP);
|
||||||
|
sclear(&com);
|
||||||
|
if(typekeys(t, "ka", &com)){
|
||||||
|
CT_CHECK(t, !keystroke(Kmodfirst+2, 0, &com));
|
||||||
|
checkstr(t, "modifier preserves Japanese", "ka", &im.pre);
|
||||||
|
CT_CHECK(t, keystroke('E', Mctrl|Mshift, &com));
|
||||||
|
checkstr(t, "committed Japanese preedit", "か", &com);
|
||||||
|
CT_CHECK(t, search.on);
|
||||||
|
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.on);
|
||||||
|
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.on);
|
||||||
|
CT_CHECK(t, !keystroke(Kmodfirst+2, 0, &com));
|
||||||
|
CT_CHECK(t, keystroke('E', Mctrl|Mshift, &com));
|
||||||
|
CT_CHECK(t, !search.on);
|
||||||
|
sclear(&com);
|
||||||
|
if(typekeys(t, "na", &com)){
|
||||||
|
shown = shownpre(&im);
|
||||||
|
checkstr(t, "Japanese resumed", "な", &shown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init();
|
||||||
|
im.l = getlang(LangKO);
|
||||||
|
sclear(&com);
|
||||||
|
if(typekeys(t, "rk", &com)){
|
||||||
|
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
||||||
|
checkstr(t, "committed Korean preedit", "가", &com);
|
||||||
|
if(typekeys(t, "smile", &com)){
|
||||||
|
CT_CHECK(t, keystroke('1', 0, &com));
|
||||||
|
checkstr(t, "Korean selection", "가😀", &com);
|
||||||
|
sclear(&com);
|
||||||
|
if(typekeys(t, "rk", &com))
|
||||||
|
checkstr(t, "Korean resumed", "가", &im.pre);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init();
|
||||||
|
im.l = &testvi;
|
||||||
|
sclear(&com);
|
||||||
|
if(typekeys(t, "as", &com)){
|
||||||
|
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
||||||
|
checkstr(t, "committed Telex preedit", "á", &com);
|
||||||
|
CT_CHECK(t, keystroke(Kesc, 0, &com));
|
||||||
|
CT_CHECK(t, !search.on);
|
||||||
|
CT_EQ_PTR(t, &testvi, im.l);
|
||||||
|
sclear(&com);
|
||||||
|
if(typekeys(t, "as", &com)){
|
||||||
|
shown = shownpre(&im);
|
||||||
|
checkstr(t, "Telex resumed", "á", &shown);
|
||||||
|
checkstr(t, "Telex raw resumed", "as", &im.raw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emojiend(&f);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
engine_emoji_start_and_unknown(struct ct *t)
|
engine_emoji_start_and_unknown(struct ct *t)
|
||||||
{
|
{
|
||||||
Emojifix f;
|
Emojifix f;
|
||||||
Str com;
|
Str com;
|
||||||
|
char want[Maxrunes+1];
|
||||||
|
int i;
|
||||||
|
|
||||||
emojibegin(&f, 0);
|
emojibegin(&f, 0);
|
||||||
sclear(&com);
|
sclear(&com);
|
||||||
@@ -427,5 +637,67 @@ engine_emoji_start_and_unknown(struct ct *t)
|
|||||||
CT_EQ_INT(t, LangKO, im.l->lang);
|
CT_EQ_INT(t, LangKO, im.l->lang);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sclear(&com);
|
||||||
|
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
||||||
|
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.on);
|
||||||
|
CT_EQ_INT(t, LangKO, im.l->lang);
|
||||||
|
}
|
||||||
|
|
||||||
|
sclear(&com);
|
||||||
|
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
||||||
|
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.on);
|
||||||
|
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.on);
|
||||||
|
emojiend(&f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
engine_emoji_dictionary_identity(struct ct *t)
|
||||||
|
{
|
||||||
|
Dictres res;
|
||||||
|
Emojifix f;
|
||||||
|
|
||||||
|
emojibegin(&f, 0);
|
||||||
|
im.pre = mkstr("same");
|
||||||
|
im.kouho[0] = mkstr("old");
|
||||||
|
im.nkouho = 1;
|
||||||
|
im.sel = 0;
|
||||||
|
memset(&res, 0, sizeof res);
|
||||||
|
res.key = im.pre;
|
||||||
|
res.kouho[0] = mkstr("wrong");
|
||||||
|
res.nkouho = 1;
|
||||||
|
res.lang = LangJP;
|
||||||
|
dictresult(&res);
|
||||||
|
CT_EQ_INT(t, 1, im.nkouho);
|
||||||
|
checkstr(t, "wrong language ignored", "old", &im.kouho[0]);
|
||||||
|
|
||||||
|
res.lang = LangKO;
|
||||||
|
res.key = mkstr("other");
|
||||||
|
dictresult(&res);
|
||||||
|
CT_EQ_INT(t, 1, im.nkouho);
|
||||||
|
checkstr(t, "wrong preedit ignored", "old", &im.kouho[0]);
|
||||||
|
|
||||||
|
res.key = im.pre;
|
||||||
|
search.on = 1;
|
||||||
|
dictresult(&res);
|
||||||
|
CT_EQ_INT(t, 1, im.nkouho);
|
||||||
|
checkstr(t, "search response ignored", "old", &im.kouho[0]);
|
||||||
|
|
||||||
|
search.on = 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);
|
emojiend(&f);
|
||||||
}
|
}
|
||||||
|
|||||||
15
tests/ipc_test.c
Normal file
15
tests/ipc_test.c
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
ipc_masks_modifiers(struct ct *t)
|
||||||
|
{
|
||||||
|
uchar buf[Ipcreqsz];
|
||||||
|
u32int key, mod;
|
||||||
|
int want;
|
||||||
|
|
||||||
|
ipcpackreq(buf, 1, Mctrl|Malt|(1<<1)|(1<<4)|(1<<7), 0x1f642);
|
||||||
|
ipcunpackreq(buf, &want, &mod, &key);
|
||||||
|
CT_EQ_INT(t, 1, want);
|
||||||
|
CT_EQ_UINT(t, Mctrl|Malt, mod);
|
||||||
|
CT_EQ_UINT(t, 0x1f642, key);
|
||||||
|
}
|
||||||
85
tests/mkemoji_test.py
Normal file
85
tests/mkemoji_test.py
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
MKEMOJI = ROOT / "map" / "mkemoji"
|
||||||
|
|
||||||
|
|
||||||
|
def generate(source=None):
|
||||||
|
args = [sys.executable, "-B", str(MKEMOJI)]
|
||||||
|
if source is not None:
|
||||||
|
args.append(str(source))
|
||||||
|
return subprocess.run(args, capture_output=True, text=True, check=False)
|
||||||
|
|
||||||
|
|
||||||
|
def table(output):
|
||||||
|
return dict(line.split("\t", 1) for line in output.splitlines())
|
||||||
|
|
||||||
|
|
||||||
|
class MkemojiTest(unittest.TestCase):
|
||||||
|
def source(self, text):
|
||||||
|
tmp = tempfile.TemporaryDirectory()
|
||||||
|
path = Path(tmp.name) / "emoji.src"
|
||||||
|
path.write_text(text, encoding="utf-8")
|
||||||
|
self.addCleanup(tmp.cleanup)
|
||||||
|
return path
|
||||||
|
|
||||||
|
def test_production_digit_slots(self):
|
||||||
|
result = generate()
|
||||||
|
self.assertEqual(result.returncode, 0, result.stderr)
|
||||||
|
data = table(result.stdout)
|
||||||
|
self.assertEqual(data["^"].split()[:9], list("¹²³⁴⁵⁶⁷⁸⁹"))
|
||||||
|
self.assertEqual(data["_"].split()[:9], list("₁₂₃₄₅₆₇₈₉"))
|
||||||
|
self.assertEqual(data["<"].split()[2], "♥")
|
||||||
|
self.assertEqual(data["^1"], "¹")
|
||||||
|
self.assertEqual(data["_2"], "₂")
|
||||||
|
self.assertEqual(data["<3"], "♥")
|
||||||
|
|
||||||
|
def test_fold_normalize_and_exact_first(self):
|
||||||
|
source = self.source(
|
||||||
|
"β\tALPHABET\n"
|
||||||
|
"α\talpha\n"
|
||||||
|
"e\u0301\tE\u0301\n"
|
||||||
|
"#\thash\n"
|
||||||
|
)
|
||||||
|
first = generate(source)
|
||||||
|
second = generate(source)
|
||||||
|
self.assertEqual(first.returncode, 0, first.stderr)
|
||||||
|
self.assertEqual(first.stdout, second.stdout)
|
||||||
|
data = table(first.stdout)
|
||||||
|
self.assertEqual(data["alpha"].split(), ["α", "β"])
|
||||||
|
self.assertEqual(data["al"].split(), ["β", "α"])
|
||||||
|
self.assertEqual(data["é"], "é")
|
||||||
|
self.assertEqual(data["hash"], "#")
|
||||||
|
|
||||||
|
def test_rejects_malformed_and_oversized_rows(self):
|
||||||
|
bad = [
|
||||||
|
"x\n",
|
||||||
|
"bad result\ta\n",
|
||||||
|
"x\t\n",
|
||||||
|
"x\t a\n",
|
||||||
|
"\0\ta\n",
|
||||||
|
"x\ta\0b\n",
|
||||||
|
"x" * 65 + "\ta\n",
|
||||||
|
"x\t" + "a" * 65 + "\n",
|
||||||
|
]
|
||||||
|
for text in bad:
|
||||||
|
with self.subTest(text=repr(text)):
|
||||||
|
result = generate(self.source(text))
|
||||||
|
self.assertEqual(result.returncode, 1)
|
||||||
|
|
||||||
|
def test_accepts_runtime_boundary(self):
|
||||||
|
source = self.source("x" * 64 + "\t" + "a" * 64 + "\n")
|
||||||
|
result = generate(source)
|
||||||
|
self.assertEqual(result.returncode, 0, result.stderr)
|
||||||
|
self.assertIn("a" * 64 + "\t" + "x" * 64, result.stdout)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
@@ -35,8 +35,13 @@ void engine_language_switch_state(struct ct*);
|
|||||||
void engine_telex_history_bound(struct ct*);
|
void engine_telex_history_bound(struct ct*);
|
||||||
void engine_emoji_single_candidate(struct ct*);
|
void engine_emoji_single_candidate(struct ct*);
|
||||||
void engine_emoji_queries(struct ct*);
|
void engine_emoji_queries(struct ct*);
|
||||||
|
void engine_emoji_digit_aliases(struct ct*);
|
||||||
|
void engine_emoji_navigation(struct ct*);
|
||||||
|
void engine_emoji_preedit_languages(struct ct*);
|
||||||
void engine_emoji_start_and_unknown(struct ct*);
|
void engine_emoji_start_and_unknown(struct ct*);
|
||||||
|
void engine_emoji_dictionary_identity(struct ct*);
|
||||||
void dictionary_candidates(struct ct*);
|
void dictionary_candidates(struct ct*);
|
||||||
void dictionary_misses_clear_result(struct ct*);
|
void dictionary_misses_clear_result(struct ct*);
|
||||||
|
void ipc_masks_modifiers(struct ct*);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -82,9 +82,14 @@ static const struct ct_test tests[] = {
|
|||||||
{ "engine/telex-history-bound", engine_telex_history_bound },
|
{ "engine/telex-history-bound", engine_telex_history_bound },
|
||||||
{ "engine/emoji-single-candidate", engine_emoji_single_candidate },
|
{ "engine/emoji-single-candidate", engine_emoji_single_candidate },
|
||||||
{ "engine/emoji-queries", engine_emoji_queries },
|
{ "engine/emoji-queries", engine_emoji_queries },
|
||||||
|
{ "engine/emoji-digit-aliases", engine_emoji_digit_aliases },
|
||||||
|
{ "engine/emoji-navigation", engine_emoji_navigation },
|
||||||
|
{ "engine/emoji-preedit-languages", engine_emoji_preedit_languages },
|
||||||
{ "engine/emoji-start-and-unknown", engine_emoji_start_and_unknown },
|
{ "engine/emoji-start-and-unknown", engine_emoji_start_and_unknown },
|
||||||
|
{ "engine/emoji-dictionary-identity", engine_emoji_dictionary_identity },
|
||||||
{ "dict/candidates", dictionary_candidates },
|
{ "dict/candidates", dictionary_candidates },
|
||||||
{ "dict/misses-clear-result", dictionary_misses_clear_result },
|
{ "dict/misses-clear-result", dictionary_misses_clear_result },
|
||||||
|
{ "ipc/masks-modifiers", ipc_masks_modifiers },
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -92,7 +97,7 @@ threadmain(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
int i, status;
|
int i, status;
|
||||||
|
|
||||||
drawc = chancreate(sizeof(Drawcmd), 1024);
|
drawc = chancreate(sizeof(Drawcmd), 4);
|
||||||
keyc = chancreate(sizeof(Keyreq), 0);
|
keyc = chancreate(sizeof(Keyreq), 0);
|
||||||
dictreqc = chancreate(sizeof(Dictreq), 64);
|
dictreqc = chancreate(sizeof(Dictreq), 64);
|
||||||
dictresc = chancreate(sizeof(Dictres), 0);
|
dictresc = chancreate(sizeof(Dictres), 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user