Compare commits

...

9 Commits

Author SHA1 Message Date
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
12 changed files with 129 additions and 244 deletions

View File

@@ -51,6 +51,7 @@ Switch input modes with Ctrl + key:
T English
V Vietnamese (Telex)
E Emoji
P Toggle preedit/candidate popup window
Type romanized input. Select candidates with 1-9 or arrow keys.
Tab or Enter to commit.

View File

@@ -12,6 +12,8 @@ struct Im
{
GtkIMContext parent;
int fd;
char pre[256];
int prelen;
};
typedef struct ImClass ImClass;
@@ -44,8 +46,8 @@ srvconnect(Im *im)
static int
readresp(Im *im, char *buf, int bufsz)
{
unsigned char hdr[2];
int n;
unsigned char hdr[2], pl;
int n, was;
if(read(im->fd, hdr, 2) != 2)
return -1;
@@ -56,6 +58,21 @@ readresp(Im *im, char *buf, int bufsz)
return -1;
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];
}
@@ -92,7 +109,7 @@ sendreset(Im *im)
if(im->fd < 0)
return;
buf[0] = 0;
buf[0] = 1;
buf[1] = 0;
buf[2] = Kesc & 0xff;
buf[3] = Kesc >> 8;
@@ -119,7 +136,7 @@ kpress(GtkIMContext *ctx, GdkEventKey *ev)
if(key == 0)
return FALSE;
mod = mget(ev->state);
buf[0] = 0;
buf[0] = 1;
buf[1] = mod;
buf[2] = key & 0xff;
buf[3] = key >> 8;
@@ -133,6 +150,29 @@ kpress(GtkIMContext *ctx, GdkEventKey *ev)
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
reset(GtkIMContext *ctx)
{
@@ -171,6 +211,7 @@ classinit(ImClass *klass)
ic = GTK_IM_CONTEXT_CLASS(klass);
oc = G_OBJECT_CLASS(klass);
ic->filter_keypress = kpress;
ic->get_preedit_string = getpreedit;
ic->reset = reset;
ic->focus_out = focusout;
oc->finalize = finalize;

1
ko.c
View File

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

View File

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

3
run.sh
View File

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

6
srv.c
View File

@@ -4,14 +4,14 @@
static char adir[40];
static void
sendkey(int fd, u32int ks, u32int mod)
sendkey(int fd, u32int ks, u32int mod, int want)
{
Keyreq kr;
kr.fd = fd;
kr.ks = ks;
kr.mod = mod;
kr.want = 0;
kr.want = want;
chansend(keyc, &kr);
}
@@ -24,7 +24,7 @@ clientthread(void *arg)
fd = (int)(uintptr)arg;
threadsetname("client %d", fd);
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);
}

View File

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

4
vi.c
View File

@@ -101,10 +101,8 @@ transvi(Im *im, Rune c)
return transmap(im, c);
memset(&e, 0, sizeof e);
if(im->pre.n == 0){
sputr(&e.s, c);
if(im->pre.n == 0)
return e;
}
if(im->pre.r[im->pre.n - 1] == '\\'){
pre = im->pre;
pre.n--;

View File

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

14
win.c
View File

@@ -31,6 +31,8 @@ wininit(void)
{
int n;
u32int mask, vals[4];
xcb_intern_atom_cookie_t c1, c2;
xcb_intern_atom_reply_t *r1, *r2;
conn = xcb_connect(nil, &n);
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,
0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
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);
xcb_create_gc(conn, gc, win, 0, nil);
img = emalloc(Imgw * Imgh * sizeof(img[0]));