#include "dat.h" #include "fn.h" #include #include #include #include #include #include #include #include "input-method-unstable-v2-client-protocol.h" #include "virtual-keyboard-unstable-v1-client-protocol.h" static struct wl_display *dpy; static struct wl_seat *seat; static struct zwp_input_method_manager_v2 *immgr; static struct zwp_virtual_keyboard_manager_v1 *vkmgr; static struct zwp_input_method_v2 *im; static struct zwp_input_method_keyboard_grab_v2 *grab; static struct zwp_virtual_keyboard_v1 *vk; static struct xkb_context *xkb; static struct xkb_keymap *keymap; static struct xkb_state *xkbst; static int active; static int pending; static u32int imserial; static void sendkey(u32int ks, u32int mod, char *com, int csz, char *pre, int psz, int *eaten) { 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.mod = mod; kr.want = 1; chansend(keyc, &kr); if(read(p[0], hdr, 2) != 2) 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 sendreset(void) { char com[64], pre[256]; int eaten; sendkey(Kesc, 0, com, sizeof(com), pre, sizeof(pre), &eaten); } static u32int mget(void) { u32int m; m = 0; if(xkbst == nil) return 0; if(xkb_state_mod_name_is_active(xkbst, XKB_MOD_NAME_SHIFT, XKB_STATE_MODS_EFFECTIVE) > 0) m |= Mshift; if(xkb_state_mod_name_is_active(xkbst, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_EFFECTIVE) > 0) m |= Mctrl; if(xkb_state_mod_name_is_active(xkbst, XKB_MOD_NAME_ALT, XKB_STATE_MODS_EFFECTIVE) > 0) m |= Malt; if(xkb_state_mod_name_is_active(xkbst, XKB_MOD_NAME_LOGO, XKB_STATE_MODS_EFFECTIVE) > 0) m |= Msuper; return m; } static void kpress(uint32_t time, uint32_t keycode, uint32_t state) { xkb_keysym_t ks; u32int k, mod; char com[64], pre[256]; int eaten, plen; if(state != WL_KEYBOARD_KEY_STATE_PRESSED || xkbst == nil){ zwp_virtual_keyboard_v1_key(vk, time, keycode, state); return; } ks = xkb_state_key_get_one_sym(xkbst, keycode + 8); k = ks >= 0xff00 ? Kspec + (ks - 0xff00) : xkb_keysym_to_utf32(ks); if(k == 0){ zwp_virtual_keyboard_v1_key(vk, time, keycode, state); return; } mod = mget(); sendkey(k, mod, com, sizeof(com), pre, sizeof(pre), &eaten); if(com[0] != '\0') zwp_input_method_v2_commit_string(im, com); plen = strlen(pre); zwp_input_method_v2_set_preedit_string(im, pre, plen, plen); zwp_input_method_v2_commit(im, imserial); if(!eaten) zwp_virtual_keyboard_v1_key(vk, time, keycode, state); } static void kg_keymap(void *data, struct zwp_input_method_keyboard_grab_v2 *g, uint32_t format, int32_t fd, uint32_t size) { char *s; (void)data; (void)g; if(format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1){ close(fd); return; } s = mmap(nil, size, PROT_READ, MAP_PRIVATE, fd, 0); if(s != MAP_FAILED){ if(xkbst != nil){ xkb_state_unref(xkbst); xkbst = nil; } if(keymap != nil) xkb_keymap_unref(keymap); keymap = xkb_keymap_new_from_string(xkb, s, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); if(keymap != nil) xkbst = xkb_state_new(keymap); munmap(s, size); } zwp_virtual_keyboard_v1_keymap(vk, format, fd, size); } static void kg_key(void *data, struct zwp_input_method_keyboard_grab_v2 *g, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { (void)data; (void)g; (void)serial; kpress(time, key, state); } static void kg_mods(void *data, struct zwp_input_method_keyboard_grab_v2 *g, uint32_t serial, uint32_t dep, uint32_t lat, uint32_t lck, uint32_t group) { (void)data; (void)g; (void)serial; if(xkbst != nil) xkb_state_update_mask(xkbst, dep, lat, lck, 0, 0, group); zwp_virtual_keyboard_v1_modifiers(vk, dep, lat, lck, group); } static void kg_repeat(void *data, struct zwp_input_method_keyboard_grab_v2 *g, int32_t rate, int32_t delay) { (void)data; (void)g; (void)rate; (void)delay; } static const struct zwp_input_method_keyboard_grab_v2_listener grab_listener = { .keymap = kg_keymap, .key = kg_key, .modifiers = kg_mods, .repeat_info = kg_repeat, }; static void im_activate(void *data, struct zwp_input_method_v2 *m) { (void)data; (void)m; pending = 1; } static void im_deactivate(void *data, struct zwp_input_method_v2 *m) { (void)data; (void)m; pending = 0; if(active){ active = 0; sendreset(); if(grab != nil){ zwp_input_method_keyboard_grab_v2_release(grab); grab = nil; } } } static void im_surrounding(void *data, struct zwp_input_method_v2 *m, const char *text, uint32_t cursor, uint32_t anchor) { (void)data; (void)m; (void)text; (void)cursor; (void)anchor; } static void im_textchange(void *data, struct zwp_input_method_v2 *m, uint32_t cause) { (void)data; (void)m; (void)cause; } static void im_content(void *data, struct zwp_input_method_v2 *m, uint32_t hint, uint32_t purpose) { (void)data; (void)m; (void)hint; (void)purpose; } static void im_done(void *data, struct zwp_input_method_v2 *m) { (void)data; (void)m; imserial++; if(pending && !active){ active = 1; grab = zwp_input_method_v2_grab_keyboard(im); if(grab != nil) zwp_input_method_keyboard_grab_v2_add_listener(grab, &grab_listener, nil); } } static void im_unavail(void *data, struct zwp_input_method_v2 *m) { (void)data; (void)m; fprint(2, "strans: wayland: input-method unavailable\n"); } static const struct zwp_input_method_v2_listener im_listener = { .activate = im_activate, .deactivate = im_deactivate, .surrounding_text = im_surrounding, .text_change_cause = im_textchange, .content_type = im_content, .done = im_done, .unavailable = im_unavail, }; static void reg_global(void *data, struct wl_registry *r, uint32_t name, const char *iface, uint32_t version) { (void)data; (void)version; if(strcmp(iface, wl_seat_interface.name) == 0) seat = wl_registry_bind(r, name, &wl_seat_interface, 5); else if(strcmp(iface, zwp_input_method_manager_v2_interface.name) == 0) immgr = wl_registry_bind(r, name, &zwp_input_method_manager_v2_interface, 1); else if(strcmp(iface, zwp_virtual_keyboard_manager_v1_interface.name) == 0) vkmgr = wl_registry_bind(r, name, &zwp_virtual_keyboard_manager_v1_interface, 1); } static void reg_remove(void *data, struct wl_registry *r, uint32_t name) { (void)data; (void)r; (void)name; } static const struct wl_registry_listener reg_listener = { .global = reg_global, .global_remove = reg_remove, }; void waylandthread(void *_) { struct wl_registry *reg; (void)_; threadsetname("wayland"); dpy = wl_display_connect(nil); if(dpy == nil){ fprint(2, "strans: wayland: cannot connect to display\n"); return; } xkb = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if(xkb == nil){ wl_display_disconnect(dpy); dpy = nil; return; } reg = wl_display_get_registry(dpy); wl_registry_add_listener(reg, ®_listener, nil); wl_display_roundtrip(dpy); if(seat == nil || immgr == nil || vkmgr == nil){ fprint(2, "strans: wayland: compositor missing input-method-v2\n"); wl_display_disconnect(dpy); dpy = nil; return; } im = zwp_input_method_manager_v2_get_input_method(immgr, seat); zwp_input_method_v2_add_listener(im, &im_listener, nil); vk = zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(vkmgr, seat); while(wl_display_dispatch(dpy) != -1) ; }