emoji: add one-shot candidate search
This commit is contained in:
1
Makefile
1
Makefile
@@ -42,5 +42,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
|
||||||
|
|
||||||
.PHONY: all check test verify-map clean xim bench
|
.PHONY: all check test verify-map clean xim bench
|
||||||
|
|||||||
24
README.md
24
README.md
@@ -66,12 +66,32 @@ Switch input modes with Ctrl + key:
|
|||||||
S Hangul
|
S Hangul
|
||||||
T English
|
T English
|
||||||
V Vietnamese (Telex)
|
V Vietnamese (Telex)
|
||||||
E Emoji
|
P Toggle preedit echo
|
||||||
P Toggle preedit/candidate popup window
|
|
||||||
|
|
||||||
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.
|
Tab or Enter to commit.
|
||||||
|
|
||||||
|
### Emoji and symbols
|
||||||
|
|
||||||
|
Ctrl+E starts a one-shot symbol search; it is not a mode. Any current preedit
|
||||||
|
is committed, then the previous language is kept for the next input. Type an
|
||||||
|
English alias or the phonetic keys of the current layout (Korean aliases work,
|
||||||
|
for example). The candidate list is shown even when Ctrl+P has hidden normal
|
||||||
|
preedit echo.
|
||||||
|
|
||||||
|
안녕 → Ctrl+E → smile → Enter → 😀
|
||||||
|
|
||||||
|
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
|
||||||
|
digits are part of the query.
|
||||||
|
|
||||||
|
`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
|
||||||
|
`map/mkemoji > map/emoji.dict` after editing it; `make verify-map` checks the
|
||||||
|
generated dictionary and the Telex map.
|
||||||
|
|
||||||
|
😀 웃음 웃다 스마일 smile grin
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
Threads communicate via CSP channels:
|
Threads communicate via CSP channels:
|
||||||
|
|||||||
1
dat.h
1
dat.h
@@ -156,6 +156,7 @@ struct Dictres
|
|||||||
Str key;
|
Str key;
|
||||||
Str kouho[Maxkouho];
|
Str kouho[Maxkouho];
|
||||||
int nkouho;
|
int nkouho;
|
||||||
|
int lang;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Lang langs[];
|
extern Lang langs[];
|
||||||
|
|||||||
1
dict.c
1
dict.c
@@ -12,6 +12,7 @@ dictlookup(Dictreq *req, Dictres *res)
|
|||||||
|
|
||||||
res->key = req->pre;
|
res->key = req->pre;
|
||||||
res->nkouho = 0;
|
res->nkouho = 0;
|
||||||
|
res->lang = req->lang;
|
||||||
if(req->key.n == 0)
|
if(req->key.n == 0)
|
||||||
return;
|
return;
|
||||||
l = getlang(req->lang);
|
l = getlang(req->lang);
|
||||||
|
|||||||
226
map/emoji.dict
226
map/emoji.dict
@@ -0,0 +1,226 @@
|
|||||||
|
! ⚠ ≠
|
||||||
|
!! ⚠
|
||||||
|
!= ≠
|
||||||
|
* ★
|
||||||
|
** ★
|
||||||
|
+ ±
|
||||||
|
+- ±
|
||||||
|
- →
|
||||||
|
-> →
|
||||||
|
. · … ÷
|
||||||
|
.. · …
|
||||||
|
... …
|
||||||
|
./ ÷
|
||||||
|
: ☹ ☺
|
||||||
|
:( ☹
|
||||||
|
:) ☺
|
||||||
|
< ← ≤ ≠ ♥
|
||||||
|
<- ←
|
||||||
|
<3 ♥
|
||||||
|
<= ≤
|
||||||
|
<> ≠
|
||||||
|
= ≡ ⇒
|
||||||
|
== ≡
|
||||||
|
=> ⇒
|
||||||
|
> ≥
|
||||||
|
>= ≥
|
||||||
|
^ ⁽ ⁾ ⁺ ⁻ ⁼ ⁰ ¹ ² ³ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹ ⁱ ⁿ
|
||||||
|
^( ⁽
|
||||||
|
^) ⁾
|
||||||
|
^+ ⁺
|
||||||
|
^- ⁻
|
||||||
|
^0 ⁰
|
||||||
|
^1 ¹
|
||||||
|
^2 ²
|
||||||
|
^3 ³
|
||||||
|
^4 ⁴
|
||||||
|
^5 ⁵
|
||||||
|
^6 ⁶
|
||||||
|
^7 ⁷
|
||||||
|
^8 ⁸
|
||||||
|
^9 ⁹
|
||||||
|
^= ⁼
|
||||||
|
^i ⁱ
|
||||||
|
^n ⁿ
|
||||||
|
_ ₍ ₎ ₊ ₋ ₌ ₀ ₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉ ₐ ₑ ₒ ₓ
|
||||||
|
_( ₍
|
||||||
|
_) ₎
|
||||||
|
_+ ₊
|
||||||
|
_- ₋
|
||||||
|
_0 ₀
|
||||||
|
_1 ₁
|
||||||
|
_2 ₂
|
||||||
|
_3 ₃
|
||||||
|
_4 ₄
|
||||||
|
_5 ₅
|
||||||
|
_6 ₆
|
||||||
|
_7 ₇
|
||||||
|
_8 ₈
|
||||||
|
_9 ₉
|
||||||
|
_= ₌
|
||||||
|
_a ₐ
|
||||||
|
_e ₑ
|
||||||
|
_o ₒ
|
||||||
|
_x ₓ
|
||||||
|
a α
|
||||||
|
al α
|
||||||
|
alp α
|
||||||
|
alph α
|
||||||
|
alpha α
|
||||||
|
b β 😊
|
||||||
|
be β
|
||||||
|
bet β
|
||||||
|
beta β
|
||||||
|
bl 😊
|
||||||
|
blu 😊
|
||||||
|
blus 😊
|
||||||
|
blush 😊
|
||||||
|
c χ
|
||||||
|
ch χ
|
||||||
|
chi χ
|
||||||
|
d ° δ Δ ↓
|
||||||
|
de Δ ° δ
|
||||||
|
deg °
|
||||||
|
del δ
|
||||||
|
delt δ
|
||||||
|
delta δ
|
||||||
|
dn ↓
|
||||||
|
e ε η
|
||||||
|
ep ε
|
||||||
|
eps ε
|
||||||
|
et η
|
||||||
|
eta η
|
||||||
|
f 凸
|
||||||
|
fu 凸
|
||||||
|
fuc 凸
|
||||||
|
fuck 凸
|
||||||
|
g γ Γ 😀
|
||||||
|
ga Γ γ
|
||||||
|
gam γ
|
||||||
|
gamm γ
|
||||||
|
gamma γ
|
||||||
|
gr 😀
|
||||||
|
gri 😀
|
||||||
|
grin 😀
|
||||||
|
h 😄 😊 ❤️
|
||||||
|
ha 😄 😊
|
||||||
|
hap 😄 😊
|
||||||
|
happ 😄 😊
|
||||||
|
happy 😄 😊
|
||||||
|
he ❤️
|
||||||
|
hea ❤️
|
||||||
|
hear ❤️
|
||||||
|
heart ❤️
|
||||||
|
i ∫ ∞ ι
|
||||||
|
ii ∫
|
||||||
|
in ∞
|
||||||
|
inf ∞
|
||||||
|
io ι
|
||||||
|
iot ι
|
||||||
|
iota ι
|
||||||
|
j 😂
|
||||||
|
jo 😂
|
||||||
|
joy 😂
|
||||||
|
k κ
|
||||||
|
ka κ
|
||||||
|
kap κ
|
||||||
|
kapp κ
|
||||||
|
kappa κ
|
||||||
|
l λ Λ 😂 ❤️ 👍
|
||||||
|
la Λ λ
|
||||||
|
lam λ
|
||||||
|
lamb λ
|
||||||
|
lambd λ
|
||||||
|
lambda λ
|
||||||
|
li 👍
|
||||||
|
lik 👍
|
||||||
|
like 👍
|
||||||
|
lo 😂 ❤️
|
||||||
|
lol 😂
|
||||||
|
lov ❤️
|
||||||
|
love ❤️
|
||||||
|
m × μ
|
||||||
|
mu μ ×
|
||||||
|
mul ×
|
||||||
|
n ν
|
||||||
|
nu ν
|
||||||
|
o ω Ω ●
|
||||||
|
om Ω ω
|
||||||
|
ome ω
|
||||||
|
omeg ω
|
||||||
|
omega ω
|
||||||
|
oo ●
|
||||||
|
p φ Φ π Π ∏ ψ Ψ
|
||||||
|
ph Φ φ
|
||||||
|
phi φ
|
||||||
|
pi π Π
|
||||||
|
pp ∏
|
||||||
|
ps Ψ ψ
|
||||||
|
psi ψ
|
||||||
|
r ρ
|
||||||
|
rh ρ
|
||||||
|
rho ρ
|
||||||
|
s σ Σ √ ∑ 😀 😄 😊
|
||||||
|
si Σ σ
|
||||||
|
sig σ
|
||||||
|
sigm σ
|
||||||
|
sigma σ
|
||||||
|
sm 😀 😄 😊
|
||||||
|
smi 😀 😄 😊
|
||||||
|
smil 😀 😄 😊
|
||||||
|
smile 😀 😄 😊
|
||||||
|
sq √
|
||||||
|
ss ∑
|
||||||
|
t τ θ Θ 👍
|
||||||
|
ta τ
|
||||||
|
tau τ
|
||||||
|
th Θ θ 👍
|
||||||
|
the θ
|
||||||
|
thet θ
|
||||||
|
theta θ
|
||||||
|
thu 👍
|
||||||
|
thum 👍
|
||||||
|
thumb 👍
|
||||||
|
thumbs 👍
|
||||||
|
thumbsu 👍
|
||||||
|
thumbsup 👍
|
||||||
|
u ↑ υ
|
||||||
|
up ↑ υ
|
||||||
|
ups υ
|
||||||
|
v ✓
|
||||||
|
vv ✓
|
||||||
|
x ξ Ξ ✗
|
||||||
|
xi ξ Ξ
|
||||||
|
xx ✗
|
||||||
|
z ζ
|
||||||
|
ze ζ
|
||||||
|
zet ζ
|
||||||
|
zeta ζ
|
||||||
|
~ ≈
|
||||||
|
~= ≈
|
||||||
|
따 👍
|
||||||
|
따봉 👍
|
||||||
|
미 😄 😊
|
||||||
|
미소 😄 😊
|
||||||
|
방 😊
|
||||||
|
방긋 😊
|
||||||
|
사 ❤️
|
||||||
|
사랑 ❤️
|
||||||
|
스 😀 😄
|
||||||
|
스마 😀 😄
|
||||||
|
스마일 😀 😄
|
||||||
|
엄 👍
|
||||||
|
엄지 👍
|
||||||
|
웃 😀 😄 😂
|
||||||
|
웃겨 😂
|
||||||
|
웃다 😀
|
||||||
|
웃음 😀 😄 😂
|
||||||
|
좋 👍
|
||||||
|
좋아 👍
|
||||||
|
좋아요 👍
|
||||||
|
찬 👍
|
||||||
|
찬성 👍
|
||||||
|
폭 😂
|
||||||
|
폭소 😂
|
||||||
|
하 ❤️
|
||||||
|
하트 ❤️
|
||||||
|
|||||||
183
map/emoji.map
183
map/emoji.map
@@ -1,183 +0,0 @@
|
|||||||
! !
|
|
||||||
!! ⚠
|
|
||||||
!= ≠
|
|
||||||
* *
|
|
||||||
** ★
|
|
||||||
+ +
|
|
||||||
+- ±
|
|
||||||
- -
|
|
||||||
-> →
|
|
||||||
. .
|
|
||||||
.. ·
|
|
||||||
... …
|
|
||||||
./ ÷
|
|
||||||
: :
|
|
||||||
:( ☹
|
|
||||||
:) ☺
|
|
||||||
< <
|
|
||||||
<- ←
|
|
||||||
<3 ♥
|
|
||||||
<= ≤
|
|
||||||
<> ≠
|
|
||||||
= =
|
|
||||||
== ≡
|
|
||||||
=> ⇒
|
|
||||||
> >
|
|
||||||
>= ≥
|
|
||||||
D D
|
|
||||||
De Δ
|
|
||||||
G G
|
|
||||||
Ga Γ
|
|
||||||
I I
|
|
||||||
II ∫
|
|
||||||
L L
|
|
||||||
La Λ
|
|
||||||
O O
|
|
||||||
Om Ω
|
|
||||||
P P
|
|
||||||
PP ∏
|
|
||||||
Ph Φ
|
|
||||||
Pi Π
|
|
||||||
Ps Ψ
|
|
||||||
S S
|
|
||||||
SS ∑
|
|
||||||
Si Σ
|
|
||||||
T T
|
|
||||||
Th Θ
|
|
||||||
X X
|
|
||||||
Xi Ξ
|
|
||||||
^ ^
|
|
||||||
^( ⁽
|
|
||||||
^) ⁾
|
|
||||||
^+ ⁺
|
|
||||||
^- ⁻
|
|
||||||
^0 ⁰
|
|
||||||
^1 ¹
|
|
||||||
^2 ²
|
|
||||||
^3 ³
|
|
||||||
^4 ⁴
|
|
||||||
^5 ⁵
|
|
||||||
^6 ⁶
|
|
||||||
^7 ⁷
|
|
||||||
^8 ⁸
|
|
||||||
^9 ⁹
|
|
||||||
^= ⁼
|
|
||||||
^i ⁱ
|
|
||||||
^n ⁿ
|
|
||||||
_ _
|
|
||||||
_( ₍
|
|
||||||
_) ₎
|
|
||||||
_+ ₊
|
|
||||||
_- ₋
|
|
||||||
_0 ₀
|
|
||||||
_1 ₁
|
|
||||||
_2 ₂
|
|
||||||
_3 ₃
|
|
||||||
_4 ₄
|
|
||||||
_5 ₅
|
|
||||||
_6 ₆
|
|
||||||
_7 ₇
|
|
||||||
_8 ₈
|
|
||||||
_9 ₉
|
|
||||||
_= ₌
|
|
||||||
_a ₐ
|
|
||||||
_e ₑ
|
|
||||||
_o ₒ
|
|
||||||
_x ₓ
|
|
||||||
a a
|
|
||||||
al al
|
|
||||||
alp alp
|
|
||||||
alph alph
|
|
||||||
alpha α
|
|
||||||
b b
|
|
||||||
be be
|
|
||||||
bet bet
|
|
||||||
beta β
|
|
||||||
c c
|
|
||||||
ch ch
|
|
||||||
chi χ
|
|
||||||
d d
|
|
||||||
de de
|
|
||||||
deg °
|
|
||||||
del del
|
|
||||||
delt delt
|
|
||||||
delta δ
|
|
||||||
dn ↓
|
|
||||||
e e
|
|
||||||
ep ep
|
|
||||||
eps ε
|
|
||||||
et et
|
|
||||||
eta η
|
|
||||||
f f
|
|
||||||
fu fu
|
|
||||||
fuc fuc
|
|
||||||
fuck 凸
|
|
||||||
g g
|
|
||||||
ga ga
|
|
||||||
gam gam
|
|
||||||
gamm gamm
|
|
||||||
gamma γ
|
|
||||||
i i
|
|
||||||
in in
|
|
||||||
inf ∞
|
|
||||||
io io
|
|
||||||
iot iot
|
|
||||||
iota ι
|
|
||||||
k k
|
|
||||||
ka ka
|
|
||||||
kap kap
|
|
||||||
kapp kapp
|
|
||||||
kappa κ
|
|
||||||
l l
|
|
||||||
la la
|
|
||||||
lam lam
|
|
||||||
lamb lamb
|
|
||||||
lambd lambd
|
|
||||||
lambda λ
|
|
||||||
m m
|
|
||||||
mu μ
|
|
||||||
mul ×
|
|
||||||
n n
|
|
||||||
nu ν
|
|
||||||
o o
|
|
||||||
om om
|
|
||||||
ome ome
|
|
||||||
omeg omeg
|
|
||||||
omega ω
|
|
||||||
oo ●
|
|
||||||
p p
|
|
||||||
ph ph
|
|
||||||
phi φ
|
|
||||||
pi π
|
|
||||||
ps ps
|
|
||||||
psi ψ
|
|
||||||
r r
|
|
||||||
rh rh
|
|
||||||
rho ρ
|
|
||||||
s s
|
|
||||||
si si
|
|
||||||
sig sig
|
|
||||||
sigm sigm
|
|
||||||
sigma σ
|
|
||||||
sq √
|
|
||||||
t t
|
|
||||||
ta ta
|
|
||||||
tau τ
|
|
||||||
th th
|
|
||||||
the the
|
|
||||||
thet thet
|
|
||||||
theta θ
|
|
||||||
u u
|
|
||||||
up ↑
|
|
||||||
ups υ
|
|
||||||
v v
|
|
||||||
vv ✓
|
|
||||||
x x
|
|
||||||
xi ξ
|
|
||||||
xx ✗
|
|
||||||
z z
|
|
||||||
ze ze
|
|
||||||
zet zet
|
|
||||||
zeta ζ
|
|
||||||
~ ~
|
|
||||||
~= ≈
|
|
||||||
208
map/emoji.src
208
map/emoji.src
@@ -1,100 +1,108 @@
|
|||||||
!! ⚠
|
# Result first, followed by one or more TAB-separated aliases.
|
||||||
!= ≠
|
⚠ !!
|
||||||
** ★
|
★ **
|
||||||
+- ±
|
± +-
|
||||||
-> →
|
→ ->
|
||||||
.. ·
|
· ..
|
||||||
... …
|
… ...
|
||||||
./ ÷
|
÷ ./
|
||||||
:( ☹
|
☹ :(
|
||||||
:) ☺
|
☺ :)
|
||||||
<- ←
|
← <-
|
||||||
<= ≤
|
≤ <=
|
||||||
<> ≠
|
≠ <> !=
|
||||||
== ≡
|
≡ ==
|
||||||
=> ⇒
|
⇒ =>
|
||||||
>= ≥
|
≥ >=
|
||||||
^( ⁽
|
⁽ ^(
|
||||||
^) ⁾
|
⁾ ^)
|
||||||
^+ ⁺
|
⁺ ^+
|
||||||
^- ⁻
|
⁻ ^-
|
||||||
^= ⁼
|
⁼ ^=
|
||||||
_( ₍
|
₍ _(
|
||||||
_) ₎
|
₎ _)
|
||||||
_+ ₊
|
₊ _+
|
||||||
_- ₋
|
₋ _-
|
||||||
_= ₌
|
₌ _=
|
||||||
~= ≈
|
≈ ~=
|
||||||
^0 ⁰
|
⁰ ^0
|
||||||
_0 ₀
|
₀ _0
|
||||||
^1 ¹
|
¹ ^1
|
||||||
_1 ₁
|
₁ _1
|
||||||
^2 ²
|
² ^2
|
||||||
_2 ₂
|
₂ _2
|
||||||
<3 ♥
|
♥ <3
|
||||||
^3 ³
|
³ ^3
|
||||||
_3 ₃
|
₃ _3
|
||||||
^4 ⁴
|
⁴ ^4
|
||||||
_4 ₄
|
₄ _4
|
||||||
^5 ⁵
|
⁵ ^5
|
||||||
_5 ₅
|
₅ _5
|
||||||
^6 ⁶
|
⁶ ^6
|
||||||
_6 ₆
|
₆ _6
|
||||||
^7 ⁷
|
⁷ ^7
|
||||||
_7 ₇
|
₇ _7
|
||||||
^8 ⁸
|
⁸ ^8
|
||||||
_8 ₈
|
₈ _8
|
||||||
^9 ⁹
|
⁹ ^9
|
||||||
_9 ₉
|
₉ _9
|
||||||
_a ₐ
|
ₐ _a
|
||||||
alpha α
|
α alpha
|
||||||
beta β
|
β beta
|
||||||
chi χ
|
χ chi
|
||||||
deg °
|
° deg
|
||||||
delta δ
|
δ delta
|
||||||
De Δ
|
Δ De
|
||||||
dn ↓
|
↓ dn
|
||||||
_e ₑ
|
ₑ _e
|
||||||
eps ε
|
ε eps
|
||||||
eta η
|
η eta
|
||||||
fuck 凸
|
凸 fuck
|
||||||
gamma γ
|
γ gamma
|
||||||
Ga Γ
|
Γ Ga
|
||||||
^i ⁱ
|
ⁱ ^i
|
||||||
II ∫
|
∫ II
|
||||||
inf ∞
|
∞ inf
|
||||||
iota ι
|
ι iota
|
||||||
kappa κ
|
κ kappa
|
||||||
lambda λ
|
λ lambda
|
||||||
La Λ
|
Λ La
|
||||||
mul ×
|
× mul
|
||||||
mu μ
|
μ mu
|
||||||
^n ⁿ
|
ⁿ ^n
|
||||||
nu ν
|
ν nu
|
||||||
omega ω
|
ω omega
|
||||||
Om Ω
|
Ω Om
|
||||||
oo ●
|
● oo
|
||||||
_o ₒ
|
ₒ _o
|
||||||
phi φ
|
φ phi
|
||||||
Ph Φ
|
Φ Ph
|
||||||
pi π
|
π pi
|
||||||
Pi Π
|
Π Pi
|
||||||
PP ∏
|
∏ PP
|
||||||
psi ψ
|
ψ psi
|
||||||
Ps Ψ
|
Ψ Ps
|
||||||
rho ρ
|
ρ rho
|
||||||
sigma σ
|
σ sigma
|
||||||
Si Σ
|
Σ Si
|
||||||
sq √
|
√ sq
|
||||||
SS ∑
|
∑ SS
|
||||||
tau τ
|
τ tau
|
||||||
theta θ
|
θ theta
|
||||||
Th Θ
|
Θ Th
|
||||||
up ↑
|
↑ up
|
||||||
ups υ
|
υ ups
|
||||||
vv ✓
|
✓ vv
|
||||||
xi ξ
|
ξ xi
|
||||||
Xi Ξ
|
Ξ Xi
|
||||||
xx ✗
|
✗ xx
|
||||||
_x ₓ
|
ₓ _x
|
||||||
zeta ζ
|
ζ zeta
|
||||||
|
|
||||||
|
# Small multilingual emoji seed. Shared aliases intentionally produce choices.
|
||||||
|
😀 웃음 웃다 스마일 smile grin
|
||||||
|
😄 웃음 미소 스마일 smile happy
|
||||||
|
😂 웃음 폭소 웃겨 joy lol
|
||||||
|
😊 미소 방긋 smile blush happy
|
||||||
|
❤️ 사랑 하트 heart love
|
||||||
|
👍 좋아요 찬성 따봉 엄지 thumbsup like
|
||||||
|
|||||||
106
map/mkemoji
106
map/mkemoji
@@ -1,39 +1,71 @@
|
|||||||
#!/bin/sh
|
#!/usr/bin/env python3
|
||||||
|
"""Write emoji.dict to stdout from a result-first UTF-8 TSV file."""
|
||||||
|
|
||||||
awk '
|
import sys
|
||||||
BEGIN { FS = "\t" }
|
import unicodedata
|
||||||
/^$/ { next }
|
from pathlib import Path
|
||||||
{
|
|
||||||
key = $1
|
|
||||||
val = $2
|
|
||||||
map[key] = val
|
|
||||||
for(i = 1; i < length(key); i++){
|
|
||||||
p = substr(key, 1, i)
|
|
||||||
if(!(p in map))
|
|
||||||
map[p] = p
|
|
||||||
}
|
|
||||||
}
|
|
||||||
END {
|
|
||||||
for(k in map)
|
|
||||||
print k "\t" map[k]
|
|
||||||
}
|
|
||||||
' $1 | sort -k1,1 > emoji.map
|
|
||||||
|
|
||||||
awk '
|
|
||||||
BEGIN { FS = "\t" }
|
SOURCE = Path(__file__).with_name("emoji.src")
|
||||||
/^$/ { next }
|
|
||||||
{
|
|
||||||
key = $1
|
def fold(s):
|
||||||
val = $2
|
s = "".join(chr(ord(c) + 32) if "A" <= c <= "Z" else c for c in s)
|
||||||
for(i = 1; i <= length(key); i++){
|
return unicodedata.normalize("NFC", s)
|
||||||
p = substr(key, 1, i)
|
|
||||||
dict[p] = dict[p] " " val
|
|
||||||
}
|
def read(path):
|
||||||
}
|
entries = []
|
||||||
END {
|
with path.open(encoding="utf-8") as src:
|
||||||
for(p in dict){
|
for lineno, raw in enumerate(src, 1):
|
||||||
sub(/^ /, "", dict[p])
|
line = raw.rstrip("\r\n")
|
||||||
print p "\t" dict[p]
|
if not line.strip() or line.lstrip().startswith("#"):
|
||||||
}
|
continue
|
||||||
}
|
fields = line.split("\t")
|
||||||
' $1 | sort -k1,1 > emoji.dict
|
if len(fields) < 2:
|
||||||
|
raise ValueError(f"{path}:{lineno}: need a result and an alias")
|
||||||
|
result = unicodedata.normalize("NFC", fields[0])
|
||||||
|
if not result or any(c.isspace() for c in result):
|
||||||
|
raise ValueError(f"{path}:{lineno}: bad result")
|
||||||
|
for field in fields[1:]:
|
||||||
|
alias = fold(field)
|
||||||
|
if not alias or alias != alias.strip():
|
||||||
|
raise ValueError(f"{path}:{lineno}: bad alias")
|
||||||
|
entries.append((result, alias))
|
||||||
|
return entries
|
||||||
|
|
||||||
|
|
||||||
|
def add(table, key, result):
|
||||||
|
values = table.setdefault(key, [])
|
||||||
|
if result not in values:
|
||||||
|
values.append(result)
|
||||||
|
|
||||||
|
|
||||||
|
def build(entries):
|
||||||
|
exact = {}
|
||||||
|
prefix = {}
|
||||||
|
for result, alias in entries:
|
||||||
|
for n in range(1, len(alias) + 1):
|
||||||
|
add(exact if n == len(alias) else prefix, alias[:n], result)
|
||||||
|
for key in sorted(exact.keys() | prefix.keys()):
|
||||||
|
values = exact.get(key, []) + prefix.get(key, [])
|
||||||
|
values = list(dict.fromkeys(values))
|
||||||
|
yield f"{key}\t{' '.join(values)}"
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) > 2:
|
||||||
|
print(f"usage: {sys.argv[0]} [emoji.src]", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
path = Path(sys.argv[1]) if len(sys.argv) == 2 else SOURCE
|
||||||
|
try:
|
||||||
|
for line in build(read(path)):
|
||||||
|
print(line)
|
||||||
|
except (OSError, UnicodeError, ValueError) as error:
|
||||||
|
print(error, file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
|
|||||||
279
strans.c
279
strans.c
@@ -3,8 +3,18 @@
|
|||||||
|
|
||||||
static Im im;
|
static Im im;
|
||||||
static int popup = 0;
|
static int popup = 0;
|
||||||
|
static int visible = 0;
|
||||||
static void dictqmap(Im*);
|
static void dictqmap(Im*);
|
||||||
|
|
||||||
|
typedef struct Search Search;
|
||||||
|
struct Search
|
||||||
|
{
|
||||||
|
int on;
|
||||||
|
Str raw;
|
||||||
|
Str text;
|
||||||
|
};
|
||||||
|
static Search search;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
backmap(Im *im)
|
backmap(Im *im)
|
||||||
{
|
{
|
||||||
@@ -16,7 +26,7 @@ Lang langs[] = {
|
|||||||
{LangJP, "hira", "kanji", transmap, backmap, dictqmap, nil, nil},
|
{LangJP, "hira", "kanji", transmap, backmap, dictqmap, nil, nil},
|
||||||
{LangJPK, "kata", "kanji", transmap, backmap, dictqmap, nil, nil},
|
{LangJPK, "kata", "kanji", transmap, backmap, dictqmap, nil, nil},
|
||||||
{LangKO, "hangul", nil, transko, backko, dictqmap, nil, nil},
|
{LangKO, "hangul", nil, transko, backko, dictqmap, nil, nil},
|
||||||
{LangEMOJI, "emoji", "emoji", transmap, backmap, dictqmap, nil, nil},
|
{LangEMOJI, nil, "emoji", nil, nil, nil, nil, nil},
|
||||||
{LangVI, "telex", nil, transvi, backvi, dictqmap, nil, nil},
|
{LangVI, "telex", nil, transvi, backvi, dictqmap, nil, nil},
|
||||||
};
|
};
|
||||||
int nlang = nelem(langs);
|
int nlang = nelem(langs);
|
||||||
@@ -44,13 +54,15 @@ static void
|
|||||||
show(void)
|
show(void)
|
||||||
{
|
{
|
||||||
Drawcmd dc;
|
Drawcmd dc;
|
||||||
|
Str *pre;
|
||||||
int i, first, n;
|
int i, first, n;
|
||||||
|
|
||||||
if(!popup)
|
|
||||||
return;
|
|
||||||
sclear(&dc.pre);
|
sclear(&dc.pre);
|
||||||
if(!mapget(im.l->map, &im.pre, &dc.pre))
|
pre = search.on ? &search.text : &im.pre;
|
||||||
dc.pre = im.pre;
|
if(popup){
|
||||||
|
if(search.on || im.l->map == nil || !mapget(im.l->map, pre, &dc.pre))
|
||||||
|
dc.pre = *pre;
|
||||||
|
}
|
||||||
first = im.sel >= Maxdisp ? im.sel - Maxdisp + 1 : 0;
|
first = im.sel >= Maxdisp ? im.sel - Maxdisp + 1 : 0;
|
||||||
n = im.nkouho - first;
|
n = im.nkouho - first;
|
||||||
if(n > Maxdisp) n = Maxdisp;
|
if(n > Maxdisp) n = Maxdisp;
|
||||||
@@ -58,6 +70,9 @@ show(void)
|
|||||||
dc.sel = im.sel >= 0 ? im.sel - first : -1;
|
dc.sel = im.sel >= 0 ? im.sel - first : -1;
|
||||||
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)
|
||||||
|
return;
|
||||||
|
visible = dc.pre.n != 0 || n != 0;
|
||||||
chansend(drawc, &dc);
|
chansend(drawc, &dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +125,7 @@ commit(Str *com)
|
|||||||
{
|
{
|
||||||
Str val;
|
Str val;
|
||||||
|
|
||||||
if(mapget(im.l->map, &im.pre, &val))
|
if(im.l->map != nil && mapget(im.l->map, &im.pre, &val))
|
||||||
sappend(com, &val);
|
sappend(com, &val);
|
||||||
else
|
else
|
||||||
sappend(com, &im.pre);
|
sappend(com, &im.pre);
|
||||||
@@ -209,13 +224,240 @@ transmap(Im *im, Rune c)
|
|||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Rune
|
||||||
|
ctrlkey(Rune c)
|
||||||
|
{
|
||||||
|
if(c >= 'a' && c <= 'z')
|
||||||
|
return c - 'a' + 1;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
foldascii(Str *s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < s->n; i++)
|
||||||
|
if(s->r[i] >= 'A' && s->r[i] <= 'Z')
|
||||||
|
s->r[i] += 'a' - 'A';
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
transstr(Lang *l, Str *raw, Str *out)
|
||||||
|
{
|
||||||
|
static Im q;
|
||||||
|
Emit e;
|
||||||
|
Str mapped;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
sclear(out);
|
||||||
|
if(l == nil || l->trans == nil || (l->trans == transmap && l->map == nil)){
|
||||||
|
*out = *raw;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memset(&q, 0, sizeof q);
|
||||||
|
q.l = l;
|
||||||
|
for(i = 0; i < raw->n; i++){
|
||||||
|
e = l->trans(&q, raw->r[i]);
|
||||||
|
sappend(out, &e.s);
|
||||||
|
q.pre = e.next;
|
||||||
|
if(!e.eat && out->n < Maxrunes)
|
||||||
|
sputr(out, raw->r[i]);
|
||||||
|
}
|
||||||
|
if(q.pre.n == 0)
|
||||||
|
return;
|
||||||
|
if(l->map != nil && mapget(l->map, &q.pre, &mapped))
|
||||||
|
sappend(out, &mapped);
|
||||||
|
else
|
||||||
|
sappend(out, &q.pre);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
addkouho(Str *s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < im.nkouho; i++)
|
||||||
|
if(scmp(&im.kouho[i], s) == 0)
|
||||||
|
return;
|
||||||
|
if(im.nkouho < Maxkouho)
|
||||||
|
im.kouho[im.nkouho++] = *s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
emojilookup(Str *key, Dictres *res)
|
||||||
|
{
|
||||||
|
Dictreq req;
|
||||||
|
|
||||||
|
req.key = *key;
|
||||||
|
req.pre = req.key;
|
||||||
|
req.lang = LangEMOJI;
|
||||||
|
dictlookup(&req, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
emojiquery(void)
|
||||||
|
{
|
||||||
|
static Dictres res;
|
||||||
|
Str raw, local;
|
||||||
|
int i, rawhit, localhit;
|
||||||
|
|
||||||
|
raw = search.raw;
|
||||||
|
foldascii(&raw);
|
||||||
|
transstr(im.l, &search.raw, &local);
|
||||||
|
foldascii(&local);
|
||||||
|
clearkouho();
|
||||||
|
emojilookup(&raw, &res);
|
||||||
|
rawhit = res.nkouho != 0;
|
||||||
|
for(i = 0; i < res.nkouho; i++)
|
||||||
|
addkouho(&res.kouho[i]);
|
||||||
|
localhit = 0;
|
||||||
|
if(scmp(&raw, &local) != 0){
|
||||||
|
emojilookup(&local, &res);
|
||||||
|
localhit = res.nkouho != 0;
|
||||||
|
for(i = 0; i < res.nkouho; i++)
|
||||||
|
addkouho(&res.kouho[i]);
|
||||||
|
}
|
||||||
|
search.text = rawhit || !localhit ? raw : local;
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
endsearch(void)
|
||||||
|
{
|
||||||
|
search.on = 0;
|
||||||
|
sclear(&search.raw);
|
||||||
|
sclear(&search.text);
|
||||||
|
clearkouho();
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
startsearch(Str *com)
|
||||||
|
{
|
||||||
|
if(im.pre.n > 0)
|
||||||
|
commit(com);
|
||||||
|
sclear(&im.pre);
|
||||||
|
sclear(&im.raw);
|
||||||
|
clearkouho();
|
||||||
|
search.on = 1;
|
||||||
|
sclear(&search.raw);
|
||||||
|
sclear(&search.text);
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
commitsearch(Str *com)
|
||||||
|
{
|
||||||
|
sappend(com, &search.text);
|
||||||
|
endsearch();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pickemoji(int n, Str *com)
|
||||||
|
{
|
||||||
|
if(n < 0 || n >= im.nkouho)
|
||||||
|
return 0;
|
||||||
|
sappend(com, &im.kouho[n]);
|
||||||
|
endsearch();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
searchkey(u32int ks, u32int mod, Str *com)
|
||||||
|
{
|
||||||
|
int n, off;
|
||||||
|
Rune c;
|
||||||
|
|
||||||
|
if(ks == Ksuper || ks == Kshift)
|
||||||
|
return 1;
|
||||||
|
if(ks == Kdown || ks == Kup){
|
||||||
|
if(im.nkouho == 0)
|
||||||
|
return 1;
|
||||||
|
if(ks == Kdown && im.sel < im.nkouho - 1)
|
||||||
|
im.sel++;
|
||||||
|
if(ks == Kup && im.sel > 0)
|
||||||
|
im.sel--;
|
||||||
|
show();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
n = ks - '1';
|
||||||
|
off = im.sel >= Maxdisp ? im.sel - Maxdisp + 1 : 0;
|
||||||
|
if((mod & Malt) && n >= 0 && n < Maxdisp){
|
||||||
|
pickemoji(off + n, com);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(ks == Ktab){
|
||||||
|
if(im.nkouho == 0)
|
||||||
|
return 1;
|
||||||
|
if(mod & Mshift){
|
||||||
|
if(im.sel <= 0)
|
||||||
|
im.sel = im.nkouho - 1;
|
||||||
|
else
|
||||||
|
im.sel--;
|
||||||
|
}else if(im.sel >= im.nkouho - 1)
|
||||||
|
im.sel = 0;
|
||||||
|
else
|
||||||
|
im.sel++;
|
||||||
|
show();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(ks == Kret){
|
||||||
|
if(im.nkouho > 0)
|
||||||
|
return pickemoji(im.sel >= 0 ? im.sel : 0, com);
|
||||||
|
commitsearch(com);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(ks == Kback){
|
||||||
|
if(search.raw.n == 0)
|
||||||
|
return 1;
|
||||||
|
spopr(&search.raw);
|
||||||
|
emojiquery();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(ks == Kesc){
|
||||||
|
endsearch();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(mod & Mctrl){
|
||||||
|
c = ctrlkey(ks);
|
||||||
|
if(c == LangEMOJI){
|
||||||
|
endsearch();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(c == 0x10){
|
||||||
|
popup = !popup;
|
||||||
|
show();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
endsearch();
|
||||||
|
if(setlang(c))
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(ks >= Kspec || ks < ' ' || (mod & (Malt|Msuper))){
|
||||||
|
commitsearch(com);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(search.raw.n >= Maxrunes){
|
||||||
|
commitsearch(com);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
sputr(&search.raw, ks);
|
||||||
|
emojiquery();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
keystroke(u32int ks, u32int mod, Str *com)
|
keystroke(u32int ks, u32int mod, Str *com)
|
||||||
{
|
{
|
||||||
int n, off;
|
int n, off;
|
||||||
|
Rune c;
|
||||||
|
|
||||||
if(ks == Ksuper || ks == Kshift)
|
if(ks == Ksuper || ks == Kshift)
|
||||||
return 1;
|
return 1;
|
||||||
|
if(search.on)
|
||||||
|
return searchkey(ks, mod, com);
|
||||||
if(ks == Kdown || ks == Kup){
|
if(ks == Kdown || ks == Kup){
|
||||||
if(im.nkouho == 0)
|
if(im.nkouho == 0)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -271,14 +513,18 @@ keystroke(u32int ks, u32int mod, Str *com)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if(mod & Mctrl){
|
if(mod & Mctrl){
|
||||||
reset();
|
c = ctrlkey(ks);
|
||||||
if(ks >= 'a' && ks <= 'z')
|
if(c == LangEMOJI){
|
||||||
ks -= 'a' - 1;
|
startsearch(com);
|
||||||
if(ks == 0x10){
|
|
||||||
popup = !popup;
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if(setlang(ks))
|
if(c == 0x10){
|
||||||
|
popup = !popup;
|
||||||
|
show();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
reset();
|
||||||
|
if(setlang(c))
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -305,6 +551,8 @@ init(void)
|
|||||||
{
|
{
|
||||||
memset(&im, 0, sizeof(im));
|
memset(&im, 0, sizeof(im));
|
||||||
im.l = getlang(LangEN);
|
im.l = getlang(LangEN);
|
||||||
|
memset(&search, 0, sizeof search);
|
||||||
|
visible = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -316,15 +564,15 @@ imhandlekey(Keyreq *kr)
|
|||||||
sclear(&res.preedit);
|
sclear(&res.preedit);
|
||||||
res.eaten = keystroke(kr->ks, kr->mod, &res.commit);
|
res.eaten = keystroke(kr->ks, kr->mod, &res.commit);
|
||||||
if(kr->want)
|
if(kr->want)
|
||||||
res.preedit = im.pre;
|
res.preedit = search.on ? search.text : im.pre;
|
||||||
chansend(kr->reply, &res);
|
chansend(kr->reply, &res);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
imthread(void*)
|
imthread(void*)
|
||||||
{
|
{
|
||||||
|
static Dictres res;
|
||||||
Keyreq kr;
|
Keyreq kr;
|
||||||
Dictres res;
|
|
||||||
Alt alts[] = {
|
Alt alts[] = {
|
||||||
{keyc, &kr, CHANRCV, nil},
|
{keyc, &kr, CHANRCV, nil},
|
||||||
{dictresc, &res, CHANRCV, nil},
|
{dictresc, &res, CHANRCV, nil},
|
||||||
@@ -339,7 +587,8 @@ imthread(void*)
|
|||||||
imhandlekey(&kr);
|
imhandlekey(&kr);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if(scmp(&res.key, &im.pre) == 0){
|
if(!search.on && res.lang == im.l->lang &&
|
||||||
|
scmp(&res.key, &im.pre) == 0){
|
||||||
setkouho(&res);
|
setkouho(&res);
|
||||||
show();
|
show();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ dictionary_candidates(struct ct *t)
|
|||||||
dictlookup(&req, &res);
|
dictlookup(&req, &res);
|
||||||
if(!CT_EQ_INT(t, 2, res.nkouho))
|
if(!CT_EQ_INT(t, 2, res.nkouho))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
CT_EQ_INT(t, LangJP, res.lang);
|
||||||
CT_EQ_INT(t, 0, scmp(&req.pre, &res.key));
|
CT_EQ_INT(t, 0, scmp(&req.pre, &res.key));
|
||||||
checkstr(t, "candidate 1", "候補1", &res.kouho[0]);
|
checkstr(t, "candidate 1", "候補1", &res.kouho[0]);
|
||||||
checkstr(t, "candidate 2", "候補2", &res.kouho[1]);
|
checkstr(t, "candidate 2", "候補2", &res.kouho[1]);
|
||||||
@@ -44,6 +45,7 @@ dictionary_candidates(struct ct *t)
|
|||||||
dictlookup(&req, &res);
|
dictlookup(&req, &res);
|
||||||
if(!CT_EQ_INT(t, Maxkouho, res.nkouho))
|
if(!CT_EQ_INT(t, Maxkouho, res.nkouho))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
CT_EQ_INT(t, LangJP, res.lang);
|
||||||
CT_EQ_INT(t, 0, scmp(&req.pre, &res.key));
|
CT_EQ_INT(t, 0, scmp(&req.pre, &res.key));
|
||||||
checkstr(t, "first capped candidate", "c00", &res.kouho[0]);
|
checkstr(t, "first capped candidate", "c00", &res.kouho[0]);
|
||||||
checkstr(t, "last capped candidate", "c31", &res.kouho[31]);
|
checkstr(t, "last capped candidate", "c31", &res.kouho[31]);
|
||||||
@@ -81,6 +83,7 @@ dictionary_misses_clear_result(struct ct *t)
|
|||||||
if(res.nkouho != 0)
|
if(res.nkouho != 0)
|
||||||
CT_ERRORF(t, "%s: want 0 candidates, got %d",
|
CT_ERRORF(t, "%s: want 0 candidates, got %d",
|
||||||
cases[i].name, res.nkouho);
|
cases[i].name, res.nkouho);
|
||||||
|
CT_EQ_INT(t, LangJP, res.lang);
|
||||||
checkstr(t, cases[i].name, cases[i].pre, &res.key);
|
checkstr(t, cases[i].name, cases[i].pre, &res.key);
|
||||||
}
|
}
|
||||||
hmapfree(lang->dict);
|
hmapfree(lang->dict);
|
||||||
|
|||||||
@@ -255,3 +255,177 @@ engine_language_switch_state(struct ct *t)
|
|||||||
}
|
}
|
||||||
vi->map = saved;
|
vi->map = saved;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct Emojifix Emojifix;
|
||||||
|
struct Emojifix
|
||||||
|
{
|
||||||
|
Im im;
|
||||||
|
Search search;
|
||||||
|
Hmap *dict;
|
||||||
|
int popup;
|
||||||
|
int visible;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
draindraw(Drawcmd *last)
|
||||||
|
{
|
||||||
|
Drawcmd dc = {0};
|
||||||
|
int n;
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
while(channbrecv(drawc, &dc) > 0){
|
||||||
|
n++;
|
||||||
|
if(last != nil)
|
||||||
|
*last = dc;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
setemoji(Hmap **dict, char *key, char *val)
|
||||||
|
{
|
||||||
|
Str s;
|
||||||
|
|
||||||
|
s = mkstr(key);
|
||||||
|
hmapset(dict, &s, val, strlen(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
emojibegin(Emojifix *f, int showpre)
|
||||||
|
{
|
||||||
|
Lang *l;
|
||||||
|
|
||||||
|
l = getlang(LangEMOJI);
|
||||||
|
f->im = im;
|
||||||
|
f->search = search;
|
||||||
|
f->dict = l->dict;
|
||||||
|
f->popup = popup;
|
||||||
|
f->visible = visible;
|
||||||
|
draindraw(nil);
|
||||||
|
l->dict = hmapalloc(8);
|
||||||
|
setemoji(&l->dict, "alpha", "α");
|
||||||
|
setemoji(&l->dict, "smil", "😀 😄");
|
||||||
|
setemoji(&l->dict, "smile", "😀 😄");
|
||||||
|
setemoji(&l->dict, "웃음", "😀 😄 😂");
|
||||||
|
init();
|
||||||
|
im.l = getlang(LangKO);
|
||||||
|
popup = showpre;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
emojiend(Emojifix *f)
|
||||||
|
{
|
||||||
|
Lang *l;
|
||||||
|
Hmap *dict;
|
||||||
|
|
||||||
|
l = getlang(LangEMOJI);
|
||||||
|
dict = l->dict;
|
||||||
|
l->dict = f->dict;
|
||||||
|
hmapfree(dict);
|
||||||
|
draindraw(nil);
|
||||||
|
im = f->im;
|
||||||
|
search = f->search;
|
||||||
|
popup = f->popup;
|
||||||
|
visible = f->visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
typekeys(struct ct *t, char *keys, Str *com)
|
||||||
|
{
|
||||||
|
for(; *keys != '\0'; keys++)
|
||||||
|
if(!CT_CHECK(t, keystroke((uchar)*keys, 0, com)))
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
engine_emoji_single_candidate(struct ct *t)
|
||||||
|
{
|
||||||
|
Drawcmd dc = {0};
|
||||||
|
Emojifix f;
|
||||||
|
Str com;
|
||||||
|
|
||||||
|
emojibegin(&f, 0);
|
||||||
|
sclear(&com);
|
||||||
|
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
||||||
|
CT_CHECK(t, search.on);
|
||||||
|
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.on);
|
||||||
|
CT_EQ_INT(t, 1, im.nkouho);
|
||||||
|
checkstr(t, "single candidate", "α", &im.kouho[0]);
|
||||||
|
CT_CHECK(t, draindraw(&dc) > 0);
|
||||||
|
CT_EQ_INT(t, 0, dc.pre.n);
|
||||||
|
CT_EQ_INT(t, 1, dc.nkouho);
|
||||||
|
CT_CHECK(t, keystroke(Kret, 0, &com));
|
||||||
|
checkstr(t, "explicit candidate commit", "α", &com);
|
||||||
|
CT_CHECK(t, !search.on);
|
||||||
|
CT_EQ_INT(t, LangKO, im.l->lang);
|
||||||
|
}
|
||||||
|
emojiend(&f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
engine_emoji_queries(struct ct *t)
|
||||||
|
{
|
||||||
|
Drawcmd dc = {0};
|
||||||
|
Emojifix f;
|
||||||
|
Str com;
|
||||||
|
|
||||||
|
emojibegin(&f, 1);
|
||||||
|
sclear(&com);
|
||||||
|
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
||||||
|
if(typekeys(t, "smile", &com)){
|
||||||
|
checkstr(t, "English alias", "smile", &search.text);
|
||||||
|
CT_EQ_INT(t, 2, im.nkouho);
|
||||||
|
CT_CHECK(t, keystroke(Kback, 0, &com));
|
||||||
|
checkstr(t, "backspaced query", "smil", &search.text);
|
||||||
|
CT_EQ_INT(t, 2, im.nkouho);
|
||||||
|
CT_CHECK(t, keystroke('e', 0, &com));
|
||||||
|
CT_CHECK(t, keystroke('2', Malt, &com));
|
||||||
|
checkstr(t, "selected English alias", "😄", &com);
|
||||||
|
CT_EQ_INT(t, LangKO, im.l->lang);
|
||||||
|
}
|
||||||
|
|
||||||
|
sclear(&com);
|
||||||
|
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
||||||
|
if(typekeys(t, "dntdma", &com)){
|
||||||
|
checkstr(t, "localized Korean query", "웃음", &search.text);
|
||||||
|
CT_EQ_INT(t, 3, im.nkouho);
|
||||||
|
CT_CHECK(t, draindraw(&dc) > 0);
|
||||||
|
checkstr(t, "popup query", "웃음", &dc.pre);
|
||||||
|
CT_EQ_INT(t, 3, dc.nkouho);
|
||||||
|
CT_CHECK(t, keystroke(Kesc, 0, &com));
|
||||||
|
checkstr(t, "cancel commit", "", &com);
|
||||||
|
CT_CHECK(t, !search.on);
|
||||||
|
CT_EQ_INT(t, LangKO, im.l->lang);
|
||||||
|
}
|
||||||
|
emojiend(&f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
engine_emoji_start_and_unknown(struct ct *t)
|
||||||
|
{
|
||||||
|
Emojifix f;
|
||||||
|
Str com;
|
||||||
|
|
||||||
|
emojibegin(&f, 0);
|
||||||
|
sclear(&com);
|
||||||
|
if(typekeys(t, "dkssud", &com)){
|
||||||
|
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
||||||
|
checkstr(t, "committed Korean preedit", "안녕", &com);
|
||||||
|
CT_CHECK(t, search.on);
|
||||||
|
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.on);
|
||||||
|
CT_EQ_INT(t, LangKO, im.l->lang);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emojiend(&f);
|
||||||
|
}
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ void engine_selects_visible_candidate(struct ct*);
|
|||||||
void engine_commit_contract(struct ct*);
|
void engine_commit_contract(struct ct*);
|
||||||
void engine_language_switch_state(struct ct*);
|
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_queries(struct ct*);
|
||||||
|
void engine_emoji_start_and_unknown(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*);
|
||||||
|
|
||||||
|
|||||||
@@ -80,6 +80,9 @@ static const struct ct_test tests[] = {
|
|||||||
{ "engine/commit-contract", engine_commit_contract },
|
{ "engine/commit-contract", engine_commit_contract },
|
||||||
{ "engine/language-switch-state", engine_language_switch_state },
|
{ "engine/language-switch-state", engine_language_switch_state },
|
||||||
{ "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-queries", engine_emoji_queries },
|
||||||
|
{ "engine/emoji-start-and-unknown", engine_emoji_start_and_unknown },
|
||||||
{ "dict/candidates", dictionary_candidates },
|
{ "dict/candidates", dictionary_candidates },
|
||||||
{ "dict/misses-clear-result", dictionary_misses_clear_result },
|
{ "dict/misses-clear-result", dictionary_misses_clear_result },
|
||||||
};
|
};
|
||||||
@@ -89,7 +92,7 @@ threadmain(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
int i, status;
|
int i, status;
|
||||||
|
|
||||||
drawc = chancreate(sizeof(Drawcmd), 4);
|
drawc = chancreate(sizeof(Drawcmd), 1024);
|
||||||
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);
|
||||||
|
|||||||
23
win.c
23
win.c
@@ -90,16 +90,18 @@ fill(u32int *buf, int n, u32int color)
|
|||||||
static void
|
static void
|
||||||
drawkouho(Drawcmd *dc, int first, int n, int w, int h)
|
drawkouho(Drawcmd *dc, int first, int n, int w, int h)
|
||||||
{
|
{
|
||||||
int sely, y, i;
|
int npre, sely, y, i;
|
||||||
Str *s;
|
Str *s;
|
||||||
|
|
||||||
fill(img, w * h, Colbg);
|
fill(img, w * h, Colbg);
|
||||||
drawstr(img, 0, 0, dc->pre.r, dc->pre.n, w, h);
|
npre = dc->pre.n != 0;
|
||||||
if(dc->sel >= 0){
|
if(npre)
|
||||||
sely = Fontsz + dc->sel * Fontsz;
|
drawstr(img, 0, 0, dc->pre.r, dc->pre.n, w, h);
|
||||||
|
if(dc->sel >= 0 && dc->sel < n){
|
||||||
|
sely = (npre + dc->sel) * Fontsz;
|
||||||
fill(img + sely * w, Fontsz * w, Colsel);
|
fill(img + sely * w, Fontsz * w, Colsel);
|
||||||
}
|
}
|
||||||
for(i = 0, y = Fontsz; i < n; i++, y += Fontsz){
|
for(i = 0, y = npre * Fontsz; i < n; i++, y += Fontsz){
|
||||||
s = &dc->kouho[first+i];
|
s = &dc->kouho[first+i];
|
||||||
putfont(img, w, h, 0, y, '1' + i + Asciitofull);
|
putfont(img, w, h, 0, y, '1' + i + Asciitofull);
|
||||||
drawstr(img, 2*Fontsz, y, s->r, s->n, w, h);
|
drawstr(img, 2*Fontsz, y, s->r, s->n, w, h);
|
||||||
@@ -124,13 +126,18 @@ winhide(void)
|
|||||||
static void
|
static void
|
||||||
winshow(Drawcmd *dc)
|
winshow(Drawcmd *dc)
|
||||||
{
|
{
|
||||||
int px, py, w, h, i, n, maxw;
|
int npre, px, py, w, h, i, n, maxw;
|
||||||
u32int vals[4];
|
u32int vals[4];
|
||||||
xcb_query_pointer_reply_t *ptr;
|
xcb_query_pointer_reply_t *ptr;
|
||||||
xcb_query_pointer_cookie_t cookie;
|
xcb_query_pointer_cookie_t cookie;
|
||||||
|
|
||||||
|
n = min(max(dc->nkouho, 0), Maxdisp);
|
||||||
|
npre = dc->pre.n != 0;
|
||||||
|
if(n == 0 && npre == 0){
|
||||||
|
winhide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
cookie = xcb_query_pointer(conn, scr->root);
|
cookie = xcb_query_pointer(conn, scr->root);
|
||||||
n = dc->nkouho;
|
|
||||||
maxw = dc->pre.n;
|
maxw = dc->pre.n;
|
||||||
for(i = 0; i < n; i++)
|
for(i = 0; i < n; i++)
|
||||||
maxw = max(maxw, dc->kouho[i].n);
|
maxw = max(maxw, dc->kouho[i].n);
|
||||||
@@ -140,7 +147,7 @@ winshow(Drawcmd *dc)
|
|||||||
px = ptr->root_x + 10;
|
px = ptr->root_x + 10;
|
||||||
py = ptr->root_y + 10;
|
py = ptr->root_y + 10;
|
||||||
free(ptr);
|
free(ptr);
|
||||||
vals[3] = h = (n + 1) * Fontsz;
|
vals[3] = h = (n + npre) * Fontsz;
|
||||||
vals[2] = w = (maxw + 3) * Fontsz;
|
vals[2] = w = (maxw + 3) * Fontsz;
|
||||||
vals[1] = py = max(0, min(py, scr->height_in_pixels - h));
|
vals[1] = py = max(0, min(py, scr->height_in_pixels - h));
|
||||||
vals[0] = px = max(0, min(px, scr->width_in_pixels - w));
|
vals[0] = px = max(0, min(px, scr->width_in_pixels - w));
|
||||||
|
|||||||
Reference in New Issue
Block a user