diff --git a/src/terminal.c b/src/terminal.c index fa513bf..e8f6f24 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -359,36 +359,42 @@ static void input_event(struct uterm_input *input, return; if (UTERM_INPUT_HAS_MODS(ev, kmscon_conf.grab_scroll_up->mods) && - ev->keysym == kmscon_conf.grab_scroll_up->keysym) { + ev->keysyms[0] == kmscon_conf.grab_scroll_up->keysym) { tsm_screen_sb_up(term->console, 1); schedule_redraw(term); ev->handled = true; return; } if (UTERM_INPUT_HAS_MODS(ev, kmscon_conf.grab_scroll_down->mods) && - ev->keysym == kmscon_conf.grab_scroll_down->keysym) { + ev->keysyms[0] == kmscon_conf.grab_scroll_down->keysym) { tsm_screen_sb_down(term->console, 1); schedule_redraw(term); ev->handled = true; return; } if (UTERM_INPUT_HAS_MODS(ev, kmscon_conf.grab_page_up->mods) && - ev->keysym == kmscon_conf.grab_page_up->keysym) { + ev->keysyms[0] == kmscon_conf.grab_page_up->keysym) { tsm_screen_sb_page_up(term->console, 1); schedule_redraw(term); ev->handled = true; return; } if (UTERM_INPUT_HAS_MODS(ev, kmscon_conf.grab_page_down->mods) && - ev->keysym == kmscon_conf.grab_page_down->keysym) { + ev->keysyms[0] == kmscon_conf.grab_page_down->keysym) { tsm_screen_sb_page_down(term->console, 1); schedule_redraw(term); ev->handled = true; return; } - if (tsm_vte_handle_keyboard(term->vte, ev->keysym, ev->mods, - ev->unicode)) { + /* TODO: xkbcommon supports multiple keysyms, but it is currently + * unclear how this feature will be used. There is no keymap, which + * uses this, yet. */ + if (ev->num_syms > 1) + return; + + if (tsm_vte_handle_keyboard(term->vte, ev->keysyms[0], ev->mods, + ev->codepoints[0])) { tsm_screen_sb_reset(term->console); schedule_redraw(term); ev->handled = true; diff --git a/src/uterm.h b/src/uterm.h index 6525983..333e2cc 100644 --- a/src/uterm.h +++ b/src/uterm.h @@ -269,11 +269,13 @@ enum uterm_input_modifier { #define UTERM_INPUT_INVALID 0xffffffff struct uterm_input_event { - bool handled; + bool handled; /* user-controlled, default is false */ uint16_t keycode; /* linux keycode - KEY_* - linux/input.h */ - uint32_t keysym; /* X keysym - XKB_KEY_* - X11/keysym.h */ unsigned int mods; /* active modifiers - uterm_modifier mask */ - uint32_t unicode; /* ucs4 unicode value or UTERM_INPUT_INVALID */ + + unsigned int num_syms; /* number of keysyms */ + uint32_t *keysyms; /* XKB-common keysym-array - XKB_KEY_* */ + uint32_t *codepoints; /* ucs4 unicode value or UTERM_INPUT_INVALID */ }; #define UTERM_INPUT_HAS_MODS(_ev, _mods) (((_ev)->mods & (_mods)) == (_mods)) diff --git a/src/uterm_input.c b/src/uterm_input.c index 0d15dd6..a5e406d 100644 --- a/src/uterm_input.c +++ b/src/uterm_input.c @@ -61,17 +61,15 @@ static void notify_key(struct uterm_input_dev *dev, int32_t value) { int ret; - struct uterm_input_event ev; if (type != EV_KEY) return; - memset(&ev, 0, sizeof(ev)); - ret = uxkb_dev_process(dev, value, code, &ev); + ret = uxkb_dev_process(dev, value, code); if (ret) return; - shl_hook_call(dev->input->hook, dev->input, &ev); + shl_hook_call(dev->input->hook, dev->input, &dev->event); } static void input_data_dev(struct ev_fd *fd, int mask, void *data) @@ -179,9 +177,17 @@ static void input_new_dev(struct uterm_input *input, if (!dev->node) goto err_free; + dev->num_syms = 1; + dev->event.keysyms = malloc(sizeof(uint32_t) * dev->num_syms); + if (!dev->event.keysyms) + goto err_node; + dev->event.codepoints = malloc(sizeof(uint32_t) * dev->num_syms); + if (!dev->event.codepoints) + goto err_syms; + ret = uxkb_dev_init(dev); if (ret) - goto err_node; + goto err_codepoints; if (input->awake > 0) { ret = input_wake_up_dev(dev); @@ -195,6 +201,10 @@ static void input_new_dev(struct uterm_input *input, err_kbd: uxkb_dev_destroy(dev); +err_codepoints: + free(dev->event.codepoints); +err_syms: + free(dev->event.keysyms); err_node: free(dev->node); err_free: @@ -207,6 +217,8 @@ static void input_free_dev(struct uterm_input_dev *dev) input_sleep_dev(dev); shl_dlist_unlink(&dev->list); uxkb_dev_destroy(dev); + free(dev->event.codepoints); + free(dev->event.keysyms); free(dev->node); free(dev); } diff --git a/src/uterm_input.h b/src/uterm_input.h index 18e1997..0798ff3 100644 --- a/src/uterm_input.h +++ b/src/uterm_input.h @@ -46,6 +46,9 @@ struct uterm_input_dev { char *node; struct ev_fd *fd; struct xkb_state *state; + + struct uterm_input_event event; + unsigned int num_syms; }; struct uterm_input { @@ -75,8 +78,7 @@ int uxkb_dev_init(struct uterm_input_dev *dev); void uxkb_dev_destroy(struct uterm_input_dev *dev); int uxkb_dev_process(struct uterm_input_dev *dev, uint16_t key_state, - uint16_t code, - struct uterm_input_event *out); + uint16_t code); void uxkb_dev_reset(struct uterm_input_dev *dev, const unsigned long *ledbits); #endif /* UTERM_INPUT_H */ diff --git a/src/uterm_input_uxkb.c b/src/uterm_input_uxkb.c index a046c9a..caa1cb4 100644 --- a/src/uterm_input_uxkb.c +++ b/src/uterm_input_uxkb.c @@ -113,15 +113,14 @@ enum { }; int uxkb_dev_process(struct uterm_input_dev *dev, - uint16_t key_state, - uint16_t code, - struct uterm_input_event *out) + uint16_t key_state, uint16_t code) { struct xkb_state *state; struct xkb_keymap *keymap; xkb_keycode_t keycode; const xkb_keysym_t *keysyms; - int num_keysyms; + int num_keysyms, i; + uint32_t *tmp; state = dev->state; keymap = xkb_state_get_map(state); @@ -143,15 +142,37 @@ int uxkb_dev_process(struct uterm_input_dev *dev, if (num_keysyms <= 0) return -ENOKEY; - /* - * TODO: xkbcommon actually supports multiple keysyms - * per key press. Here we're just using the first one, - * but we might want to support this feature. - */ - out->keycode = code; - out->keysym = keysyms[0]; - out->mods = shl_get_xkb_mods(state); - out->unicode = xkb_keysym_to_utf32(out->keysym) ? : UTERM_INPUT_INVALID; + if (dev->num_syms < num_keysyms) { + tmp = realloc(dev->event.keysyms, + sizeof(uint32_t) * num_keysyms); + if (!tmp) { + log_warning("cannot reallocate keysym buffer"); + return -ENOKEY; + } + dev->event.keysyms = tmp; + + tmp = realloc(dev->event.codepoints, + sizeof(uint32_t) * num_keysyms); + if (!tmp) { + log_warning("cannot reallocate codepoints buffer"); + return -ENOKEY; + } + dev->event.codepoints = tmp; + + dev->num_syms = num_keysyms; + } + + dev->event.handled = false; + dev->event.keycode = code; + dev->event.mods = shl_get_xkb_mods(state); + dev->event.num_syms = num_keysyms; + memcpy(dev->event.keysyms, keysyms, sizeof(uint32_t) * num_keysyms); + + for (i = 0; i < num_keysyms; ++i) { + dev->event.codepoints[i] = xkb_keysym_to_utf32(keysyms[i]); + if (!dev->event.codepoints[i]) + dev->event.codepoints[i] = UTERM_INPUT_INVALID; + } return 0; } diff --git a/src/uterm_vt.c b/src/uterm_vt.c index b293c9c..53e91df 100644 --- a/src/uterm_vt.c +++ b/src/uterm_vt.c @@ -503,15 +503,15 @@ static void real_input(struct uterm_vt *vt, struct uterm_input_event *ev) id = 0; if (SHL_HAS_BITS(ev->mods, SHL_CONTROL_MASK | SHL_ALT_MASK) && - ev->keysym >= XKB_KEY_F1 && ev->keysym <= XKB_KEY_F12) { + ev->keysyms[0] >= XKB_KEY_F1 && ev->keysyms[0] <= XKB_KEY_F12) { ev->handled = true; - id = ev->keysym - XKB_KEY_F1 + 1; + id = ev->keysyms[0] - XKB_KEY_F1 + 1; if (id == vt->real_num) return; - } else if (ev->keysym >= XKB_KEY_XF86Switch_VT_1 && - ev->keysym <= XKB_KEY_XF86Switch_VT_12) { + } else if (ev->keysyms[0] >= XKB_KEY_XF86Switch_VT_1 && + ev->keysyms[0] <= XKB_KEY_XF86Switch_VT_12) { ev->handled = true; - id = ev->keysym - XKB_KEY_XF86Switch_VT_1 + 1; + id = ev->keysyms[0] - XKB_KEY_XF86Switch_VT_1 + 1; if (id == vt->real_num) return; } @@ -577,7 +577,7 @@ static void fake_input(struct uterm_vt *vt, struct uterm_input_event *ev) return; if (SHL_HAS_BITS(ev->mods, SHL_CONTROL_MASK | SHL_LOGO_MASK) && - ev->keysym == XKB_KEY_F12) { + ev->keysyms[0] == XKB_KEY_F12) { ev->handled = true; if (vt->active) { log_debug("deactivating fake VT due to user input");