uterm: input: add support for multiple keysyms
authorDavid Herrmann <dh.herrmann@googlemail.com>
Tue, 9 Oct 2012 09:19:30 +0000 (11:19 +0200)
committerDavid Herrmann <dh.herrmann@googlemail.com>
Tue, 9 Oct 2012 09:19:30 +0000 (11:19 +0200)
xkbcommon supports reporting multiple keysyms per key-event. There is no
keymap which uses this, yet. However, this feature is not meant to enhance
performance by reducing the number of calls into xkb, but instead multiple
keysyms are to be handled as one big keysym.
But there are no examples, yet, so we cannot actually perform any
conversions on them. But we can add the infrastructure for it.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
src/terminal.c
src/uterm.h
src/uterm_input.c
src/uterm_input.h
src/uterm_input_uxkb.c
src/uterm_vt.c

index fa513bf..e8f6f24 100644 (file)
@@ -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;
index 6525983..333e2cc 100644 (file)
@@ -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))
index 0d15dd6..a5e406d 100644 (file)
@@ -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);
 }
index 18e1997..0798ff3 100644 (file)
@@ -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 */
index a046c9a..caa1cb4 100644 (file)
@@ -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;
 }
index b293c9c..53e91df 100644 (file)
@@ -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");