From b22bb3097634206956392929795fd2902f08faa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 8 Mar 2020 12:08:46 +0100 Subject: [PATCH] wip: initial framework for dealing with key/mouse bindings in different modes This adds initial support for defining key and mouse bindings that are applied in different terminal modes/states. For example, there are two arrays dealing with key and mouse bindings in the "normal" mode. Most bindings will go here. There's also an array for "search" mode. These bindings will be used when the user has started a scrollback search. In the future, there may be a model selection mode as well. Or maybe "search" and "modal selection" will be combined into a single "keyboard" mode. We'll see. Since the keyboard bindings depend on the current XKB keymap, translation from the user specified key combination string cannot be done when loading the configuration, but must be done when we've received a keymap from the wayland server. We should explore if it's possible to load some kind of default keymap just to be able to verify the validity of the key combination strings at configuration load time, to be able to reject the configuration at startup. A couple of key bindings have been added as proof of concept. Mouse bindings aren't handled at all yet, and is likely to be re-written. For example, we can probably translate the configuration strings at configuration load time. --- config.c | 19 +++++++++++ config.h | 14 ++++++++ input.c | 97 +++++++++++++++++++++++++++++++++++++++++++++---------- wayland.c | 1 + wayland.h | 16 +++++++++ 5 files changed, 130 insertions(+), 17 deletions(-) diff --git a/config.c b/config.c index 46056567..0baa5eb5 100644 --- a/config.c +++ b/config.c @@ -619,6 +619,19 @@ config_load(struct config *conf, const char *conf_path) }, }, + .bindings = { + .key = { + [BIND_ACTION_CLIPBOARD_COPY] = strdup("Control+Shift+C"), + [BIND_ACTION_CLIPBOARD_PASTE] = strdup("Control+Shift+V"), + [BIND_ACTION_SEARCH_START] = strdup("Control+Shift+R"), + }, + .mouse = { + [BIND_ACTION_PRIMARY_PASTE] = strdup("BTN_MIDDLE"), + }, + .search = { + }, + }, + .csd = { .preferred = CONF_CSD_PREFER_SERVER, .title_height = 26, @@ -671,4 +684,10 @@ config_free(struct config conf) free(conf.shell); tll_free_and_free(conf.fonts, free); free(conf.server_socket_path); + + for (size_t i = 0; i < BIND_ACTION_COUNT; i++) { + free(conf.bindings.key[i]); + free(conf.bindings.mouse[i]); + free(conf.bindings.search[i]); + } } diff --git a/config.h b/config.h index a89637e1..af078b00 100644 --- a/config.h +++ b/config.h @@ -36,6 +36,20 @@ struct config { } color; } cursor; + struct { + /* Bindings for "normal" mode */ + char *key[BIND_ACTION_COUNT]; + char *mouse[BIND_ACTION_COUNT]; + + /* + * Special modes + */ + + /* While searching (not - action to *start* a search is in the + * 'key' bindings above */ + char *search[BIND_ACTION_COUNT]; + } bindings; + struct { enum { CONF_CSD_PREFER_SERVER, CONF_CSD_PREFER_CLIENT } preferred; diff --git a/input.c b/input.c index efa58c9d..0e6b3c92 100644 --- a/input.c +++ b/input.c @@ -31,6 +31,35 @@ #include "terminal.h" #include "vt.h" +static void +execute_binding(struct terminal *term, enum binding_action action, + uint32_t serial) +{ + switch (action) { + case BIND_ACTION_CLIPBOARD_COPY: + selection_to_clipboard(term, serial); + break; + + case BIND_ACTION_CLIPBOARD_PASTE: + selection_from_clipboard(term, serial); + term_reset_view(term); + break; + + case BIND_ACTION_PRIMARY_PASTE: + LOG_ERR("unimplemented"); + assert(false); + break; + + case BIND_ACTION_SEARCH_START: + search_begin(term); + break; + + case BIND_ACTION_COUNT: + assert(false); + break; + } +} + static void keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size) @@ -59,6 +88,7 @@ keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard, xkb_context_unref(wayl->kbd.xkb); wayl->kbd.xkb = NULL; } + tll_free(wayl->kbd.key_bindings); wayl->kbd.xkb = xkb_context_new(XKB_CONTEXT_NO_FLAGS); wayl->kbd.xkb_keymap = xkb_keymap_new_from_string( @@ -81,6 +111,48 @@ keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard, munmap(map_str, size); close(fd); + + for (size_t i = 0; i < BIND_ACTION_COUNT; i++) { + const char *combo = wayl->conf->bindings.key[i]; + + if (combo == NULL) + continue; + + xkb_mod_mask_t mod_mask = 0; + xkb_keysym_t sym = 0; + + char *copy = strdup(combo); + + for (char *p = strtok(copy, "+"), *n = strtok(NULL, "+"); + p != NULL; + p = n, n = strtok(NULL, "+")) + { + if (n != NULL) { + /* Modifier */ + xkb_mod_index_t mod = xkb_keymap_mod_get_index( + wayl->kbd.xkb_keymap, p); + + if (mod == -1) { + LOG_ERR("%s: not a valid modifier name", p); + continue; + } + + mod_mask |= 1 << mod; + LOG_DBG("MOD: %d - %s", mod, p); + } else { + /* Symbol */ + sym = xkb_keysym_from_name(p, 0); + } + } + + free(copy); + + assert(sym != 0); + + /* TODO: convert to DBG */ + LOG_INFO("binding: %s -> mods=0x%08x, sym=%d", combo, mod_mask, sym); + tll_push_back(wayl->kbd.key_bindings, ((struct key_binding){mod_mask, sym, i})); + } } static void @@ -374,6 +446,13 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, "effective=0x%08x, repeats=%d", sym, mods, consumed, significant, effective_mods, should_repeat); + tll_foreach(wayl->kbd.key_bindings, it) { + if (it->item.mods == effective_mods && it->item.sym == sym) { + execute_binding(term, it->item.action, serial); + goto maybe_repeat; + } + } + /* * Builtin shortcuts */ @@ -408,23 +487,7 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, } else if (effective_mods == (shift | ctrl)) { - if (sym == XKB_KEY_C) { - selection_to_clipboard(term, serial); - goto maybe_repeat; - } - - else if (sym == XKB_KEY_V) { - selection_from_clipboard(term, serial); - term_reset_view(term); - goto maybe_repeat; - } - - else if (sym == XKB_KEY_R) { - search_begin(term); - goto maybe_repeat; - } - - else if (sym == XKB_KEY_Return) { + if (sym == XKB_KEY_Return) { term_spawn_new(term); goto maybe_repeat; } diff --git a/wayland.c b/wayland.c index 4bf77562..c508c710 100644 --- a/wayland.c +++ b/wayland.c @@ -911,6 +911,7 @@ wayl_destroy(struct wayland *wayl) if (wayl->presentation != NULL) wp_presentation_destroy(wayl->presentation); + tll_free(wayl->kbd.key_bindings); if (wayl->kbd.xkb_compose_state != NULL) xkb_compose_state_unref(wayl->kbd.xkb_compose_state); if (wayl->kbd.xkb_compose_table != NULL) diff --git a/wayland.h b/wayland.h index ed53591d..775aee0f 100644 --- a/wayland.h +++ b/wayland.h @@ -41,6 +41,20 @@ struct monitor { float inch; /* e.g. 24" */ }; +enum binding_action { + BIND_ACTION_CLIPBOARD_COPY, + BIND_ACTION_CLIPBOARD_PASTE, + BIND_ACTION_PRIMARY_PASTE, + BIND_ACTION_SEARCH_START, + BIND_ACTION_COUNT, +}; + +struct key_binding { + xkb_mod_mask_t mods; + xkb_keysym_t sym; + enum binding_action action; +}; + struct kbd { struct xkb_context *xkb; struct xkb_keymap *xkb_keymap; @@ -66,6 +80,8 @@ struct kbd { bool alt; bool ctrl; bool meta; + + tll(struct key_binding) key_bindings; }; struct wl_clipboard {