tsm: vte: use ASCII keysyms for ctrl+<XY> shortcuts
authorDavid Herrmann <dh.herrmann@googlemail.com>
Tue, 9 Oct 2012 10:26:07 +0000 (12:26 +0200)
committerDavid Herrmann <dh.herrmann@googlemail.com>
Tue, 9 Oct 2012 10:30:40 +0000 (12:30 +0200)
If a user has multiple active XKB layouts but only one of them has ASCII
keysyms on the base level, then ctrl+<XY> might actually never work,
because these keys aren't available in the current layout. This patch
tries to find a layout of the user that actually _has_ ascii keysyms on
the base level and passes this information along with the normal keysym
information.

The TSM layer can now use this ascii keysym instead of the normal unicode
keysym to handle ctrl+<XY> shortcuts. This is the same way xterm et. al.
handle this, so it seems to be a good idea to do this in TSM, too.

Reported (and mainly written) by Ran Benita.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
src/shl_misc.h
src/terminal.c
src/tsm_vte.c
src/tsm_vte.h
src/uterm.h
src/uterm_input_uxkb.c
src/wlt_terminal.c
src/wlt_theme.c
src/wlt_toolkit.c
src/wlt_toolkit.h

index 47bee10..9afd058 100644 (file)
@@ -95,4 +95,35 @@ static inline unsigned int shl_get_xkb_mods(struct xkb_state *state)
        return mods;
 }
 
+static inline uint32_t shl_get_ascii(struct xkb_state *state, uint32_t keycode,
+                                    const uint32_t *keysyms,
+                                    unsigned int num_keysyms)
+{
+       struct xkb_keymap *keymap;
+       xkb_layout_index_t num_layouts;
+       xkb_layout_index_t layout;
+       xkb_level_index_t level;
+       const xkb_keysym_t *syms;
+       int num_syms;
+
+       if (num_keysyms == 1 && keysyms[0] < 128)
+               return keysyms[0];
+
+       keymap = xkb_state_get_map(state);
+       num_layouts = xkb_keymap_num_layouts_for_key(keymap, keycode);
+
+       for (layout = 0; layout < num_layouts; layout++) {
+               level = xkb_state_key_get_level(state, keycode, layout);
+               num_syms = xkb_keymap_key_get_syms_by_level(keymap, keycode,
+                                                       layout, level, &syms);
+               if (num_syms != 1)
+                       continue;
+
+               if (syms[0] < 128)
+                       return syms[0];
+       }
+
+       return XKB_KEY_NoSymbol;
+}
+
 #endif /* SHL_MISC_H */
index e8f6f24..460dd22 100644 (file)
@@ -393,8 +393,8 @@ static void input_event(struct uterm_input *input,
        if (ev->num_syms > 1)
                return;
 
-       if (tsm_vte_handle_keyboard(term->vte, ev->keysyms[0], ev->mods,
-                                   ev->codepoints[0])) {
+       if (tsm_vte_handle_keyboard(term->vte, ev->keysyms[0], ev->ascii,
+                                   ev->mods, ev->codepoints[0])) {
                tsm_screen_sb_reset(term->console);
                schedule_redraw(term);
                ev->handled = true;
index 155b242..5fd9bd6 100644 (file)
@@ -2152,10 +2152,12 @@ void tsm_vte_input(struct tsm_vte *vte, const char *u8, size_t len)
 }
 
 bool tsm_vte_handle_keyboard(struct tsm_vte *vte, uint32_t keysym,
-                            unsigned int mods, uint32_t unicode)
+                            uint32_t ascii, unsigned int mods,
+                            uint32_t unicode)
 {
        char val, u8[4];
        size_t len;
+       uint32_t sym;
 
        /* MOD1 (mostly labeled 'Alt') prepends an escape character to every
         * input that is sent by a key.
@@ -2167,8 +2169,22 @@ bool tsm_vte_handle_keyboard(struct tsm_vte *vte, uint32_t keysym,
        if (mods & TSM_ALT_MASK)
                vte->flags |= FLAG_PREPEND_ESCAPE;
 
+       /* A user might actually use multiple layouts for keyboard input. The
+        * @keysym variable contains the actual keysym that the user used. But
+        * if this keysym is not in the ascii range, the input handler does
+        * check all other layouts that the user specified whether one of them
+        * maps the key to some ASCII keysym and provides this via @ascii.
+        * We always use the real keysym except when handling CTRL+<XY>
+        * shortcuts we use the ascii keysym. This is for compatibility to xterm
+        * et. al. so ctrl+c always works regardless of the currently active
+        * keyboard layout.
+        * But if no ascii-sym is found, we still use the real keysym. */
+       sym = ascii;
+       if (sym == XKB_KEY_NoSymbol)
+               sym = keysym;
+
        if (mods & TSM_CONTROL_MASK) {
-               switch (keysym) {
+               switch (sym) {
                case XKB_KEY_2:
                case XKB_KEY_space:
                        vte_write(vte, "\x00", 1);
index d12b27a..638ac95 100644 (file)
@@ -79,6 +79,7 @@ void tsm_vte_reset(struct tsm_vte *vte);
 void tsm_vte_hard_reset(struct tsm_vte *vte);
 void tsm_vte_input(struct tsm_vte *vte, const char *u8, size_t len);
 bool tsm_vte_handle_keyboard(struct tsm_vte *vte, uint32_t keysym,
-                            unsigned int mods, uint32_t unicode);
+                            uint32_t ascii, unsigned int mods,
+                            uint32_t unicode);
 
 #endif /* TSM_VTE_H */
index 333e2cc..5424462 100644 (file)
@@ -271,6 +271,7 @@ enum uterm_input_modifier {
 struct uterm_input_event {
        bool handled;           /* user-controlled, default is false */
        uint16_t keycode;       /* linux keycode - KEY_* - linux/input.h */
+       uint32_t ascii;         /* ascii keysym for @keycode */
        unsigned int mods;      /* active modifiers - uterm_modifier mask */
 
        unsigned int num_syms;  /* number of keysyms */
index caa1cb4..09b8a52 100644 (file)
@@ -164,6 +164,7 @@ int uxkb_dev_process(struct uterm_input_dev *dev,
 
        dev->event.handled = false;
        dev->event.keycode = code;
+       dev->event.ascii = shl_get_ascii(state, code, keysyms, num_keysyms);
        dev->event.mods = shl_get_xkb_mods(state);
        dev->event.num_syms = num_keysyms;
        memcpy(dev->event.keysyms, keysyms, sizeof(uint32_t) * num_keysyms);
index 505945d..96b5bf0 100644 (file)
@@ -398,7 +398,8 @@ static const struct wl_data_source_listener copy_listener = {
 };
 
 static bool widget_key(struct wlt_widget *widget, unsigned int mask,
-                      uint32_t sym, uint32_t state, bool handled, void *data)
+                      uint32_t sym, uint32_t ascii, uint32_t state,
+                      bool handled, void *data)
 {
        struct wlt_terminal *term = data;
        uint32_t ucs4;
@@ -536,7 +537,7 @@ static bool widget_key(struct wlt_widget *widget, unsigned int mask,
                return true;
        }
 
-       if (tsm_vte_handle_keyboard(term->vte, sym, mask, ucs4)) {
+       if (tsm_vte_handle_keyboard(term->vte, sym, ascii, mask, ucs4)) {
                tsm_screen_sb_reset(term->scr);
                wlt_window_schedule_redraw(term->wnd);
                return true;
index b4e65d1..52b7d17 100644 (file)
@@ -531,7 +531,8 @@ static void widget_pointer_button(struct wlt_widget *widget,
 }
 
 static bool widget_key(struct wlt_widget *widget, unsigned int mask,
-                      uint32_t sym, uint32_t state, bool handled, void *data)
+                      uint32_t sym, uint32_t ascii, uint32_t state,
+                      bool handled, void *data)
 {
        struct wlt_theme *theme = data;
 
index 8531244..6b358c4 100644 (file)
@@ -101,6 +101,7 @@ struct wlt_display {
        struct wlt_window *keyboard_focus;
        struct ev_timer *repeat_timer;
        uint32_t repeat_sym;
+       uint32_t repeat_ascii;
 
        struct wl_data_device_manager *w_manager;
        struct wl_data_device *w_data_dev;
@@ -639,7 +640,7 @@ static void keyboard_key(void *data, struct wl_keyboard *keyboard,
 {
        struct wlt_display *disp = data;
        struct wlt_window *wnd = disp->keyboard_focus;
-       uint32_t code, num_syms;
+       uint32_t code, num_syms, ascii;
        unsigned int mask;
        enum wl_keyboard_key_state state = state_w;
        const xkb_keysym_t *syms;
@@ -659,6 +660,7 @@ static void keyboard_key(void *data, struct wl_keyboard *keyboard,
 
        mask = shl_get_xkb_mods(disp->xkb_state);
        num_syms = xkb_key_get_syms(disp->xkb_state, code, &syms);
+       ascii = shl_get_ascii(disp->xkb_state, code, syms, num_syms);
        sym = XKB_KEY_NoSymbol;
        if (num_syms == 1)
                sym = syms[0];
@@ -667,7 +669,7 @@ static void keyboard_key(void *data, struct wl_keyboard *keyboard,
        shl_dlist_for_each(iter, &wnd->widget_list) {
                widget = shl_dlist_entry(iter, struct wlt_widget, list);
                if (widget->keyboard_cb) {
-                       if (widget->keyboard_cb(widget, mask, sym, state,
+                       if (widget->keyboard_cb(widget, mask, sym, ascii, state,
                                                handled, widget->data))
                                handled = true;
                }
@@ -678,6 +680,7 @@ static void keyboard_key(void *data, struct wl_keyboard *keyboard,
                ev_timer_update(disp->repeat_timer, NULL);
        } else if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
                disp->repeat_sym = sym;
+               disp->repeat_ascii = ascii;
                spec.it_interval.tv_sec = 0;
                spec.it_interval.tv_nsec = wlt_conf.xkb_repeat_rate * 1000000;
                spec.it_value.tv_sec = 0;
@@ -704,6 +707,7 @@ static void repeat_event(struct ev_timer *timer, uint64_t num, void *data)
                widget = shl_dlist_entry(iter, struct wlt_widget, list);
                if (widget->keyboard_cb) {
                        if (widget->keyboard_cb(widget, mask, disp->repeat_sym,
+                                               disp->repeat_ascii,
                                                WL_KEYBOARD_KEY_STATE_PRESSED,
                                                handled, widget->data))
                                handled = true;
index df2edc1..20fac59 100644 (file)
@@ -115,6 +115,7 @@ typedef void (*wlt_widget_pointer_button_cb) (struct wlt_widget *widget,
 typedef bool (*wlt_widget_keyboard_cb) (struct wlt_widget *widget,
                                        unsigned int mods,
                                        uint32_t key,
+                                       uint32_t ascii,
                                        uint32_t state,
                                        bool handled,
                                        void *data);