harden ipc and frontend recovery
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
CC = cc
|
CC = cc
|
||||||
CFLAGS = -Wall -O2
|
CFLAGS = -Wall -O2
|
||||||
|
|
||||||
bench: main.c
|
bench: main.c ../ipc.c ../ipc.h
|
||||||
$(CC) $(CFLAGS) -o $@ main.c
|
$(CC) $(CFLAGS) -I.. -o $@ main.c ../ipc.c
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f bench
|
rm -f bench
|
||||||
|
|||||||
32
bench/main.c
32
bench/main.c
@@ -1,3 +1,4 @@
|
|||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -5,13 +6,7 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
#include "../ipc.h"
|
||||||
enum {
|
|
||||||
Kback = 0xf008,
|
|
||||||
Kret = 0xf00d,
|
|
||||||
Kesc = 0xf01b,
|
|
||||||
Mctrl = 1<<2,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Key Key;
|
typedef struct Key Key;
|
||||||
struct Key {
|
struct Key {
|
||||||
@@ -93,8 +88,7 @@ dial(void)
|
|||||||
die("socket");
|
die("socket");
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
addr.sun_family = AF_UNIX;
|
addr.sun_family = AF_UNIX;
|
||||||
snprintf(addr.sun_path, sizeof(addr.sun_path),
|
snprintf(addr.sun_path, sizeof(addr.sun_path), IPCPATH, getuid());
|
||||||
"/tmp/strans.%d", getuid());
|
|
||||||
if(connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
|
if(connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
|
||||||
die("connect");
|
die("connect");
|
||||||
}
|
}
|
||||||
@@ -102,28 +96,20 @@ dial(void)
|
|||||||
static void
|
static void
|
||||||
sendkey(int key, int mod)
|
sendkey(int key, int mod)
|
||||||
{
|
{
|
||||||
unsigned char req[4];
|
unsigned char req[Ipcreqsz];
|
||||||
|
|
||||||
req[0] = 0;
|
ipcpackreq(req, 0, mod, key);
|
||||||
req[1] = mod;
|
if(ipcsend(fd, req, sizeof req) < 0)
|
||||||
req[2] = key & 0xff;
|
|
||||||
req[3] = (key >> 8) & 0xff;
|
|
||||||
if(write(fd, req, 4) != 4)
|
|
||||||
die("write");
|
die("write");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
readresp(void)
|
readresp(void)
|
||||||
{
|
{
|
||||||
unsigned char buf[256];
|
char buf[Ipcfieldmax+1];
|
||||||
int n;
|
Ipcresp resp;
|
||||||
|
|
||||||
if(read(fd, buf, 2) != 2)
|
return ipcreadresp(fd, 0, buf, sizeof buf, NULL, 0, &resp);
|
||||||
return -1;
|
|
||||||
n = buf[1];
|
|
||||||
if(n > 0 && read(fd, buf + 2, n) != n)
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static double
|
static double
|
||||||
|
|||||||
12
dat.h
12
dat.h
@@ -126,12 +126,20 @@ struct Drawcmd
|
|||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Keyreq Keyreq;
|
typedef struct Keyreq Keyreq;
|
||||||
|
typedef struct Keyres Keyres;
|
||||||
|
struct Keyres
|
||||||
|
{
|
||||||
|
int eaten;
|
||||||
|
Str commit;
|
||||||
|
Str preedit;
|
||||||
|
};
|
||||||
|
|
||||||
struct Keyreq
|
struct Keyreq
|
||||||
{
|
{
|
||||||
int fd;
|
|
||||||
u32int ks;
|
u32int ks;
|
||||||
u32int mod;
|
u32int mod;
|
||||||
int want; /* nonzero: append preedit after commit */
|
int want; /* nonzero: include preedit in reply */
|
||||||
|
Channel *reply;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Dictreq Dictreq;
|
typedef struct Dictreq Dictreq;
|
||||||
|
|||||||
1
fn.h
1
fn.h
@@ -36,6 +36,7 @@ void backko(Im*);
|
|||||||
void backvi(Im*);
|
void backvi(Im*);
|
||||||
void dictsend(Im*, Str*);
|
void dictsend(Im*, Str*);
|
||||||
|
|
||||||
|
int srvreadkey(int, Keyreq*);
|
||||||
void srvthread(void*);
|
void srvthread(void*);
|
||||||
void ibusthread(void*);
|
void ibusthread(void*);
|
||||||
void waylandthread(void*);
|
void waylandthread(void*);
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ CFLAGS = -Wall -O2 -I.. `pkg-config --cflags gtk+-3.0`
|
|||||||
LDFLAGS = `pkg-config --libs gtk+-3.0`
|
LDFLAGS = `pkg-config --libs gtk+-3.0`
|
||||||
DSTDIR ?= $(shell find /usr/lib* -type d -path "*/gtk-3.0/*/immodules" 2>/dev/null | head -1)
|
DSTDIR ?= $(shell find /usr/lib* -type d -path "*/gtk-3.0/*/immodules" 2>/dev/null | head -1)
|
||||||
|
|
||||||
im-strans.so: main.c
|
im-strans.so: main.c ../ipc.c ../ipc.h
|
||||||
$(CC) -shared -fPIC $(CFLAGS) -o $@ $< $(LDFLAGS)
|
$(CC) -shared -fPIC $(CFLAGS) -o $@ main.c ../ipc.c $(LDFLAGS)
|
||||||
|
|
||||||
docker: main.c Dockerfile
|
docker: main.c Dockerfile
|
||||||
docker build -t strans-gtk .
|
docker build -t strans-gtk .
|
||||||
|
|||||||
102
gtk/main.c
102
gtk/main.c
@@ -12,7 +12,7 @@ struct Im
|
|||||||
{
|
{
|
||||||
GtkIMContext parent;
|
GtkIMContext parent;
|
||||||
int fd;
|
int fd;
|
||||||
char pre[256];
|
char pre[Ipcfieldmax+1];
|
||||||
int prelen;
|
int prelen;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -36,52 +36,61 @@ srvconnect(Im *im)
|
|||||||
return;
|
return;
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
addr.sun_family = AF_UNIX;
|
addr.sun_family = AF_UNIX;
|
||||||
snprintf(addr.sun_path, sizeof(addr.sun_path), "/tmp/strans.%d", getuid());
|
snprintf(addr.sun_path, sizeof(addr.sun_path), IPCPATH, getuid());
|
||||||
if(connect(im->fd, (struct sockaddr*)&addr, sizeof(addr)) < 0){
|
if(connect(im->fd, (struct sockaddr*)&addr, sizeof(addr)) < 0){
|
||||||
close(im->fd);
|
close(im->fd);
|
||||||
im->fd = -1;
|
im->fd = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
srvclose(Im *im)
|
||||||
|
{
|
||||||
|
int was;
|
||||||
|
|
||||||
|
if(im->fd >= 0)
|
||||||
|
close(im->fd);
|
||||||
|
im->fd = -1;
|
||||||
|
was = im->prelen;
|
||||||
|
im->pre[0] = '\0';
|
||||||
|
im->prelen = 0;
|
||||||
|
if(was > 0){
|
||||||
|
g_signal_emit_by_name(im, "preedit-changed");
|
||||||
|
g_signal_emit_by_name(im, "preedit-end");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
readresp(Im *im, char *buf, int bufsz)
|
readresp(Im *im, char *buf, int bufsz)
|
||||||
{
|
{
|
||||||
unsigned char hdr[2], pl;
|
Ipcresp resp;
|
||||||
int n, was;
|
int was;
|
||||||
|
|
||||||
if(read(im->fd, hdr, 2) != 2)
|
|
||||||
return -1;
|
|
||||||
n = hdr[1];
|
|
||||||
buf[0] = '\0';
|
|
||||||
if(n > 0 && n < bufsz){
|
|
||||||
if(read(im->fd, buf, n) != n)
|
|
||||||
return -1;
|
|
||||||
buf[n] = '\0';
|
|
||||||
}
|
|
||||||
if(read(im->fd, &pl, 1) != 1)
|
|
||||||
return -1;
|
|
||||||
if(pl >= sizeof(im->pre))
|
|
||||||
return -1;
|
|
||||||
was = im->prelen;
|
was = im->prelen;
|
||||||
if(pl > 0 && read(im->fd, im->pre, pl) != pl)
|
if(ipcreadresp(im->fd, 1, buf, bufsz, im->pre,
|
||||||
|
sizeof(im->pre), &resp) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
im->pre[pl] = '\0';
|
im->prelen = resp.npreedit;
|
||||||
im->prelen = pl;
|
if(was == 0 && im->prelen > 0)
|
||||||
if(was == 0 && pl > 0)
|
|
||||||
g_signal_emit_by_name(im, "preedit-start");
|
g_signal_emit_by_name(im, "preedit-start");
|
||||||
if(was != 0 || pl != 0)
|
if(was != 0 || im->prelen != 0)
|
||||||
g_signal_emit_by_name(im, "preedit-changed");
|
g_signal_emit_by_name(im, "preedit-changed");
|
||||||
if(was > 0 && pl == 0)
|
if(was > 0 && im->prelen == 0)
|
||||||
g_signal_emit_by_name(im, "preedit-end");
|
g_signal_emit_by_name(im, "preedit-end");
|
||||||
return hdr[0];
|
return resp.eaten;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t
|
static uint32_t
|
||||||
kget(uint32_t gdk)
|
kget(uint32_t gdk)
|
||||||
{
|
{
|
||||||
if(gdk >= 0xff00)
|
uint32_t u;
|
||||||
|
|
||||||
|
u = gdk_keyval_to_unicode(gdk);
|
||||||
|
if((gdk & 0xff000000) == 0x01000000 && u != 0)
|
||||||
|
return u;
|
||||||
|
if(gdk >= 0xff00 && gdk <= 0xffff)
|
||||||
return Kspec + (gdk - 0xff00);
|
return Kspec + (gdk - 0xff00);
|
||||||
return gdk_keyval_to_unicode(gdk);
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t
|
static uint32_t
|
||||||
@@ -104,17 +113,17 @@ mget(uint32_t state)
|
|||||||
static void
|
static void
|
||||||
sendreset(Im *im)
|
sendreset(Im *im)
|
||||||
{
|
{
|
||||||
unsigned char buf[4];
|
unsigned char buf[Ipcreqsz];
|
||||||
char resp[64];
|
char resp[Ipcfieldmax+1];
|
||||||
|
|
||||||
if(im->fd < 0)
|
if(im->fd < 0){
|
||||||
|
srvclose(im);
|
||||||
return;
|
return;
|
||||||
buf[0] = 1;
|
}
|
||||||
buf[1] = 0;
|
ipcpackreq(buf, 1, 0, Kesc);
|
||||||
buf[2] = Kesc & 0xff;
|
if(ipcsend(im->fd, buf, sizeof buf) < 0 ||
|
||||||
buf[3] = Kesc >> 8;
|
readresp(im, resp, sizeof(resp)) < 0)
|
||||||
if(send(im->fd, buf, 4, MSG_NOSIGNAL) == 4)
|
srvclose(im);
|
||||||
readresp(im, resp, sizeof(resp));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@@ -137,8 +146,8 @@ static gboolean
|
|||||||
kpress(GtkIMContext *ctx, GdkEventKey *ev)
|
kpress(GtkIMContext *ctx, GdkEventKey *ev)
|
||||||
{
|
{
|
||||||
Im *im;
|
Im *im;
|
||||||
unsigned char buf[4];
|
unsigned char buf[Ipcreqsz];
|
||||||
char resp[64];
|
char resp[Ipcfieldmax+1];
|
||||||
uint32_t key, mod;
|
uint32_t key, mod;
|
||||||
int r;
|
int r;
|
||||||
GtkInputPurpose purpose;
|
GtkInputPurpose purpose;
|
||||||
@@ -154,21 +163,18 @@ kpress(GtkIMContext *ctx, GdkEventKey *ev)
|
|||||||
if(purpose == GTK_INPUT_PURPOSE_PASSWORD || purpose == GTK_INPUT_PURPOSE_PIN)
|
if(purpose == GTK_INPUT_PURPOSE_PASSWORD || purpose == GTK_INPUT_PURPOSE_PIN)
|
||||||
return plaincommit(ctx, key, mod);
|
return plaincommit(ctx, key, mod);
|
||||||
srvconnect(im);
|
srvconnect(im);
|
||||||
if(im->fd < 0)
|
if(im->fd < 0){
|
||||||
|
srvclose(im);
|
||||||
return plaincommit(ctx, key, mod);
|
return plaincommit(ctx, key, mod);
|
||||||
buf[0] = 1;
|
}
|
||||||
buf[1] = mod;
|
ipcpackreq(buf, 1, mod, key);
|
||||||
buf[2] = key & 0xff;
|
if(ipcsend(im->fd, buf, sizeof buf) < 0){
|
||||||
buf[3] = key >> 8;
|
srvclose(im);
|
||||||
if(send(im->fd, buf, 4, MSG_NOSIGNAL) != 4){
|
|
||||||
close(im->fd);
|
|
||||||
im->fd = -1;
|
|
||||||
return plaincommit(ctx, key, mod);
|
return plaincommit(ctx, key, mod);
|
||||||
}
|
}
|
||||||
r = readresp(im, resp, sizeof(resp));
|
r = readresp(im, resp, sizeof(resp));
|
||||||
if(r < 0){
|
if(r < 0){
|
||||||
close(im->fd);
|
srvclose(im);
|
||||||
im->fd = -1;
|
|
||||||
return plaincommit(ctx, key, mod);
|
return plaincommit(ctx, key, mod);
|
||||||
}
|
}
|
||||||
if(resp[0] != '\0')
|
if(resp[0] != '\0')
|
||||||
@@ -228,6 +234,8 @@ static void
|
|||||||
init(Im *im)
|
init(Im *im)
|
||||||
{
|
{
|
||||||
im->fd = -1;
|
im->fd = -1;
|
||||||
|
im->pre[0] = '\0';
|
||||||
|
im->prelen = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
62
ibus.c
62
ibus.c
@@ -8,6 +8,7 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <dbus/dbus.h>
|
#include <dbus/dbus.h>
|
||||||
|
#include <xkbcommon/xkbcommon.h>
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@@ -30,6 +31,7 @@ static DBusServer *srv;
|
|||||||
static char addrfile[256];
|
static char addrfile[256];
|
||||||
static int icctr;
|
static int icctr;
|
||||||
static int busctr;
|
static int busctr;
|
||||||
|
static Channel *replyc;
|
||||||
|
|
||||||
static DBusHandlerResult onmsg(DBusConnection*, DBusMessage*, void*);
|
static DBusHandlerResult onmsg(DBusConnection*, DBusMessage*, void*);
|
||||||
|
|
||||||
@@ -182,9 +184,14 @@ togglewatch(DBusWatch *w, void *_)
|
|||||||
static u32int
|
static u32int
|
||||||
kget(u32int sym)
|
kget(u32int sym)
|
||||||
{
|
{
|
||||||
|
u32int c;
|
||||||
|
|
||||||
|
c = xkb_keysym_to_utf32(sym);
|
||||||
|
if(c >= ' ' && c != 0x7f)
|
||||||
|
return c;
|
||||||
if(sym >= 0xff00 && sym <= 0xffff)
|
if(sym >= 0xff00 && sym <= 0xffff)
|
||||||
return Kspec + (sym - 0xff00);
|
return Kspec + (sym - 0xff00);
|
||||||
return sym;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32int
|
static u32int
|
||||||
@@ -201,53 +208,24 @@ mget(u32int state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sendkey(u32int ks, u32int mod, char *com, int csz, char *pre, int psz,
|
sendkey(u32int ks, u32int mod, Keyres *res)
|
||||||
int *eaten)
|
|
||||||
{
|
{
|
||||||
Keyreq kr;
|
Keyreq kr;
|
||||||
int p[2];
|
|
||||||
uchar hdr[2];
|
|
||||||
uchar pl;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
*eaten = 0;
|
|
||||||
com[0] = '\0';
|
|
||||||
pre[0] = '\0';
|
|
||||||
if(pipe(p) < 0)
|
|
||||||
return;
|
|
||||||
kr.fd = p[1];
|
|
||||||
kr.ks = ks;
|
kr.ks = ks;
|
||||||
kr.mod = mod;
|
kr.mod = mod;
|
||||||
kr.want = 1;
|
kr.want = 1;
|
||||||
|
kr.reply = replyc;
|
||||||
chansend(keyc, &kr);
|
chansend(keyc, &kr);
|
||||||
if(read(p[0], hdr, 2) != 2)
|
chanrecv(replyc, res);
|
||||||
goto out;
|
|
||||||
*eaten = hdr[0];
|
|
||||||
n = hdr[1];
|
|
||||||
if(n > 0 && n < csz){
|
|
||||||
if(read(p[0], com, n) != n)
|
|
||||||
goto out;
|
|
||||||
com[n] = '\0';
|
|
||||||
}
|
|
||||||
if(read(p[0], &pl, 1) != 1)
|
|
||||||
goto out;
|
|
||||||
if(pl > 0 && pl < psz){
|
|
||||||
if(read(p[0], pre, pl) != pl)
|
|
||||||
goto out;
|
|
||||||
pre[pl] = '\0';
|
|
||||||
}
|
|
||||||
out:
|
|
||||||
close(p[0]);
|
|
||||||
close(p[1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sendreset(void)
|
sendreset(void)
|
||||||
{
|
{
|
||||||
char com[64], pre[256];
|
Keyres res;
|
||||||
int eaten;
|
|
||||||
|
|
||||||
sendkey(Kesc, 0, com, sizeof(com), pre, sizeof(pre), &eaten);
|
sendkey(Kesc, 0, &res);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -305,7 +283,7 @@ emitpreedit(DBusConnection *c, const char *path, const char *text)
|
|||||||
return;
|
return;
|
||||||
dbus_message_iter_init_append(sig, &it);
|
dbus_message_iter_init_append(sig, &it);
|
||||||
appendibustext(&it, text);
|
appendibustext(&it, text);
|
||||||
cursor = utflen(text);
|
cursor = utflen((char*)text);
|
||||||
visible = text[0] != '\0' ? TRUE : FALSE;
|
visible = text[0] != '\0' ? TRUE : FALSE;
|
||||||
dbus_message_iter_append_basic(&it, DBUS_TYPE_UINT32, &cursor);
|
dbus_message_iter_append_basic(&it, DBUS_TYPE_UINT32, &cursor);
|
||||||
dbus_message_iter_append_basic(&it, DBUS_TYPE_BOOLEAN, &visible);
|
dbus_message_iter_append_basic(&it, DBUS_TYPE_BOOLEAN, &visible);
|
||||||
@@ -353,8 +331,8 @@ handlekey(DBusConnection *c, DBusMessage *m)
|
|||||||
DBusMessage *r;
|
DBusMessage *r;
|
||||||
DBusError err;
|
DBusError err;
|
||||||
dbus_uint32_t sym, code, state;
|
dbus_uint32_t sym, code, state;
|
||||||
char commit[256], preedit[256];
|
Keyres res;
|
||||||
int eaten;
|
char commit[Maxutf], preedit[Maxutf];
|
||||||
dbus_bool_t b;
|
dbus_bool_t b;
|
||||||
u32int ks, mod;
|
u32int ks, mod;
|
||||||
|
|
||||||
@@ -378,13 +356,14 @@ handlekey(DBusConnection *c, DBusMessage *m)
|
|||||||
}
|
}
|
||||||
ks = kget(sym);
|
ks = kget(sym);
|
||||||
mod = mget(state);
|
mod = mget(state);
|
||||||
sendkey(ks, mod, commit, sizeof(commit), preedit, sizeof(preedit),
|
sendkey(ks, mod, &res);
|
||||||
&eaten);
|
stoutf(&res.commit, commit, sizeof commit);
|
||||||
|
stoutf(&res.preedit, preedit, sizeof preedit);
|
||||||
if(commit[0] != '\0')
|
if(commit[0] != '\0')
|
||||||
emitcommit(c, dbus_message_get_path(m), commit);
|
emitcommit(c, dbus_message_get_path(m), commit);
|
||||||
emitpreedit(c, dbus_message_get_path(m), preedit);
|
emitpreedit(c, dbus_message_get_path(m), preedit);
|
||||||
r = dbus_message_new_method_return(m);
|
r = dbus_message_new_method_return(m);
|
||||||
b = eaten ? TRUE : FALSE;
|
b = res.eaten ? TRUE : FALSE;
|
||||||
dbus_message_append_args(r, DBUS_TYPE_BOOLEAN, &b, DBUS_TYPE_INVALID);
|
dbus_message_append_args(r, DBUS_TYPE_BOOLEAN, &b, DBUS_TYPE_INVALID);
|
||||||
dbus_connection_send(c, r, nil);
|
dbus_connection_send(c, r, nil);
|
||||||
dbus_message_unref(r);
|
dbus_message_unref(r);
|
||||||
@@ -581,6 +560,7 @@ ibusthread(void *_)
|
|||||||
threadsetname("ibus");
|
threadsetname("ibus");
|
||||||
if(ibusinit() < 0)
|
if(ibusinit() < 0)
|
||||||
return;
|
return;
|
||||||
|
replyc = chancreate(sizeof(Keyres), 0);
|
||||||
for(;;){
|
for(;;){
|
||||||
n = 0;
|
n = 0;
|
||||||
for(i = 0; i < nwatches && n < Maxwatches; i++){
|
for(i = 0; i < nwatches && n < Maxwatches; i++){
|
||||||
|
|||||||
186
ipc.c
Normal file
186
ipc.c
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include "ipc.h"
|
||||||
|
|
||||||
|
#if !defined(MSG_NOSIGNAL) && !defined(SO_NOSIGPIPE)
|
||||||
|
#error "ipcsend requires MSG_NOSIGNAL or SO_NOSIGPIPE"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
putlen(unsigned char p[Ipclensz], size_t n)
|
||||||
|
{
|
||||||
|
p[0] = n;
|
||||||
|
p[1] = n >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
getlen(const unsigned char p[Ipclensz])
|
||||||
|
{
|
||||||
|
return p[0] | (p[1] << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ipcpackreq(unsigned char req[Ipcreqsz], int want, unsigned int mod,
|
||||||
|
unsigned int key)
|
||||||
|
{
|
||||||
|
req[0] = want != 0;
|
||||||
|
req[1] = mod;
|
||||||
|
req[2] = key;
|
||||||
|
req[3] = key >> 8;
|
||||||
|
req[4] = key >> 16;
|
||||||
|
req[5] = key >> 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ipcunpackreq(const unsigned char req[Ipcreqsz], int *want, unsigned int *mod,
|
||||||
|
unsigned int *key)
|
||||||
|
{
|
||||||
|
*want = req[0] != 0;
|
||||||
|
*mod = req[1];
|
||||||
|
*key = (unsigned int)req[2] |
|
||||||
|
((unsigned int)req[3] << 8) |
|
||||||
|
((unsigned int)req[4] << 16) |
|
||||||
|
((unsigned int)req[5] << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ipcpackresp(unsigned char *dst, size_t cap, int eaten,
|
||||||
|
const char *commit, size_t ncommit, const char *preedit, size_t npreedit,
|
||||||
|
int want)
|
||||||
|
{
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
if(ncommit > Ipcfieldmax || npreedit > Ipcfieldmax)
|
||||||
|
return -1;
|
||||||
|
if((ncommit > 0 && commit == NULL) ||
|
||||||
|
(want && npreedit > 0 && preedit == NULL))
|
||||||
|
return -1;
|
||||||
|
n = Ipcresphdrsz + ncommit + (want ? Ipclensz + npreedit : 0);
|
||||||
|
if(dst == NULL || cap < n)
|
||||||
|
return -1;
|
||||||
|
dst[0] = eaten != 0;
|
||||||
|
putlen(dst + 1, ncommit);
|
||||||
|
if(ncommit > 0)
|
||||||
|
memcpy(dst + Ipcresphdrsz, commit, ncommit);
|
||||||
|
if(want){
|
||||||
|
putlen(dst + Ipcresphdrsz + ncommit, npreedit);
|
||||||
|
if(npreedit > 0)
|
||||||
|
memcpy(dst + Ipcresphdrsz + ncommit + Ipclensz,
|
||||||
|
preedit, npreedit);
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ipcreadn(int fd, void *buf, size_t n)
|
||||||
|
{
|
||||||
|
unsigned char *p;
|
||||||
|
ssize_t r;
|
||||||
|
|
||||||
|
p = buf;
|
||||||
|
while(n > 0){
|
||||||
|
r = read(fd, p, n);
|
||||||
|
if(r < 0 && errno == EINTR)
|
||||||
|
continue;
|
||||||
|
if(r <= 0)
|
||||||
|
return -1;
|
||||||
|
p += r;
|
||||||
|
n -= r;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ipcsend(int fd, const void *buf, size_t n)
|
||||||
|
{
|
||||||
|
const unsigned char *p;
|
||||||
|
ssize_t r;
|
||||||
|
int flags;
|
||||||
|
#if !defined(MSG_NOSIGNAL) && defined(SO_NOSIGPIPE)
|
||||||
|
int one, sr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
p = buf;
|
||||||
|
#ifdef MSG_NOSIGNAL
|
||||||
|
flags = MSG_NOSIGNAL;
|
||||||
|
#else
|
||||||
|
flags = 0;
|
||||||
|
#ifdef SO_NOSIGPIPE
|
||||||
|
one = 1;
|
||||||
|
do
|
||||||
|
sr = setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof one);
|
||||||
|
while(sr < 0 && errno == EINTR);
|
||||||
|
if(sr < 0)
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
while(n > 0){
|
||||||
|
r = send(fd, p, n, flags);
|
||||||
|
if(r < 0 && errno == EINTR)
|
||||||
|
continue;
|
||||||
|
if(r <= 0)
|
||||||
|
return -1;
|
||||||
|
p += r;
|
||||||
|
n -= r;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
readfield(int fd, size_t n, char *dst, size_t cap)
|
||||||
|
{
|
||||||
|
unsigned char discard[128];
|
||||||
|
size_t keep, part;
|
||||||
|
|
||||||
|
if(cap > 0 && dst == NULL)
|
||||||
|
return -1;
|
||||||
|
keep = 0;
|
||||||
|
if(cap > 0)
|
||||||
|
keep = n >= cap ? cap - 1 : n;
|
||||||
|
if(keep > 0 && ipcreadn(fd, dst, keep) < 0)
|
||||||
|
return -1;
|
||||||
|
if(cap > 0)
|
||||||
|
dst[keep] = '\0';
|
||||||
|
n -= keep;
|
||||||
|
while(n > 0){
|
||||||
|
part = n < sizeof discard ? n : sizeof discard;
|
||||||
|
if(ipcreadn(fd, discard, part) < 0)
|
||||||
|
return -1;
|
||||||
|
n -= part;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ipcreadresp(int fd, int want, char *commit, size_t ccap,
|
||||||
|
char *preedit, size_t pcap, Ipcresp *resp)
|
||||||
|
{
|
||||||
|
unsigned char hdr[Ipcresphdrsz], npreedit[Ipclensz];
|
||||||
|
|
||||||
|
if(resp == NULL || (ccap > 0 && commit == NULL) ||
|
||||||
|
(pcap > 0 && preedit == NULL))
|
||||||
|
return -1;
|
||||||
|
if(ccap > 0)
|
||||||
|
commit[0] = '\0';
|
||||||
|
if(pcap > 0)
|
||||||
|
preedit[0] = '\0';
|
||||||
|
memset(resp, 0, sizeof *resp);
|
||||||
|
if(ipcreadn(fd, hdr, sizeof hdr) < 0)
|
||||||
|
return -1;
|
||||||
|
resp->eaten = hdr[0] != 0;
|
||||||
|
resp->ncommit = getlen(hdr + 1);
|
||||||
|
if(resp->ncommit > Ipcfieldmax)
|
||||||
|
return -1;
|
||||||
|
if(readfield(fd, resp->ncommit, commit, ccap) < 0)
|
||||||
|
return -1;
|
||||||
|
if(!want)
|
||||||
|
return 0;
|
||||||
|
if(ipcreadn(fd, npreedit, sizeof npreedit) < 0)
|
||||||
|
return -1;
|
||||||
|
resp->npreedit = getlen(npreedit);
|
||||||
|
if(resp->npreedit > Ipcfieldmax)
|
||||||
|
return -1;
|
||||||
|
return readfield(fd, resp->npreedit, preedit, pcap);
|
||||||
|
}
|
||||||
41
ipc.h
41
ipc.h
@@ -1,9 +1,21 @@
|
|||||||
// req: 4 bytes [type, mod, key lo, key hi]
|
#ifndef STRANS_IPC_H
|
||||||
// resp: 2+n bytes [type, n, ...]
|
#define STRANS_IPC_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#define IPCPATH "/tmp/strans.2.%d"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Request: [want-preedit, modifiers, key byte 0, ..., key byte 3].
|
||||||
|
* Response: [eaten, commit-length-low, commit-length-high, commit...],
|
||||||
|
* followed, when requested, by
|
||||||
|
* [preedit-length-low, preedit-length-high, preedit...].
|
||||||
|
* Lengths are little-endian byte counts; fields are at most Ipcfieldmax bytes.
|
||||||
|
*/
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
Kspec = 0xf000,
|
Kspec = 0x110000,
|
||||||
Kback = Kspec|0x08,
|
Kback = Kspec|0x08,
|
||||||
Ktab = Kspec|0x09,
|
Ktab = Kspec|0x09,
|
||||||
Kret = Kspec|0x0d,
|
Kret = Kspec|0x0d,
|
||||||
@@ -17,4 +29,27 @@ enum
|
|||||||
Mctrl = 1<<2,
|
Mctrl = 1<<2,
|
||||||
Malt = 1<<3,
|
Malt = 1<<3,
|
||||||
Msuper = 1<<6,
|
Msuper = 1<<6,
|
||||||
|
|
||||||
|
Ipcreqsz = 6,
|
||||||
|
Ipclensz = 2,
|
||||||
|
Ipcresphdrsz = 1 + Ipclensz,
|
||||||
|
Ipcfieldmax = 256,
|
||||||
|
Ipcmaxresp = Ipcresphdrsz + Ipcfieldmax + Ipclensz + Ipcfieldmax,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct Ipcresp Ipcresp;
|
||||||
|
struct Ipcresp
|
||||||
|
{
|
||||||
|
int eaten;
|
||||||
|
size_t ncommit;
|
||||||
|
size_t npreedit;
|
||||||
|
};
|
||||||
|
|
||||||
|
void ipcpackreq(unsigned char[Ipcreqsz], int, unsigned int, unsigned int);
|
||||||
|
void ipcunpackreq(const unsigned char[Ipcreqsz], int*, unsigned int*, unsigned int*);
|
||||||
|
int ipcpackresp(unsigned char*, size_t, int, const char*, size_t, const char*, size_t, int);
|
||||||
|
int ipcreadn(int, void*, size_t);
|
||||||
|
int ipcsend(int, const void*, size_t);
|
||||||
|
int ipcreadresp(int, int, char*, size_t, char*, size_t, Ipcresp*);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
59
srv.c
59
srv.c
@@ -2,30 +2,53 @@
|
|||||||
#include "fn.h"
|
#include "fn.h"
|
||||||
|
|
||||||
static char adir[40];
|
static char adir[40];
|
||||||
|
static Channel *clientc;
|
||||||
|
|
||||||
static void
|
int
|
||||||
sendkey(int fd, u32int ks, u32int mod, int want)
|
srvreadkey(int fd, Keyreq *kr)
|
||||||
{
|
{
|
||||||
Keyreq kr;
|
uchar req[Ipcreqsz];
|
||||||
|
u32int ks, mod;
|
||||||
|
int want;
|
||||||
|
|
||||||
kr.fd = fd;
|
if(ipcreadn(fd, req, sizeof req) < 0)
|
||||||
kr.ks = ks;
|
return -1;
|
||||||
kr.mod = mod;
|
ipcunpackreq(req, &want, &mod, &ks);
|
||||||
kr.want = want;
|
kr->ks = ks;
|
||||||
chansend(keyc, &kr);
|
kr->mod = mod;
|
||||||
|
kr->want = want;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clientthread(void *arg)
|
clientthread(void *arg)
|
||||||
{
|
{
|
||||||
|
Channel *reply;
|
||||||
int fd;
|
int fd;
|
||||||
uchar req[4];
|
Keyreq kr;
|
||||||
|
Keyres res;
|
||||||
|
uchar out[Ipcmaxresp];
|
||||||
|
char commit[Maxutf], preedit[Maxutf];
|
||||||
|
int n, ncommit, npreedit;
|
||||||
|
uchar token;
|
||||||
|
|
||||||
fd = (int)(uintptr)arg;
|
fd = (int)(uintptr)arg;
|
||||||
threadsetname("client %d", fd);
|
threadsetname("client %d", fd);
|
||||||
while(read(fd, req, 4) == 4)
|
reply = chancreate(sizeof(Keyres), 0);
|
||||||
sendkey(fd, req[2] | (req[3] << 8), req[1], req[0]);
|
kr.reply = reply;
|
||||||
|
while(srvreadkey(fd, &kr) == 0){
|
||||||
|
chansend(keyc, &kr);
|
||||||
|
chanrecv(reply, &res);
|
||||||
|
ncommit = stoutf(&res.commit, commit, sizeof commit);
|
||||||
|
npreedit = stoutf(&res.preedit, preedit, sizeof preedit);
|
||||||
|
n = ipcpackresp(out, sizeof out, res.eaten,
|
||||||
|
commit, ncommit, preedit, npreedit, kr.want);
|
||||||
|
if(n < 0 || ipcsend(fd, out, n) < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
chanfree(reply);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
chanrecv(clientc, &token);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -33,7 +56,7 @@ srvinit(void)
|
|||||||
{
|
{
|
||||||
char addr[64];
|
char addr[64];
|
||||||
|
|
||||||
snprint(addr, sizeof(addr), "unix!/tmp/strans.%d", getuid());
|
snprint(addr, sizeof(addr), "unix!" IPCPATH, getuid());
|
||||||
remove(addr + 5);
|
remove(addr + 5);
|
||||||
if(announce(addr, adir) < 0)
|
if(announce(addr, adir) < 0)
|
||||||
die("announce: %r");
|
die("announce: %r");
|
||||||
@@ -44,13 +67,23 @@ srvthread(void*)
|
|||||||
{
|
{
|
||||||
char ldir[40];
|
char ldir[40];
|
||||||
int fd;
|
int fd;
|
||||||
|
uchar token;
|
||||||
|
|
||||||
threadsetname("srv");
|
threadsetname("srv");
|
||||||
srvinit();
|
srvinit();
|
||||||
|
token = 0;
|
||||||
|
clientc = chancreate(sizeof token, Maxclients);
|
||||||
for(;;){
|
for(;;){
|
||||||
fd = listen(adir, ldir);
|
fd = listen(adir, ldir);
|
||||||
if(fd < 0)
|
if(fd < 0)
|
||||||
continue;
|
continue;
|
||||||
proccreate(clientthread, (void*)(uintptr)fd, 8192);
|
if(channbsend(clientc, &token) <= 0){
|
||||||
|
close(fd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(proccreate(clientthread, (void*)(uintptr)fd, 8192) < 0){
|
||||||
|
chanrecv(clientc, &token);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
36
strans.c
36
strans.c
@@ -308,14 +308,24 @@ init(void)
|
|||||||
im.l = getlang(LangEN);
|
im.l = getlang(LangEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
imhandlekey(Keyreq *kr)
|
||||||
|
{
|
||||||
|
Keyres res;
|
||||||
|
|
||||||
|
sclear(&res.commit);
|
||||||
|
sclear(&res.preedit);
|
||||||
|
res.eaten = keystroke(kr->ks, kr->mod, &res.commit);
|
||||||
|
if(kr->want)
|
||||||
|
res.preedit = im.pre;
|
||||||
|
chansend(kr->reply, &res);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
imthread(void*)
|
imthread(void*)
|
||||||
{
|
{
|
||||||
Keyreq kr;
|
Keyreq kr;
|
||||||
Dictres res;
|
Dictres res;
|
||||||
Str com;
|
|
||||||
uchar out[256];
|
|
||||||
int n, len, r;
|
|
||||||
Alt alts[] = {
|
Alt alts[] = {
|
||||||
{keyc, &kr, CHANRCV, nil},
|
{keyc, &kr, CHANRCV, nil},
|
||||||
{dictresc, &res, CHANRCV, nil},
|
{dictresc, &res, CHANRCV, nil},
|
||||||
@@ -327,24 +337,7 @@ imthread(void*)
|
|||||||
for(;;){
|
for(;;){
|
||||||
switch(alt(alts)){
|
switch(alt(alts)){
|
||||||
case 0:
|
case 0:
|
||||||
sclear(&com);
|
imhandlekey(&kr);
|
||||||
r = keystroke(kr.ks, kr.mod, &com);
|
|
||||||
out[0] = r;
|
|
||||||
out[1] = 0;
|
|
||||||
n = 2;
|
|
||||||
if(com.n > 0){
|
|
||||||
len = stoutf(&com, (char*)(out+2), sizeof(out)-2);
|
|
||||||
out[1] = len;
|
|
||||||
n += len;
|
|
||||||
}
|
|
||||||
if(kr.want){
|
|
||||||
len = im.pre.n > 0 ?
|
|
||||||
stoutf(&im.pre, (char*)(out+n+1),
|
|
||||||
sizeof(out)-n-1) : 0;
|
|
||||||
out[n] = len;
|
|
||||||
n += 1 + len;
|
|
||||||
}
|
|
||||||
write(kr.fd, out, n);
|
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if(scmp(&res.key, &im.pre) == 0){
|
if(scmp(&res.key, &im.pre) == 0){
|
||||||
@@ -385,4 +378,3 @@ mapinit(char *dir)
|
|||||||
langs[i].map = trieopen(path);
|
langs[i].map = trieopen(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
97
wayland.c
97
wayland.c
@@ -25,55 +25,40 @@ static struct xkb_state *xkbst;
|
|||||||
static int active;
|
static int active;
|
||||||
static int pending;
|
static int pending;
|
||||||
static u32int imserial;
|
static u32int imserial;
|
||||||
|
static Channel *replyc;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sendkey(u32int ks, u32int mod, char *com, int csz, char *pre, int psz,
|
sendkey(u32int ks, u32int mod, Keyres *res)
|
||||||
int *eaten)
|
|
||||||
{
|
{
|
||||||
Keyreq kr;
|
Keyreq kr;
|
||||||
int p[2];
|
|
||||||
uchar hdr[2];
|
|
||||||
uchar pl;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
*eaten = 0;
|
|
||||||
com[0] = '\0';
|
|
||||||
pre[0] = '\0';
|
|
||||||
if(pipe(p) < 0)
|
|
||||||
return;
|
|
||||||
kr.fd = p[1];
|
|
||||||
kr.ks = ks;
|
kr.ks = ks;
|
||||||
kr.mod = mod;
|
kr.mod = mod;
|
||||||
kr.want = 1;
|
kr.want = 1;
|
||||||
|
kr.reply = replyc;
|
||||||
chansend(keyc, &kr);
|
chansend(keyc, &kr);
|
||||||
if(read(p[0], hdr, 2) != 2)
|
chanrecv(replyc, res);
|
||||||
goto out;
|
|
||||||
*eaten = hdr[0];
|
|
||||||
n = hdr[1];
|
|
||||||
if(n > 0 && n < csz){
|
|
||||||
if(read(p[0], com, n) != n)
|
|
||||||
goto out;
|
|
||||||
com[n] = '\0';
|
|
||||||
}
|
|
||||||
if(read(p[0], &pl, 1) != 1)
|
|
||||||
goto out;
|
|
||||||
if(pl > 0 && pl < psz){
|
|
||||||
if(read(p[0], pre, pl) != pl)
|
|
||||||
goto out;
|
|
||||||
pre[pl] = '\0';
|
|
||||||
}
|
|
||||||
out:
|
|
||||||
close(p[0]);
|
|
||||||
close(p[1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sendreset(void)
|
sendreset(void)
|
||||||
{
|
{
|
||||||
char com[64], pre[256];
|
Keyres res;
|
||||||
int eaten;
|
|
||||||
|
|
||||||
sendkey(Kesc, 0, com, sizeof(com), pre, sizeof(pre), &eaten);
|
sendkey(Kesc, 0, &res);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32int
|
||||||
|
kget(xkb_keysym_t ks)
|
||||||
|
{
|
||||||
|
u32int c;
|
||||||
|
|
||||||
|
c = xkb_keysym_to_utf32(ks);
|
||||||
|
if(c >= ' ' && c != 0x7f)
|
||||||
|
return c;
|
||||||
|
if(ks >= 0xff00 && ks <= 0xffff)
|
||||||
|
return Kspec + (ks - 0xff00);
|
||||||
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32int
|
static u32int
|
||||||
@@ -104,29 +89,32 @@ kpress(uint32_t time, uint32_t keycode, uint32_t state)
|
|||||||
{
|
{
|
||||||
xkb_keysym_t ks;
|
xkb_keysym_t ks;
|
||||||
u32int k, mod;
|
u32int k, mod;
|
||||||
char com[64], pre[256];
|
Keyres res;
|
||||||
int eaten, plen;
|
char commit[Maxutf], preedit[Maxutf];
|
||||||
|
int plen;
|
||||||
|
|
||||||
if(state != WL_KEYBOARD_KEY_STATE_PRESSED || xkbst == nil){
|
if(state != WL_KEYBOARD_KEY_STATE_PRESSED || xkbst == nil){
|
||||||
zwp_virtual_keyboard_v1_key(vk, time, keycode, state);
|
zwp_virtual_keyboard_v1_key(vk, time, keycode, state);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ks = xkb_state_key_get_one_sym(xkbst, keycode + 8);
|
ks = xkb_state_key_get_one_sym(xkbst, keycode + 8);
|
||||||
k = ks >= 0xff00 ? Kspec + (ks - 0xff00) : xkb_keysym_to_utf32(ks);
|
k = kget(ks);
|
||||||
if(k == 0){
|
if(k == 0){
|
||||||
zwp_virtual_keyboard_v1_key(vk, time, keycode, state);
|
zwp_virtual_keyboard_v1_key(vk, time, keycode, state);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mod = mget();
|
mod = mget();
|
||||||
sendkey(k, mod, com, sizeof(com), pre, sizeof(pre), &eaten);
|
sendkey(k, mod, &res);
|
||||||
if(com[0] != '\0'){
|
stoutf(&res.commit, commit, sizeof commit);
|
||||||
zwp_input_method_v2_commit_string(im, com);
|
stoutf(&res.preedit, preedit, sizeof preedit);
|
||||||
|
if(commit[0] != '\0'){
|
||||||
|
zwp_input_method_v2_commit_string(im, commit);
|
||||||
zwp_input_method_v2_commit(im, imserial);
|
zwp_input_method_v2_commit(im, imserial);
|
||||||
}
|
}
|
||||||
plen = strlen(pre);
|
plen = strlen(preedit);
|
||||||
zwp_input_method_v2_set_preedit_string(im, pre, plen, plen);
|
zwp_input_method_v2_set_preedit_string(im, preedit, plen, plen);
|
||||||
zwp_input_method_v2_commit(im, imserial);
|
zwp_input_method_v2_commit(im, imserial);
|
||||||
if(!eaten)
|
if(!res.eaten)
|
||||||
zwp_virtual_keyboard_v1_key(vk, time, keycode, state);
|
zwp_virtual_keyboard_v1_key(vk, time, keycode, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,6 +146,7 @@ kg_keymap(void *data, struct zwp_input_method_keyboard_grab_v2 *g,
|
|||||||
munmap(s, size);
|
munmap(s, size);
|
||||||
}
|
}
|
||||||
zwp_virtual_keyboard_v1_keymap(vk, format, fd, size);
|
zwp_virtual_keyboard_v1_keymap(vk, format, fd, size);
|
||||||
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -215,14 +204,6 @@ im_deactivate(void *data, struct zwp_input_method_v2 *m)
|
|||||||
(void)data;
|
(void)data;
|
||||||
(void)m;
|
(void)m;
|
||||||
pending = 0;
|
pending = 0;
|
||||||
if(active){
|
|
||||||
active = 0;
|
|
||||||
sendreset();
|
|
||||||
if(grab != nil){
|
|
||||||
zwp_input_method_keyboard_grab_v2_release(grab);
|
|
||||||
grab = nil;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -266,6 +247,13 @@ im_done(void *data, struct zwp_input_method_v2 *m)
|
|||||||
if(grab != nil)
|
if(grab != nil)
|
||||||
zwp_input_method_keyboard_grab_v2_add_listener(grab,
|
zwp_input_method_keyboard_grab_v2_add_listener(grab,
|
||||||
&grab_listener, nil);
|
&grab_listener, nil);
|
||||||
|
}else if(!pending && active){
|
||||||
|
active = 0;
|
||||||
|
sendreset();
|
||||||
|
if(grab != nil){
|
||||||
|
zwp_input_method_keyboard_grab_v2_release(grab);
|
||||||
|
grab = nil;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,9 +280,9 @@ reg_global(void *data, struct wl_registry *r, uint32_t name,
|
|||||||
const char *iface, uint32_t version)
|
const char *iface, uint32_t version)
|
||||||
{
|
{
|
||||||
(void)data;
|
(void)data;
|
||||||
(void)version;
|
|
||||||
if(strcmp(iface, wl_seat_interface.name) == 0)
|
if(strcmp(iface, wl_seat_interface.name) == 0)
|
||||||
seat = wl_registry_bind(r, name, &wl_seat_interface, 5);
|
seat = wl_registry_bind(r, name, &wl_seat_interface,
|
||||||
|
version < 5 ? version : 5);
|
||||||
else if(strcmp(iface, zwp_input_method_manager_v2_interface.name) == 0)
|
else if(strcmp(iface, zwp_input_method_manager_v2_interface.name) == 0)
|
||||||
immgr = wl_registry_bind(r, name,
|
immgr = wl_registry_bind(r, name,
|
||||||
&zwp_input_method_manager_v2_interface, 1);
|
&zwp_input_method_manager_v2_interface, 1);
|
||||||
@@ -345,6 +333,9 @@ waylandthread(void *_)
|
|||||||
im = zwp_input_method_manager_v2_get_input_method(immgr, seat);
|
im = zwp_input_method_manager_v2_get_input_method(immgr, seat);
|
||||||
zwp_input_method_v2_add_listener(im, &im_listener, nil);
|
zwp_input_method_v2_add_listener(im, &im_listener, nil);
|
||||||
vk = zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(vkmgr, seat);
|
vk = zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(vkmgr, seat);
|
||||||
|
replyc = chancreate(sizeof(Keyres), 0);
|
||||||
while(wl_display_dispatch(dpy) != -1)
|
while(wl_display_dispatch(dpy) != -1)
|
||||||
;
|
;
|
||||||
|
chanfree(replyc);
|
||||||
|
replyc = nil;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
CC = cc
|
CC = cc
|
||||||
CFLAGS = -Wall -Wextra -O2 -I.. -Ixcb-imdkit/src
|
XKB_CFLAGS := $(shell pkg-config --cflags xkbcommon)
|
||||||
|
XKB_LIBS := $(shell pkg-config --libs xkbcommon)
|
||||||
|
CFLAGS = -Wall -Wextra -O2 -I.. -Ixcb-imdkit/src $(XKB_CFLAGS)
|
||||||
PROG = strans-xim
|
PROG = strans-xim
|
||||||
|
|
||||||
SRCS = $(wildcard *.c)
|
SRCS = $(wildcard *.c)
|
||||||
@@ -9,8 +11,8 @@ LIBS = xcb-imdkit/libxcb-imdkit.a xcb-util/libxcb-util.a
|
|||||||
|
|
||||||
all: $(PROG)
|
all: $(PROG)
|
||||||
|
|
||||||
$(PROG): $(OBJS) $(LIBS)
|
$(PROG): $(OBJS) $(LIBS) ../ipc.c ../ipc.h
|
||||||
$(CC) -o $@ $(OBJS) $(LIBS) -lxcb
|
$(CC) $(CFLAGS) -o $@ $(OBJS) ../ipc.c $(LIBS) -lxcb $(XKB_LIBS)
|
||||||
|
|
||||||
$(OBJS): ../ipc.h
|
$(OBJS): ../ipc.h
|
||||||
|
|
||||||
|
|||||||
94
xim/main.c
94
xim/main.c
@@ -5,13 +5,14 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
|
#include <xkbcommon/xkbcommon.h>
|
||||||
#include "imdkit.h"
|
#include "imdkit.h"
|
||||||
#include "encoding.h"
|
#include "encoding.h"
|
||||||
#include "ipc.h"
|
#include "ipc.h"
|
||||||
|
|
||||||
static xcb_connection_t *conn;
|
static xcb_connection_t *conn;
|
||||||
static xcb_im_t *xim;
|
static xcb_im_t *xim;
|
||||||
static int srvfd;
|
static int srvfd = -1;
|
||||||
static xcb_keysym_t *kmap;
|
static xcb_keysym_t *kmap;
|
||||||
static uint8_t minkc, maxkc;
|
static uint8_t minkc, maxkc;
|
||||||
static uint8_t symsper;
|
static uint8_t symsper;
|
||||||
@@ -105,50 +106,74 @@ commit(xcb_im_input_context_t *ic, char *s, int len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
srvclose(void)
|
||||||
|
{
|
||||||
|
if(srvfd < 0)
|
||||||
|
return;
|
||||||
|
close(srvfd);
|
||||||
|
srvfd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
srvconnect(void)
|
srvconnect(void)
|
||||||
{
|
{
|
||||||
struct sockaddr_un addr;
|
struct sockaddr_un addr;
|
||||||
|
int fd;
|
||||||
|
|
||||||
srvfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
if(srvfd >= 0)
|
||||||
if(srvfd < 0)
|
return 0;
|
||||||
die("socket failed");
|
fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if(fd < 0)
|
||||||
|
return -1;
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
addr.sun_family = AF_UNIX;
|
addr.sun_family = AF_UNIX;
|
||||||
snprintf(addr.sun_path, sizeof(addr.sun_path), "/tmp/strans.%d", getuid());
|
snprintf(addr.sun_path, sizeof(addr.sun_path), IPCPATH, getuid());
|
||||||
if(connect(srvfd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
|
if(connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0){
|
||||||
die("can't connect to strans");
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
srvfd = fd;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
readresp(xcb_im_input_context_t *ic)
|
readresp(xcb_im_input_context_t *ic)
|
||||||
{
|
{
|
||||||
unsigned char buf[64];
|
char buf[Ipcfieldmax+1];
|
||||||
int n;
|
Ipcresp resp;
|
||||||
|
|
||||||
if(read(srvfd, buf, 2) != 2)
|
if(ipcreadresp(srvfd, 0, buf, sizeof buf, NULL, 0, &resp) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
n = buf[1];
|
if(buf[0] != '\0')
|
||||||
if(n > 0 && (size_t)n < sizeof(buf) && read(srvfd, buf+2, n) == n)
|
commit(ic, buf, strlen(buf));
|
||||||
commit(ic, (char*)(buf+2), n);
|
return resp.eaten;
|
||||||
return buf[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
kpress(xcb_im_input_context_t *ic, xcb_key_press_event_t *ev)
|
kpress(xcb_im_input_context_t *ic, xcb_key_press_event_t *ev)
|
||||||
{
|
{
|
||||||
unsigned char buf[4];
|
unsigned char buf[Ipcreqsz];
|
||||||
uint32_t key;
|
uint32_t key, rune;
|
||||||
|
int eaten;
|
||||||
|
|
||||||
key = kget(ev->detail, ev->state);
|
key = kget(ev->detail, ev->state);
|
||||||
if(key >= 0xff00)
|
rune = xkb_keysym_to_utf32(key);
|
||||||
|
if(rune >= ' ' && rune != 0x7f)
|
||||||
|
key = rune;
|
||||||
|
else if(key >= 0xff00 && key <= 0xffff)
|
||||||
key = Kspec + (key - 0xff00);
|
key = Kspec + (key - 0xff00);
|
||||||
buf[0] = 0;
|
else
|
||||||
buf[1] = ev->state;
|
key = rune;
|
||||||
buf[2] = key;
|
ipcpackreq(buf, 0, ev->state, key);
|
||||||
buf[3] = key >> 8;
|
eaten = 0;
|
||||||
if(write(srvfd, buf, 4) != 4)
|
if(srvconnect() == 0){
|
||||||
die("write failed");
|
if(ipcsend(srvfd, buf, sizeof buf) < 0 ||
|
||||||
if(readresp(ic) == 0)
|
(eaten = readresp(ic)) < 0){
|
||||||
|
srvclose();
|
||||||
|
eaten = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(eaten == 0)
|
||||||
xcb_im_forward_event(xim, ic, ev);
|
xcb_im_forward_event(xim, ic, ev);
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
}
|
}
|
||||||
@@ -156,15 +181,13 @@ kpress(xcb_im_input_context_t *ic, xcb_key_press_event_t *ev)
|
|||||||
static void
|
static void
|
||||||
reset(xcb_im_input_context_t *ic)
|
reset(xcb_im_input_context_t *ic)
|
||||||
{
|
{
|
||||||
unsigned char buf[4];
|
unsigned char buf[Ipcreqsz];
|
||||||
|
|
||||||
buf[0] = 0;
|
ipcpackreq(buf, 0, 0, Kesc);
|
||||||
buf[1] = 0;
|
if(srvconnect() < 0)
|
||||||
buf[2] = Kesc & 0xff;
|
return;
|
||||||
buf[3] = Kesc >> 8;
|
if(ipcsend(srvfd, buf, sizeof buf) < 0 || readresp(ic) < 0)
|
||||||
if(write(srvfd, buf, 4) != 4)
|
srvclose();
|
||||||
die("write failed");
|
|
||||||
readresp(ic);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -173,6 +196,11 @@ callback(xcb_im_t *im, xcb_im_client_t *client, xcb_im_input_context_t *ic,
|
|||||||
{
|
{
|
||||||
xcb_key_press_event_t *ev;
|
xcb_key_press_event_t *ev;
|
||||||
|
|
||||||
|
(void)im;
|
||||||
|
(void)client;
|
||||||
|
(void)frame;
|
||||||
|
(void)user;
|
||||||
|
|
||||||
switch(hdr->major_opcode){
|
switch(hdr->major_opcode){
|
||||||
case XCB_XIM_FORWARD_EVENT:
|
case XCB_XIM_FORWARD_EVENT:
|
||||||
ev = arg;
|
ev = arg;
|
||||||
@@ -220,7 +248,6 @@ main(void)
|
|||||||
{
|
{
|
||||||
xcb_generic_event_t *ev;
|
xcb_generic_event_t *ev;
|
||||||
|
|
||||||
srvconnect();
|
|
||||||
ximinit();
|
ximinit();
|
||||||
for(;;){
|
for(;;){
|
||||||
ev = xcb_wait_for_event(conn);
|
ev = xcb_wait_for_event(conn);
|
||||||
@@ -229,5 +256,6 @@ main(void)
|
|||||||
xcb_im_filter_event(xim, ev);
|
xcb_im_filter_event(xim, ev);
|
||||||
free(ev);
|
free(ev);
|
||||||
}
|
}
|
||||||
|
srvclose();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user