Compare commits

..

11 Commits

Author SHA1 Message Date
a94d55c541 fix vietnamese telex: qu-/gi- onset tone placement and dd+tone
transvi fixes:

1. qu-/gi- onset tone placement. The u after q, and the i after g when a
   vowel follows, are onset glides rather than the rime nucleus, so the
   tone must skip them: qua -> quá (was qúa), gia -> giá. The onset was
   previously passed straight through to the app, so transvi never saw it
   and toned the glide. Keep the onset in the preedit by adding qu-/gi-
   clusters to telex.map (mktelex.py onsets(), appended additively to the
   curated map), and add onsetglide() so transvi skips the glide. gi- with
   no following vowel keeps i as the nucleus (gì, gìn).

2. A tone key on a vowel-less preedit (e.g. "đ" from dd) now commits the
   preedit and lets the tone key pass through (eat=0), matching the engine
   commit-on-passthrough invariant, instead of eating it into the commit.

Verified against the running engine: qua/quan/quay/quê/quên/quyển,
gia/già/giàu/giữ/giúp/giống, gì/gìn, dd+s; unchanged mua->mùa, của, lúa;
all non-qu/gi words byte-identical to before.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 13:14:31 +09:00
aefe9bc618 fix gtk: commit pending text on passthrough keys
The GTK IM module only emitted the commit signal when the key was
eaten (r != 0). But when a non-matching key is pressed mid-composition
the engine commits the pending preedit and returns eaten=0 so the raw
key passes through, sending a commit string with eaten=0. GTK dropped
it, silently losing the composed text (e.g. Hangul "ㅇ" + "?" yielded
only "?").

Commit whenever a commit string is present, matching the wayland, ibus
and xim frontends.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 12:50:32 +09:00
bd2c1aeaca add emoji.src 2026-05-29 02:35:52 +09:00
f686edd198 fix gtk predit window 2026-05-29 02:28:49 +09:00
7e69827c13 passthrough unmatched keys 2026-05-28 23:38:23 +09:00
795353609b popup tooltip hint 2026-05-28 20:22:27 +09:00
28b48d997c split wayland commit cycles 2026-05-28 20:22:27 +09:00
f4347b70cc default popup off 2026-05-28 19:07:28 +09:00
69e92de010 wait for compositor 2026-05-28 19:04:41 +09:00
293313652f gtk inline preedit 2026-05-28 18:50:42 +09:00
b842c724e2 add popup toggle 2026-05-28 18:10:41 +09:00
14 changed files with 1081 additions and 248 deletions

View File

@@ -51,6 +51,7 @@ Switch input modes with Ctrl + key:
T English T English
V Vietnamese (Telex) V Vietnamese (Telex)
E Emoji E Emoji
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.

View File

@@ -12,6 +12,8 @@ struct Im
{ {
GtkIMContext parent; GtkIMContext parent;
int fd; int fd;
char pre[256];
int prelen;
}; };
typedef struct ImClass ImClass; typedef struct ImClass ImClass;
@@ -44,8 +46,8 @@ srvconnect(Im *im)
static int static int
readresp(Im *im, char *buf, int bufsz) readresp(Im *im, char *buf, int bufsz)
{ {
unsigned char hdr[2]; unsigned char hdr[2], pl;
int n; int n, was;
if(read(im->fd, hdr, 2) != 2) if(read(im->fd, hdr, 2) != 2)
return -1; return -1;
@@ -56,6 +58,21 @@ readresp(Im *im, char *buf, int bufsz)
return -1; return -1;
buf[n] = '\0'; buf[n] = '\0';
} }
if(read(im->fd, &pl, 1) != 1)
return -1;
if(pl >= sizeof(im->pre))
return -1;
was = im->prelen;
if(pl > 0 && read(im->fd, im->pre, pl) != pl)
return -1;
im->pre[pl] = '\0';
im->prelen = pl;
if(was == 0 && pl > 0)
g_signal_emit_by_name(im, "preedit-start");
if(was != 0 || pl != 0)
g_signal_emit_by_name(im, "preedit-changed");
if(was > 0 && pl == 0)
g_signal_emit_by_name(im, "preedit-end");
return hdr[0]; return hdr[0];
} }
@@ -92,7 +109,7 @@ sendreset(Im *im)
if(im->fd < 0) if(im->fd < 0)
return; return;
buf[0] = 0; buf[0] = 1;
buf[1] = 0; buf[1] = 0;
buf[2] = Kesc & 0xff; buf[2] = Kesc & 0xff;
buf[3] = Kesc >> 8; buf[3] = Kesc >> 8;
@@ -119,7 +136,7 @@ kpress(GtkIMContext *ctx, GdkEventKey *ev)
if(key == 0) if(key == 0)
return FALSE; return FALSE;
mod = mget(ev->state); mod = mget(ev->state);
buf[0] = 0; buf[0] = 1;
buf[1] = mod; buf[1] = mod;
buf[2] = key & 0xff; buf[2] = key & 0xff;
buf[3] = key >> 8; buf[3] = key >> 8;
@@ -128,11 +145,34 @@ kpress(GtkIMContext *ctx, GdkEventKey *ev)
r = readresp(im, resp, sizeof(resp)); r = readresp(im, resp, sizeof(resp));
if(r < 0) if(r < 0)
return FALSE; return FALSE;
if(r != 0 && resp[0] != '\0') if(resp[0] != '\0')
g_signal_emit_by_name(ctx, "commit", resp); g_signal_emit_by_name(ctx, "commit", resp);
return r != 0; return r != 0;
} }
static void
getpreedit(GtkIMContext *ctx, gchar **str, PangoAttrList **attrs,
gint *cursor_pos)
{
Im *im;
PangoAttribute *u;
im = (Im*)ctx;
if(str)
*str = g_strdup(im->pre);
if(attrs){
*attrs = pango_attr_list_new();
if(im->prelen > 0){
u = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
u->start_index = 0;
u->end_index = im->prelen;
pango_attr_list_insert(*attrs, u);
}
}
if(cursor_pos)
*cursor_pos = g_utf8_strlen(im->pre, -1);
}
static void static void
reset(GtkIMContext *ctx) reset(GtkIMContext *ctx)
{ {
@@ -171,6 +211,7 @@ classinit(ImClass *klass)
ic = GTK_IM_CONTEXT_CLASS(klass); ic = GTK_IM_CONTEXT_CLASS(klass);
oc = G_OBJECT_CLASS(klass); oc = G_OBJECT_CLASS(klass);
ic->filter_keypress = kpress; ic->filter_keypress = kpress;
ic->get_preedit_string = getpreedit;
ic->reset = reset; ic->reset = reset;
ic->focus_out = focusout; ic->focus_out = focusout;
oc->finalize = finalize; oc->finalize = finalize;

1
ko.c
View File

@@ -203,7 +203,6 @@ transko(Im *im, Rune c)
e.s = im->pre; e.s = im->pre;
sclear(&im->pre); sclear(&im->pre);
} }
sputr(&e.s, c);
return e; return e;
} }

View File

@@ -1,179 +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 α
al α
alp α
alph α
alpha α
b β
be β
bet β
beta β
c χ
ch χ
chi χ
d ° δ ↓
D Δ
de ° δ
De Δ
deg °
del δ
delt δ
delta δ
dn ↓
_e ₑ
e ε η
ep ε
eps ε
et η
eta η
g γ
G Γ
ga γ
Ga Γ
gam γ
gamm γ
gamma γ
^i ⁱ
i ∞ ι
I ∫
II ∫
in ∞
inf ∞
io ι
iot ι
iota ι
k κ
ka κ
kap κ
kapp κ
kappa κ
l λ
L Λ
la λ
La Λ
lam λ
lamb λ
lambd λ
lambda λ
m × μ
mu × μ
mul ×
^n ⁿ
n ν
nu ν
_o ₒ
o ω ●
O Ω
om ω
Om Ω
ome ω
omeg ω
omega ω
oo ●
p φ π ψ
P Φ Π ∏ Ψ
ph φ
Ph Φ
phi φ
pi π
Pi Π
PP ∏
ps ψ
Ps Ψ
psi ψ
r ρ
rh ρ
rho ρ
s σ
S Σ ∑
si σ
Si Σ
sig σ
sigm σ
sigma σ
sq √
SS ∑
t τ θ
T Θ
ta τ
tau τ
th θ
Th Θ
the θ
thet θ
theta θ
u ↑ υ
up ↑ υ
ups υ
v ✓
vv ✓
_x ₓ
x ξ ✗
X Ξ
xi ξ
Xi Ξ
xx ✗
z ζ
ze ζ
zet ζ
zeta ζ

View File

@@ -16,6 +16,7 @@
:) ☺ :) ☺
< < < <
<- ← <- ←
<3 ♥
<= ≤ <= ≤
<> ≠ <> ≠
= = = =
@@ -23,42 +24,66 @@
=> ⇒ => ⇒
> > > >
>= ≥ >= ≥
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 ⁰
_0 ₀ _0 ₀
^1 ¹
_1 ₁ _1 ₁
^2 ²
_2 ₂ _2 ₂
<3 ♥
^3 ³
_3 ₃ _3 ₃
^4 ⁴
_4 ₄ _4 ₄
^5 ⁵
_5 ₅ _5 ₅
^6 ⁶
_6 ₆ _6 ₆
^7 ⁷
_7 ₇ _7 ₇
^8 ⁸
_8 ₈ _8 ₈
^9 ⁹
_9 ₉ _9 ₉
_= ₌
_a ₐ _a ₐ
_e ₑ
_o ₒ
_x ₓ
a a a a
al al al al
alp alp alp alp
@@ -72,31 +97,27 @@ c c
ch ch ch ch
chi χ chi χ
d d d d
D D
de de de de
De Δ
deg ° deg °
del del del del
delt delt delt delt
delta δ delta δ
dn ↓ dn ↓
_e ₑ
e e e e
ep ep ep ep
eps ε eps ε
et et et et
eta η eta η
f f
fu fu
fuc fuc
fuck 凸
g g g g
G G
ga ga ga ga
Ga Γ
gam gam gam gam
gamm gamm gamm gamm
gamma γ gamma γ
^i ⁱ
i i i i
I I
II ∫
in in in in
inf ∞ inf ∞
io io io io
@@ -108,9 +129,7 @@ kap kap
kapp kapp kapp kapp
kappa κ kappa κ
l l l l
L L
la la la la
La Λ
lam lam lam lam
lamb lamb lamb lamb
lambd lambd lambd lambd
@@ -118,47 +137,33 @@ lambda λ
m m m m
mu μ mu μ
mul × mul ×
^n ⁿ
n n n n
nu ν nu ν
_o ₒ
o o o o
O O
om om om om
Om Ω
ome ome ome ome
omeg omeg omeg omeg
omega ω omega ω
oo ● oo ●
p p p p
P P
ph ph ph ph
Ph Φ
phi φ phi φ
pi π pi π
Pi Π
PP ∏
ps ps ps ps
Ps Ψ
psi ψ psi ψ
r r r r
rh rh rh rh
rho ρ rho ρ
s s s s
S S
si si si si
Si Σ
sig sig sig sig
sigm sigm sigm sigm
sigma σ sigma σ
sq √ sq √
SS ∑
t t t t
T T
ta ta ta ta
tau τ tau τ
th th th th
Th Θ
the the the the
thet thet thet thet
theta θ theta θ
@@ -167,13 +172,12 @@ up ↑
ups υ ups υ
v v v v
vv ✓ vv ✓
_x ₓ
x x x x
X X
xi ξ xi ξ
Xi Ξ
xx ✗ xx ✗
z z z z
ze ze ze ze
zet zet zet zet
zeta ζ zeta ζ
~ ~
~= ≈

View File

@@ -57,6 +57,7 @@ dn ↓
_e ₑ _e ₑ
eps ε eps ε
eta η eta η
fuck 凸
gamma γ gamma γ
Ga Γ Ga Γ
^i ⁱ ^i ⁱ

View File

@@ -31,7 +31,10 @@ upper = str.maketrans(
def addtone(v, t): def addtone(v, t):
return v.translate(tone[t]) return v.translate(tone[t])
entries = []
def emit(input, output): def emit(input, output):
entries.append((input, output))
print(f"{input}\t{output}") print(f"{input}\t{output}")
def up(s): def up(s):
c = s[0].translate(upper) c = s[0].translate(upper)
@@ -147,6 +150,24 @@ def final():
for t in tone: for t in tone:
emit(i+c+t, o.replace(v, addtone(v, t), 1)+c) emit(i+c+t, o.replace(v, addtone(v, t), 1)+c)
def onsets():
# Keep the qu-/gi- onset in the preedit so the tone lands on the rime
# nucleus, not on the onset glide (qua->quá not qúa, gia->giá not gía).
# transvi (onsetglide) knows to skip the glide; here we only need the
# composed clusters to exist so the preedit accumulates them.
vowels = set("aeiouy")
tones = set("sfrxj")
base = [(i, o) for (i, o) in list(entries)
if i and i[0] in vowels and not (set(i) & tones)]
for i, o in base:
if i[0] != 'u': # no qu+u syllable; u is the glide
emit("qu" + i, "qu" + o)
emit("gi" + i, "gi" + o)
# gi- with the i as nucleus (no following vowel): gì, gìn, gìm, ...
for c in ["", "c", "m", "n", "p", "t", "ch", "ng", "nh"]:
if c:
emit("gi" + c, "gi" + c)
vowel1() vowel1()
vowel2() vowel2()
vowel3() vowel3()
@@ -157,3 +178,4 @@ tone1mod()
tone2mod() tone2mod()
escape() escape()
final() final()
onsets()

View File

@@ -587,3 +587,903 @@ Yt Yt
y y y y
Y Y Y Y
\ \ \ \
qua qua
Qua Qua
gia gia
Gia Gia
quaa quâ
Quaa Quâ
giaa giâ
Giaa Giâ
quaaa quaa
Quaaa Quaa
giaaa giaa
Giaaa Giaa
quaac quâc
Quaac Quâc
giaac giâc
Giaac Giâc
quaach quâch
Quaach Quâch
giaach giâch
Giaach Giâch
quaam quâm
Quaam Quâm
giaam giâm
Giaam Giâm
quaan quân
Quaan Quân
giaan giân
Giaan Giân
quaang quâng
Quaang Quâng
giaang giâng
Giaang Giâng
quaanh quânh
Quaanh Quânh
giaanh giânh
Giaanh Giânh
quaap quâp
Quaap Quâp
giaap giâp
Giaap Giâp
quaat quât
Quaat Quât
giaat giât
Giaat Giât
quac quac
Quac Quac
giac giac
Giac Giac
quach quach
Quach Quach
giach giach
Giach Giach
quai quai
Quai Quai
giai giai
Giai Giai
quaic quaic
Quaic Quaic
giaic giaic
Giaic Giaic
quaich quaich
Quaich Quaich
giaich giaich
Giaich Giaich
quaim quaim
Quaim Quaim
giaim giaim
Giaim Giaim
quain quain
Quain Quain
giain giain
Giain Giain
quaing quaing
Quaing Quaing
giaing giaing
Giaing Giaing
quainh quainh
Quainh Quainh
giainh giainh
Giainh Giainh
quaip quaip
Quaip Quaip
giaip giaip
Giaip Giaip
quait quait
Quait Quait
giait giait
Giait Giait
quam quam
Quam Quam
giam giam
Giam Giam
quan quan
Quan Quan
gian gian
Gian Gian
quang quang
Quang Quang
giang giang
Giang Giang
quanh quanh
Quanh Quanh
gianh gianh
Gianh Gianh
quao quao
Quao Quao
giao giao
Giao Giao
quaoc quaoc
Quaoc Quaoc
giaoc giaoc
Giaoc Giaoc
quaoch quaoch
Quaoch Quaoch
giaoch giaoch
Giaoch Giaoch
quaom quaom
Quaom Quaom
giaom giaom
Giaom Giaom
quaon quaon
Quaon Quaon
giaon giaon
Giaon Giaon
quaong quaong
Quaong Quaong
giaong giaong
Giaong Giaong
quaonh quaonh
Quaonh Quaonh
giaonh giaonh
Giaonh Giaonh
quaop quaop
Quaop Quaop
giaop giaop
Giaop Giaop
quaot quaot
Quaot Quaot
giaot giaot
Giaot Giaot
quap quap
Quap Quap
giap giap
Giap Giap
quat quat
Quat Quat
giat giat
Giat Giat
quau quau
Quau Quau
giau giau
Giau Giau
quauc quauc
Quauc Quauc
giauc giauc
Giauc Giauc
quauch quauch
Quauch Quauch
giauch giauch
Giauch Giauch
quaum quaum
Quaum Quaum
giaum giaum
Giaum Giaum
quaun quaun
Quaun Quaun
giaun giaun
Giaun Giaun
quaung quaung
Quaung Quaung
giaung giaung
Giaung Giaung
quaunh quaunh
Quaunh Quaunh
giaunh giaunh
Giaunh Giaunh
quaup quaup
Quaup Quaup
giaup giaup
Giaup Giaup
quaut quaut
Quaut Quaut
giaut giaut
Giaut Giaut
quaw quă
Quaw Quă
giaw giă
Giaw Giă
quawc quăc
Quawc Quăc
giawc giăc
Giawc Giăc
quawch quăch
Quawch Quăch
giawch giăch
Giawch Giăch
quawm quăm
Quawm Quăm
giawm giăm
Giawm Giăm
quawn quăn
Quawn Quăn
giawn giăn
Giawn Giăn
quawng quăng
Quawng Quăng
giawng giăng
Giawng Giăng
quawnh quănh
Quawnh Quănh
giawnh giănh
Giawnh Giănh
quawp quăp
Quawp Quăp
giawp giăp
Giawp Giăp
quawt quăt
Quawt Quăt
giawt giăt
Giawt Giăt
quaww quaw
Quaww Quaw
giaww giaw
Giaww Giaw
quay quay
Quay Quay
giay giay
Giay Giay
quayc quayc
Quayc Quayc
giayc giayc
Giayc Giayc
quaych quaych
Quaych Quaych
giaych giaych
Giaych Giaych
quaym quaym
Quaym Quaym
giaym giaym
Giaym Giaym
quayn quayn
Quayn Quayn
giayn giayn
Giayn Giayn
quayng quayng
Quayng Quayng
giayng giayng
Giayng Giayng
quaynh quaynh
Quaynh Quaynh
giaynh giaynh
Giaynh Giaynh
quayp quayp
Quayp Quayp
giayp giayp
Giayp Giayp
quayt quayt
Quayt Quayt
giayt giayt
Giayt Giayt
quec quec
Quec Quec
giec giec
Giec Giec
quech quech
Quech Quech
giech giech
Giech Giech
que que
Que Que
gie gie
Gie Gie
queec quêc
Queec Quêc
gieec giêc
Gieec Giêc
queech quêch
Queech Quêch
gieech giêch
Gieech Giêch
quee quê
Quee Quê
giee giê
Giee Giê
queee quee
Queee Quee
gieee giee
Gieee Giee
queem quêm
Queem Quêm
gieem giêm
Gieem Giêm
queen quên
Queen Quên
gieen giên
Gieen Giên
queeng quêng
Queeng Quêng
gieeng giêng
Gieeng Giêng
queenh quênh
Queenh Quênh
gieenh giênh
Gieenh Giênh
queep quêp
Queep Quêp
gieep giêp
Gieep Giêp
queet quêt
Queet Quêt
gieet giêt
Gieet Giêt
quem quem
Quem Quem
giem giem
Giem Giem
quen quen
Quen Quen
gien gien
Gien Gien
queng queng
Queng Queng
gieng gieng
Gieng Gieng
quenh quenh
Quenh Quenh
gienh gienh
Gienh Gienh
quep quep
Quep Quep
giep giep
Giep Giep
quet quet
Quet Quet
giet giet
Giet Giet
queu queu
Queu Queu
gieu gieu
Gieu Gieu
quich quich
Quich Quich
giich giich
Giich Giich
quic quic
Quic Quic
giic giic
Giic Giic
quieech quiêch
Quieech Quiêch
giieech giiêch
Giieech Giiêch
quieec quiêc
Quieec Quiêc
giieec giiêc
Giieec Giiêc
quiee quiê
Quiee Quiê
giiee giiê
Giiee Giiê
quieem quiêm
Quieem Quiêm
giieem giiêm
Giieem Giiêm
quieeng quiêng
Quieeng Quiêng
giieeng giiêng
Giieeng Giiêng
quieenh quiênh
Quieenh Quiênh
giieenh giiênh
Giieenh Giiênh
quieen quiên
Quieen Quiên
giieen giiên
Giieen Giiên
quieep quiêp
Quieep Quiêp
giieep giiêp
Giieep Giiêp
quieet quiêt
Quieet Quiêt
giieet giiêt
Giieet Giiêt
quieeu quiêu
Quieeu Quiêu
giieeu giiêu
Giieeu Giiêu
quie quie
Quie Quie
giie giie
Giie Giie
qui qui
Qui Qui
gii gii
Gii Gii
quim quim
Quim Quim
giim giim
Giim Giim
quing quing
Quing Quing
giing giing
Giing Giing
quinh quinh
Quinh Quinh
giinh giinh
Giinh Giinh
quin quin
Quin Quin
giin giin
Giin Giin
quip quip
Quip Quip
giip giip
Giip Giip
quit quit
Quit Quit
giit giit
Giit Giit
quiu quiu
Quiu Quiu
giiu giiu
Giiu Giiu
quoach quoach
Quoach Quoach
gioach gioach
Gioach Gioach
quoac quoac
Quoac Quoac
gioac gioac
Gioac Gioac
quoai quoai
Quoai Quoai
gioai gioai
Gioai Gioai
quoam quoam
Quoam Quoam
gioam gioam
Gioam Gioam
quoang quoang
Quoang Quoang
gioang gioang
Gioang Gioang
quoanh quoanh
Quoanh Quoanh
gioanh gioanh
Gioanh Gioanh
quoan quoan
Quoan Quoan
gioan gioan
Gioan Gioan
quoa quoa
Quoa Quoa
gioa gioa
Gioa Gioa
quoap quoap
Quoap Quoap
gioap gioap
Gioap Gioap
quoat quoat
Quoat Quoat
gioat gioat
Gioat Gioat
quoawch quoăch
Quoawch Quoăch
gioawch gioăch
Gioawch Gioăch
quoawc quoăc
Quoawc Quoăc
gioawc gioăc
Gioawc Gioăc
quoawm quoăm
Quoawm Quoăm
gioawm gioăm
Gioawm Gioăm
quoawng quoăng
Quoawng Quoăng
gioawng gioăng
Gioawng Gioăng
quoawnh quoănh
Quoawnh Quoănh
gioawnh gioănh
Gioawnh Gioănh
quoawn quoăn
Quoawn Quoăn
gioawn gioăn
Gioawn Gioăn
quoaw quoă
Quoaw Quoă
gioaw gioă
Gioaw Gioă
quoawp quoăp
Quoawp Quoăp
gioawp gioăp
Gioawp Gioăp
quoawt quoăt
Quoawt Quoăt
gioawt gioăt
Gioawt Gioăt
quoay quoay
Quoay Quoay
gioay gioay
Gioay Gioay
quoch quoch
Quoch Quoch
gioch gioch
Gioch Gioch
quoc quoc
Quoc Quoc
gioc gioc
Gioc Gioc
quoe quoe
Quoe Quoe
gioe gioe
Gioe Gioe
quoich quoich
Quoich Quoich
gioich gioich
Gioich Gioich
quoic quoic
Quoic Quoic
gioic gioic
Gioic Gioic
quoim quoim
Quoim Quoim
gioim gioim
Gioim Gioim
quoing quoing
Quoing Quoing
gioing gioing
Gioing Gioing
quoinh quoinh
Quoinh Quoinh
gioinh gioinh
Gioinh Gioinh
quoin quoin
Quoin Quoin
gioin gioin
Gioin Gioin
quoi quoi
Quoi Quoi
gioi gioi
Gioi Gioi
quoip quoip
Quoip Quoip
gioip gioip
Gioip Gioip
quoit quoit
Quoit Quoit
gioit gioit
Gioit Gioit
quom quom
Quom Quom
giom giom
Giom Giom
quong quong
Quong Quong
giong giong
Giong Giong
quonh quonh
Quonh Quonh
gionh gionh
Gionh Gionh
quon quon
Quon Quon
gion gion
Gion Gion
quo quo
Quo Quo
gio gio
Gio Gio
quooch quôch
Quooch Quôch
giooch giôch
Giooch Giôch
quooc quôc
Quooc Quôc
giooc giôc
Giooc Giôc
quoom quôm
Quoom Quôm
gioom giôm
Gioom Giôm
quoong quông
Quoong Quông
gioong giông
Gioong Giông
quoonh quônh
Quoonh Quônh
gioonh giônh
Gioonh Giônh
quoon quôn
Quoon Quôn
gioon giôn
Gioon Giôn
quoo quô
Quoo Quô
gioo giô
Gioo Giô
quooo quoo
Quooo Quoo
giooo gioo
Giooo Gioo
quoop quôp
Quoop Quôp
gioop giôp
Gioop Giôp
quoot quôt
Quoot Quôt
gioot giôt
Gioot Giôt
quop quop
Quop Quop
giop giop
Giop Giop
quot quot
Quot Quot
giot giot
Giot Giot
quowch quơch
Quowch Quơch
giowch giơch
Giowch Giơch
quowc quơc
Quowc Quơc
giowc giơc
Giowc Giơc
quowm quơm
Quowm Quơm
giowm giơm
Giowm Giơm
quowng quơng
Quowng Quơng
giowng giơng
Giowng Giơng
quownh quơnh
Quownh Quơnh
giownh giơnh
Giownh Giơnh
quown quơn
Quown Quơn
giown giơn
Giown Giơn
quow quơ
Quow Quơ
giow giơ
Giow Giơ
quowp quơp
Quowp Quơp
giowp giơp
Giowp Giơp
quowt quơt
Quowt Quơt
giowt giơt
Giowt Giơt
quoww quow
Quoww Quow
gioww giow
Gioww Giow
giuaach giuâch
Giuaach Giuâch
giuaac giuâc
Giuaac Giuâc
giuaam giuâm
Giuaam Giuâm
giuaang giuâng
Giuaang Giuâng
giuaanh giuânh
Giuaanh Giuânh
giuaan giuân
Giuaan Giuân
giuaap giuâp
Giuaap Giuâp
giuaat giuât
Giuaat Giuât
giuaa giuâ
Giuaa Giuâ
giua giua
Giua Giua
giuch giuch
Giuch Giuch
giuc giuc
Giuc Giuc
giuich giuich
Giuich Giuich
giuic giuic
Giuic Giuic
giuim giuim
Giuim Giuim
giuing giuing
Giuing Giuing
giuinh giuinh
Giuinh Giuinh
giuin giuin
Giuin Giuin
giuip giuip
Giuip Giuip
giuit giuit
Giuit Giuit
giui giui
Giui Giui
gium gium
Gium Gium
giung giung
Giung Giung
giunh giunh
Giunh Giunh
giun giun
Giun Giun
giuooch giuôch
Giuooch Giuôch
giuooc giuôc
Giuooc Giuôc
giuooi giuôi
Giuooi Giuôi
giuoom giuôm
Giuoom Giuôm
giuoong giuông
Giuoong Giuông
giuoonh giuônh
Giuoonh Giuônh
giuoon giuôn
Giuoon Giuôn
giuoop giuôp
Giuoop Giuôp
giuoot giuôt
Giuoot Giuôt
giuoo giuô
Giuoo Giuô
giuo giuo
Giuo Giuo
giuowch giươch
Giuowch Giươch
giuowc giươc
Giuowc Giươc
giuowi giươi
Giuowi Giươi
giuowm giươm
Giuowm Giươm
giuowng giương
Giuowng Giương
giuownh giươnh
Giuownh Giươnh
giuown giươn
Giuown Giươn
giuowp giươp
Giuowp Giươp
giuowt giươt
Giuowt Giươt
giuow giươ
Giuow Giươ
giup giup
Giup Giup
giut giut
Giut Giut
giu giu
Giu Giu
giuwa giưa
Giuwa Giưa
giuwch giưch
Giuwch Giưch
giuwc giưc
Giuwc Giưc
giuwm giưm
Giuwm Giưm
giuwng giưng
Giuwng Giưng
giuwnh giưnh
Giuwnh Giưnh
giuwn giưn
Giuwn Giưn
giuwow giươ
Giuwow Giươ
giuwp giưp
Giuwp Giưp
giuwt giưt
Giuwt Giưt
giuw giư
Giuw Giư
giuww giuw
Giuww Giuw
giuya giuya
Giuya Giuya
giuych giuych
Giuych Giuych
giuyc giuyc
Giuyc Giuyc
giuyee giuyê
Giuyee Giuyê
giuym giuym
Giuym Giuym
giuyng giuyng
Giuyng Giuyng
giuynh giuynh
Giuynh Giuynh
giuyn giuyn
Giuyn Giuyn
giuyp giuyp
Giuyp Giuyp
giuyt giuyt
Giuyt Giuyt
giuy giuy
Giuy Giuy
quych quych
Quych Quych
giych giych
Giych Giych
quyc quyc
Quyc Quyc
giyc giyc
Giyc Giyc
quyeech quyêch
Quyeech Quyêch
giyeech giyêch
Giyeech Giyêch
quyeec quyêc
Quyeec Quyêc
giyeec giyêc
Giyeec Giyêc
quyeem quyêm
Quyeem Quyêm
giyeem giyêm
Giyeem Giyêm
quyeeng quyêng
Quyeeng Quyêng
giyeeng giyêng
Giyeeng Giyêng
quyeenh quyênh
Quyeenh Quyênh
giyeenh giyênh
Giyeenh Giyênh
quyeen quyên
Quyeen Quyên
giyeen giyên
Giyeen Giyên
quyeep quyêp
Quyeep Quyêp
giyeep giyêp
Giyeep Giyêp
quyeet quyêt
Quyeet Quyêt
giyeet giyêt
Giyeet Giyêt
quyeeu quyêu
Quyeeu Quyêu
giyeeu giyêu
Giyeeu Giyêu
quyee quyê
Quyee Quyê
giyee giyê
Giyee Giyê
quye quye
Quye Quye
giye giye
Giye Giye
quym quym
Quym Quym
giym giym
Giym Giym
quyng quyng
Quyng Quyng
giyng giyng
Giyng Giyng
quynh quynh
Quynh Quynh
giynh giynh
Giynh Giynh
quyn quyn
Quyn Quyn
giyn giyn
Giyn Giyn
quyp quyp
Quyp Quyp
giyp giyp
Giyp Giyp
quyt quyt
Quyt Quyt
giyt giyt
Giyt Giyt
quy quy
Quy Quy
giy giy
Giy Giy
gic gic
Gic Gic
gim gim
Gim Gim
gin gin
Gin Gin
gip gip
Gip Gip
git git
Git Git
gich gich
Gich Gich
ging ging
Ging Ging
ginh ginh
Ginh Ginh

3
run.sh
View File

@@ -1,8 +1,7 @@
#!/bin/sh #!/bin/sh
cd "$(dirname "$0")"
pkill strans pkill strans
pkill strans-xim
sleep 1 sleep 1
./strans map font & ./strans map font &
sleep 1 sleep 1

6
srv.c
View File

@@ -4,14 +4,14 @@
static char adir[40]; static char adir[40];
static void static void
sendkey(int fd, u32int ks, u32int mod) sendkey(int fd, u32int ks, u32int mod, int want)
{ {
Keyreq kr; Keyreq kr;
kr.fd = fd; kr.fd = fd;
kr.ks = ks; kr.ks = ks;
kr.mod = mod; kr.mod = mod;
kr.want = 0; kr.want = want;
chansend(keyc, &kr); chansend(keyc, &kr);
} }
@@ -24,7 +24,7 @@ clientthread(void *arg)
fd = (int)(uintptr)arg; fd = (int)(uintptr)arg;
threadsetname("client %d", fd); threadsetname("client %d", fd);
while(read(fd, req, 4) == 4) while(read(fd, req, 4) == 4)
sendkey(fd, req[2] | (req[3] << 8), req[1]); sendkey(fd, req[2] | (req[3] << 8), req[1], req[0]);
close(fd); close(fd);
} }

View File

@@ -2,6 +2,7 @@
#include "fn.h" #include "fn.h"
static Im im; static Im im;
static int popup = 0;
static void dictqmap(Im*); static void dictqmap(Im*);
static void static void
@@ -45,6 +46,8 @@ show(void)
Drawcmd dc; Drawcmd dc;
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)) if(!mapget(im.l->map, &im.pre, &dc.pre))
dc.pre = im.pre; dc.pre = im.pre;
@@ -182,10 +185,8 @@ transmap(Im *im, Rune c)
e.s = im->pre; e.s = im->pre;
sclear(&key); sclear(&key);
sputr(&key, c); sputr(&key, c);
if(!maplookup(t, &key, &e.dict)){ if(!maplookup(t, &key, &e.dict))
sputr(&e.s, c);
return e; return e;
}
e.eat = 1; e.eat = 1;
sputr(&e.next, c); sputr(&e.next, c);
return e; return e;
@@ -256,6 +257,10 @@ keystroke(u32int ks, u32int mod, Str *com)
reset(); reset();
if(ks >= 'a' && ks <= 'z') if(ks >= 'a' && ks <= 'z')
ks -= 'a' - 1; ks -= 'a' - 1;
if(ks == 0x10){
popup = !popup;
return 1;
}
if(setlang(ks)) if(setlang(ks))
return 1; return 1;
return 0; return 0;
@@ -266,14 +271,16 @@ keystroke(u32int ks, u32int mod, Str *com)
return 1; return 1;
} }
if(ks > 0x7f || ks == ' '){ if(ks > 0x7f || ks == ' '){
if(im.pre.n == 0)
return 0;
commit(com); commit(com);
sputr(com, ks); sputr(com, ks);
reset(); reset();
return 1; return 1;
} }
dotrans(ks, com); n = dotrans(ks, com);
show(); show();
return 1; return n;
} }
static void static void

36
vi.c
View File

@@ -89,22 +89,45 @@ applytone(Rune c, int tidx)
return c; return c;
} }
/*
* In qu- and gi- onsets the u/i is a glide that belongs to the onset,
* not the rime, so it must not bear the tone (qua -> quá, gia -> giá).
* The i of gi- is only a glide when another vowel follows; otherwise it
* is the nucleus itself (gì, gìn). Returns the rune index to skip, or -1.
*/
static int
onsetglide(Str *m)
{
Rune a, b;
int i;
if(m->n < 2)
return -1;
a = m->r[0];
b = removetone(m->r[1]);
if((a == 'q' || a == 'Q') && (b == 'u' || b == 'U'))
return 1;
if((a == 'g' || a == 'G') && (b == 'i' || b == 'I'))
for(i = 2; i < m->n; i++)
if(isvowel(removetone(m->r[i])))
return 1;
return -1;
}
Emit Emit
transvi(Im *im, Rune c) transvi(Im *im, Rune c)
{ {
Emit e; Emit e;
Str mapped, pre; Str mapped, pre;
int i, tidx, vi, last, penult; int i, tidx, vi, last, penult, glide;
Rune v, b1, b2; Rune v, b1, b2;
if(!istone(c) && c != 'z') if(!istone(c) && c != 'z')
return transmap(im, c); return transmap(im, c);
memset(&e, 0, sizeof e); memset(&e, 0, sizeof e);
if(im->pre.n == 0){ if(im->pre.n == 0)
sputr(&e.s, c);
return e; return e;
}
if(im->pre.r[im->pre.n - 1] == '\\'){ if(im->pre.r[im->pre.n - 1] == '\\'){
pre = im->pre; pre = im->pre;
pre.n--; pre.n--;
@@ -117,9 +140,12 @@ transvi(Im *im, Rune c)
} }
if(!mapget(im->l->map, &im->pre, &mapped)) if(!mapget(im->l->map, &im->pre, &mapped))
mapped = im->pre; mapped = im->pre;
glide = onsetglide(&mapped);
last = -1; last = -1;
penult = -1; penult = -1;
for(i = 0; i < mapped.n; i++){ for(i = 0; i < mapped.n; i++){
if(i == glide)
continue;
v = removetone(mapped.r[i]); v = removetone(mapped.r[i]);
if(isvowel(v)){ if(isvowel(v)){
penult = last; penult = last;
@@ -142,9 +168,7 @@ transvi(Im *im, Rune c)
} }
} }
if(vi < 0){ if(vi < 0){
e.eat = 1;
e.s = mapped; e.s = mapped;
sputr(&e.s, c);
return e; return e;
} }

View File

@@ -5,6 +5,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <poll.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <wayland-client.h> #include <wayland-client.h>
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
@@ -118,8 +119,10 @@ kpress(uint32_t time, uint32_t keycode, uint32_t state)
} }
mod = mget(); mod = mget();
sendkey(k, mod, com, sizeof(com), pre, sizeof(pre), &eaten); sendkey(k, mod, com, sizeof(com), pre, sizeof(pre), &eaten);
if(com[0] != '\0') if(com[0] != '\0'){
zwp_input_method_v2_commit_string(im, com); zwp_input_method_v2_commit_string(im, com);
zwp_input_method_v2_commit(im, imserial);
}
plen = strlen(pre); plen = strlen(pre);
zwp_input_method_v2_set_preedit_string(im, pre, plen, plen); zwp_input_method_v2_set_preedit_string(im, pre, plen, plen);
zwp_input_method_v2_commit(im, imserial); zwp_input_method_v2_commit(im, imserial);
@@ -321,11 +324,8 @@ waylandthread(void *_)
(void)_; (void)_;
threadsetname("wayland"); threadsetname("wayland");
dpy = wl_display_connect(nil); while((dpy = wl_display_connect(nil)) == nil)
if(dpy == nil){ poll(nil, 0, 1000);
fprint(2, "strans: wayland: cannot connect to display\n");
return;
}
xkb = xkb_context_new(XKB_CONTEXT_NO_FLAGS); xkb = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if(xkb == nil){ if(xkb == nil){
wl_display_disconnect(dpy); wl_display_disconnect(dpy);

14
win.c
View File

@@ -31,6 +31,8 @@ wininit(void)
{ {
int n; int n;
u32int mask, vals[4]; u32int mask, vals[4];
xcb_intern_atom_cookie_t c1, c2;
xcb_intern_atom_reply_t *r1, *r2;
conn = xcb_connect(nil, &n); conn = xcb_connect(nil, &n);
if(conn == nil || xcb_connection_has_error(conn)) if(conn == nil || xcb_connection_has_error(conn))
@@ -49,6 +51,18 @@ wininit(void)
xcb_create_window(conn, XCB_COPY_FROM_PARENT, win, scr->root, xcb_create_window(conn, XCB_COPY_FROM_PARENT, win, scr->root,
0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
scr->root_visual, mask, vals); scr->root_visual, mask, vals);
c1 = xcb_intern_atom(conn, 0,
strlen("_NET_WM_WINDOW_TYPE"), "_NET_WM_WINDOW_TYPE");
c2 = xcb_intern_atom(conn, 0,
strlen("_NET_WM_WINDOW_TYPE_TOOLTIP"),
"_NET_WM_WINDOW_TYPE_TOOLTIP");
r1 = xcb_intern_atom_reply(conn, c1, nil);
r2 = xcb_intern_atom_reply(conn, c2, nil);
if(r1 != nil && r2 != nil)
xcb_change_property(conn, XCB_PROP_MODE_REPLACE,
win, r1->atom, XCB_ATOM_ATOM, 32, 1, &r2->atom);
free(r1);
free(r2);
gc = xcb_generate_id(conn); gc = xcb_generate_id(conn);
xcb_create_gc(conn, gc, win, 0, nil); xcb_create_gc(conn, gc, win, 0, nil);
img = emalloc(Imgw * Imgh * sizeof(img[0])); img = emalloc(Imgw * Imgh * sizeof(img[0]));