emoji: add one-shot candidate search
This commit is contained in:
1
Makefile
1
Makefile
@@ -42,5 +42,6 @@ test:
|
||||
|
||||
verify-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
|
||||
|
||||
24
README.md
24
README.md
@@ -66,12 +66,32 @@ Switch input modes with Ctrl + key:
|
||||
S Hangul
|
||||
T English
|
||||
V Vietnamese (Telex)
|
||||
E Emoji
|
||||
P Toggle preedit/candidate popup window
|
||||
P Toggle preedit echo
|
||||
|
||||
Type romanized input. Select candidates with 1-9 or arrow keys.
|
||||
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
|
||||
|
||||
Threads communicate via CSP channels:
|
||||
|
||||
1
dat.h
1
dat.h
@@ -156,6 +156,7 @@ struct Dictres
|
||||
Str key;
|
||||
Str kouho[Maxkouho];
|
||||
int nkouho;
|
||||
int lang;
|
||||
};
|
||||
|
||||
extern Lang langs[];
|
||||
|
||||
1
dict.c
1
dict.c
@@ -12,6 +12,7 @@ dictlookup(Dictreq *req, Dictres *res)
|
||||
|
||||
res->key = req->pre;
|
||||
res->nkouho = 0;
|
||||
res->lang = req->lang;
|
||||
if(req->key.n == 0)
|
||||
return;
|
||||
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 @@
|
||||
!! ⚠
|
||||
!= ≠
|
||||
** ★
|
||||
+- ±
|
||||
-> →
|
||||
.. ·
|
||||
... …
|
||||
./ ÷
|
||||
:( ☹
|
||||
:) ☺
|
||||
<- ←
|
||||
<= ≤
|
||||
<> ≠
|
||||
== ≡
|
||||
=> ⇒
|
||||
>= ≥
|
||||
^( ⁽
|
||||
^) ⁾
|
||||
^+ ⁺
|
||||
^- ⁻
|
||||
^= ⁼
|
||||
_( ₍
|
||||
_) ₎
|
||||
_+ ₊
|
||||
_- ₋
|
||||
_= ₌
|
||||
~= ≈
|
||||
^0 ⁰
|
||||
_0 ₀
|
||||
^1 ¹
|
||||
_1 ₁
|
||||
^2 ²
|
||||
_2 ₂
|
||||
<3 ♥
|
||||
^3 ³
|
||||
_3 ₃
|
||||
^4 ⁴
|
||||
_4 ₄
|
||||
^5 ⁵
|
||||
_5 ₅
|
||||
^6 ⁶
|
||||
_6 ₆
|
||||
^7 ⁷
|
||||
_7 ₇
|
||||
^8 ⁸
|
||||
_8 ₈
|
||||
^9 ⁹
|
||||
_9 ₉
|
||||
_a ₐ
|
||||
alpha α
|
||||
beta β
|
||||
chi χ
|
||||
deg °
|
||||
delta δ
|
||||
De Δ
|
||||
dn ↓
|
||||
_e ₑ
|
||||
eps ε
|
||||
eta η
|
||||
fuck 凸
|
||||
gamma γ
|
||||
Ga Γ
|
||||
^i ⁱ
|
||||
II ∫
|
||||
inf ∞
|
||||
iota ι
|
||||
kappa κ
|
||||
lambda λ
|
||||
La Λ
|
||||
mul ×
|
||||
mu μ
|
||||
^n ⁿ
|
||||
nu ν
|
||||
omega ω
|
||||
Om Ω
|
||||
oo ●
|
||||
_o ₒ
|
||||
phi φ
|
||||
Ph Φ
|
||||
pi π
|
||||
Pi Π
|
||||
PP ∏
|
||||
psi ψ
|
||||
Ps Ψ
|
||||
rho ρ
|
||||
sigma σ
|
||||
Si Σ
|
||||
sq √
|
||||
SS ∑
|
||||
tau τ
|
||||
theta θ
|
||||
Th Θ
|
||||
up ↑
|
||||
ups υ
|
||||
vv ✓
|
||||
xi ξ
|
||||
Xi Ξ
|
||||
xx ✗
|
||||
_x ₓ
|
||||
zeta ζ
|
||||
# Result first, followed by one or more TAB-separated aliases.
|
||||
⚠ !!
|
||||
★ **
|
||||
± +-
|
||||
→ ->
|
||||
· ..
|
||||
… ...
|
||||
÷ ./
|
||||
☹ :(
|
||||
☺ :)
|
||||
← <-
|
||||
≤ <=
|
||||
≠ <> !=
|
||||
≡ ==
|
||||
⇒ =>
|
||||
≥ >=
|
||||
⁽ ^(
|
||||
⁾ ^)
|
||||
⁺ ^+
|
||||
⁻ ^-
|
||||
⁼ ^=
|
||||
₍ _(
|
||||
₎ _)
|
||||
₊ _+
|
||||
₋ _-
|
||||
₌ _=
|
||||
≈ ~=
|
||||
⁰ ^0
|
||||
₀ _0
|
||||
¹ ^1
|
||||
₁ _1
|
||||
² ^2
|
||||
₂ _2
|
||||
♥ <3
|
||||
³ ^3
|
||||
₃ _3
|
||||
⁴ ^4
|
||||
₄ _4
|
||||
⁵ ^5
|
||||
₅ _5
|
||||
⁶ ^6
|
||||
₆ _6
|
||||
⁷ ^7
|
||||
₇ _7
|
||||
⁸ ^8
|
||||
₈ _8
|
||||
⁹ ^9
|
||||
₉ _9
|
||||
ₐ _a
|
||||
α alpha
|
||||
β beta
|
||||
χ chi
|
||||
° deg
|
||||
δ delta
|
||||
Δ De
|
||||
↓ dn
|
||||
ₑ _e
|
||||
ε eps
|
||||
η eta
|
||||
凸 fuck
|
||||
γ gamma
|
||||
Γ Ga
|
||||
ⁱ ^i
|
||||
∫ II
|
||||
∞ inf
|
||||
ι iota
|
||||
κ kappa
|
||||
λ lambda
|
||||
Λ La
|
||||
× mul
|
||||
μ mu
|
||||
ⁿ ^n
|
||||
ν nu
|
||||
ω omega
|
||||
Ω Om
|
||||
● oo
|
||||
ₒ _o
|
||||
φ phi
|
||||
Φ Ph
|
||||
π pi
|
||||
Π Pi
|
||||
∏ PP
|
||||
ψ psi
|
||||
Ψ Ps
|
||||
ρ rho
|
||||
σ sigma
|
||||
Σ Si
|
||||
√ sq
|
||||
∑ SS
|
||||
τ tau
|
||||
θ theta
|
||||
Θ Th
|
||||
↑ up
|
||||
υ ups
|
||||
✓ vv
|
||||
ξ xi
|
||||
Ξ Xi
|
||||
✗ xx
|
||||
ₓ _x
|
||||
ζ 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 '
|
||||
BEGIN { FS = "\t" }
|
||||
/^$/ { next }
|
||||
{
|
||||
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
|
||||
import sys
|
||||
import unicodedata
|
||||
from pathlib import Path
|
||||
|
||||
awk '
|
||||
BEGIN { FS = "\t" }
|
||||
/^$/ { next }
|
||||
{
|
||||
key = $1
|
||||
val = $2
|
||||
for(i = 1; i <= length(key); i++){
|
||||
p = substr(key, 1, i)
|
||||
dict[p] = dict[p] " " val
|
||||
}
|
||||
}
|
||||
END {
|
||||
for(p in dict){
|
||||
sub(/^ /, "", dict[p])
|
||||
print p "\t" dict[p]
|
||||
}
|
||||
}
|
||||
' $1 | sort -k1,1 > emoji.dict
|
||||
|
||||
SOURCE = Path(__file__).with_name("emoji.src")
|
||||
|
||||
|
||||
def fold(s):
|
||||
s = "".join(chr(ord(c) + 32) if "A" <= c <= "Z" else c for c in s)
|
||||
return unicodedata.normalize("NFC", s)
|
||||
|
||||
|
||||
def read(path):
|
||||
entries = []
|
||||
with path.open(encoding="utf-8") as src:
|
||||
for lineno, raw in enumerate(src, 1):
|
||||
line = raw.rstrip("\r\n")
|
||||
if not line.strip() or line.lstrip().startswith("#"):
|
||||
continue
|
||||
fields = line.split("\t")
|
||||
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 int popup = 0;
|
||||
static int visible = 0;
|
||||
static void dictqmap(Im*);
|
||||
|
||||
typedef struct Search Search;
|
||||
struct Search
|
||||
{
|
||||
int on;
|
||||
Str raw;
|
||||
Str text;
|
||||
};
|
||||
static Search search;
|
||||
|
||||
static void
|
||||
backmap(Im *im)
|
||||
{
|
||||
@@ -16,7 +26,7 @@ Lang langs[] = {
|
||||
{LangJP, "hira", "kanji", transmap, backmap, dictqmap, nil, nil},
|
||||
{LangJPK, "kata", "kanji", transmap, backmap, 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},
|
||||
};
|
||||
int nlang = nelem(langs);
|
||||
@@ -44,13 +54,15 @@ static void
|
||||
show(void)
|
||||
{
|
||||
Drawcmd dc;
|
||||
Str *pre;
|
||||
int i, first, n;
|
||||
|
||||
if(!popup)
|
||||
return;
|
||||
sclear(&dc.pre);
|
||||
if(!mapget(im.l->map, &im.pre, &dc.pre))
|
||||
dc.pre = im.pre;
|
||||
pre = search.on ? &search.text : &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;
|
||||
n = im.nkouho - first;
|
||||
if(n > Maxdisp) n = Maxdisp;
|
||||
@@ -58,6 +70,9 @@ show(void)
|
||||
dc.sel = im.sel >= 0 ? im.sel - first : -1;
|
||||
for(i = 0; i < n; 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);
|
||||
}
|
||||
|
||||
@@ -110,7 +125,7 @@ commit(Str *com)
|
||||
{
|
||||
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);
|
||||
else
|
||||
sappend(com, &im.pre);
|
||||
@@ -209,13 +224,240 @@ transmap(Im *im, Rune c)
|
||||
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
|
||||
keystroke(u32int ks, u32int mod, Str *com)
|
||||
{
|
||||
int n, off;
|
||||
Rune c;
|
||||
|
||||
if(ks == Ksuper || ks == Kshift)
|
||||
return 1;
|
||||
if(search.on)
|
||||
return searchkey(ks, mod, com);
|
||||
if(ks == Kdown || ks == Kup){
|
||||
if(im.nkouho == 0)
|
||||
return 0;
|
||||
@@ -271,14 +513,18 @@ keystroke(u32int ks, u32int mod, Str *com)
|
||||
return 0;
|
||||
}
|
||||
if(mod & Mctrl){
|
||||
reset();
|
||||
if(ks >= 'a' && ks <= 'z')
|
||||
ks -= 'a' - 1;
|
||||
if(ks == 0x10){
|
||||
popup = !popup;
|
||||
c = ctrlkey(ks);
|
||||
if(c == LangEMOJI){
|
||||
startsearch(com);
|
||||
return 1;
|
||||
}
|
||||
if(setlang(ks))
|
||||
if(c == 0x10){
|
||||
popup = !popup;
|
||||
show();
|
||||
return 1;
|
||||
}
|
||||
reset();
|
||||
if(setlang(c))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -305,6 +551,8 @@ init(void)
|
||||
{
|
||||
memset(&im, 0, sizeof(im));
|
||||
im.l = getlang(LangEN);
|
||||
memset(&search, 0, sizeof search);
|
||||
visible = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -316,15 +564,15 @@ imhandlekey(Keyreq *kr)
|
||||
sclear(&res.preedit);
|
||||
res.eaten = keystroke(kr->ks, kr->mod, &res.commit);
|
||||
if(kr->want)
|
||||
res.preedit = im.pre;
|
||||
res.preedit = search.on ? search.text : im.pre;
|
||||
chansend(kr->reply, &res);
|
||||
}
|
||||
|
||||
void
|
||||
imthread(void*)
|
||||
{
|
||||
static Dictres res;
|
||||
Keyreq kr;
|
||||
Dictres res;
|
||||
Alt alts[] = {
|
||||
{keyc, &kr, CHANRCV, nil},
|
||||
{dictresc, &res, CHANRCV, nil},
|
||||
@@ -339,7 +587,8 @@ imthread(void*)
|
||||
imhandlekey(&kr);
|
||||
break;
|
||||
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);
|
||||
show();
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ dictionary_candidates(struct ct *t)
|
||||
dictlookup(&req, &res);
|
||||
if(!CT_EQ_INT(t, 2, res.nkouho))
|
||||
goto cleanup;
|
||||
CT_EQ_INT(t, LangJP, res.lang);
|
||||
CT_EQ_INT(t, 0, scmp(&req.pre, &res.key));
|
||||
checkstr(t, "candidate 1", "候補1", &res.kouho[0]);
|
||||
checkstr(t, "candidate 2", "候補2", &res.kouho[1]);
|
||||
@@ -44,6 +45,7 @@ dictionary_candidates(struct ct *t)
|
||||
dictlookup(&req, &res);
|
||||
if(!CT_EQ_INT(t, Maxkouho, res.nkouho))
|
||||
goto cleanup;
|
||||
CT_EQ_INT(t, LangJP, res.lang);
|
||||
CT_EQ_INT(t, 0, scmp(&req.pre, &res.key));
|
||||
checkstr(t, "first capped candidate", "c00", &res.kouho[0]);
|
||||
checkstr(t, "last capped candidate", "c31", &res.kouho[31]);
|
||||
@@ -81,6 +83,7 @@ dictionary_misses_clear_result(struct ct *t)
|
||||
if(res.nkouho != 0)
|
||||
CT_ERRORF(t, "%s: want 0 candidates, got %d",
|
||||
cases[i].name, res.nkouho);
|
||||
CT_EQ_INT(t, LangJP, res.lang);
|
||||
checkstr(t, cases[i].name, cases[i].pre, &res.key);
|
||||
}
|
||||
hmapfree(lang->dict);
|
||||
|
||||
@@ -255,3 +255,177 @@ engine_language_switch_state(struct ct *t)
|
||||
}
|
||||
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_language_switch_state(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_misses_clear_result(struct ct*);
|
||||
|
||||
|
||||
@@ -80,6 +80,9 @@ static const struct ct_test tests[] = {
|
||||
{ "engine/commit-contract", engine_commit_contract },
|
||||
{ "engine/language-switch-state", engine_language_switch_state },
|
||||
{ "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/misses-clear-result", dictionary_misses_clear_result },
|
||||
};
|
||||
@@ -89,7 +92,7 @@ threadmain(int argc, char **argv)
|
||||
{
|
||||
int i, status;
|
||||
|
||||
drawc = chancreate(sizeof(Drawcmd), 4);
|
||||
drawc = chancreate(sizeof(Drawcmd), 1024);
|
||||
keyc = chancreate(sizeof(Keyreq), 0);
|
||||
dictreqc = chancreate(sizeof(Dictreq), 64);
|
||||
dictresc = chancreate(sizeof(Dictres), 0);
|
||||
|
||||
23
win.c
23
win.c
@@ -90,16 +90,18 @@ fill(u32int *buf, int n, u32int color)
|
||||
static void
|
||||
drawkouho(Drawcmd *dc, int first, int n, int w, int h)
|
||||
{
|
||||
int sely, y, i;
|
||||
int npre, sely, y, i;
|
||||
Str *s;
|
||||
|
||||
fill(img, w * h, Colbg);
|
||||
drawstr(img, 0, 0, dc->pre.r, dc->pre.n, w, h);
|
||||
if(dc->sel >= 0){
|
||||
sely = Fontsz + dc->sel * Fontsz;
|
||||
npre = dc->pre.n != 0;
|
||||
if(npre)
|
||||
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);
|
||||
}
|
||||
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];
|
||||
putfont(img, w, h, 0, y, '1' + i + Asciitofull);
|
||||
drawstr(img, 2*Fontsz, y, s->r, s->n, w, h);
|
||||
@@ -124,13 +126,18 @@ winhide(void)
|
||||
static void
|
||||
winshow(Drawcmd *dc)
|
||||
{
|
||||
int px, py, w, h, i, n, maxw;
|
||||
int npre, px, py, w, h, i, n, maxw;
|
||||
u32int vals[4];
|
||||
xcb_query_pointer_reply_t *ptr;
|
||||
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);
|
||||
n = dc->nkouho;
|
||||
maxw = dc->pre.n;
|
||||
for(i = 0; i < n; i++)
|
||||
maxw = max(maxw, dc->kouho[i].n);
|
||||
@@ -140,7 +147,7 @@ winshow(Drawcmd *dc)
|
||||
px = ptr->root_x + 10;
|
||||
py = ptr->root_y + 10;
|
||||
free(ptr);
|
||||
vals[3] = h = (n + 1) * Fontsz;
|
||||
vals[3] = h = (n + npre) * Fontsz;
|
||||
vals[2] = w = (maxw + 3) * Fontsz;
|
||||
vals[1] = py = max(0, min(py, scr->height_in_pixels - h));
|
||||
vals[0] = px = max(0, min(px, scr->width_in_pixels - w));
|
||||
|
||||
Reference in New Issue
Block a user