From a4d53bdf88ea112d1d802a6a004a84732297f01b Mon Sep 17 00:00:00 2001 From: "feeptr@codeberg.org" Date: Mon, 27 Sep 2021 19:09:07 +0000 Subject: [PATCH] config, input: allow configuring select-override modifiers --- config.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++------- config.h | 1 + input.c | 14 +++++---- input.h | 5 ++++ terminal.c | 11 +++++-- wayland.h | 2 ++ 6 files changed, 100 insertions(+), 19 deletions(-) diff --git a/config.c b/config.c index 0616e87a..5dd59384 100644 --- a/config.c +++ b/config.c @@ -1333,6 +1333,10 @@ parse_section_cursor(struct context *ctx) return true; } +static bool +parse_modifiers(struct context *ctx, const char *text, size_t len, + struct config_key_modifiers *modifiers); + static bool parse_section_mouse(struct context *ctx) { @@ -1345,6 +1349,13 @@ parse_section_mouse(struct context *ctx) else if (strcmp(key, "alternate-scroll-mode") == 0) return value_to_bool(ctx, &conf->mouse.alternate_scroll_mode); + else if (strcmp(key, "selection-override-modifiers") == 0) { + if (!parse_modifiers(ctx, ctx->value, strlen(ctx->value), &conf->mouse.selection_override_modifiers)) { + LOG_CONTEXTUAL_ERR("%s: invalid modifiers '%s'", key, ctx->value); + return false; + } + } + else { LOG_CONTEXTUAL_ERR("not a valid option: %s", key); return false; @@ -1971,10 +1982,6 @@ value_to_mouse_combos(struct context *ctx, struct key_combo_list *key_combos) *key = '\0'; if (!parse_modifiers(ctx, combo, key - combo, &modifiers)) goto err; - if (modifiers.shift) { - LOG_CONTEXTUAL_ERR("Shift cannot be used in mouse bindings"); - goto err; - } key++; /* Skip past the '+' */ } @@ -2054,6 +2061,62 @@ err: return false; } +static bool +modifiers_equal(const struct config_key_modifiers *mods1, + const struct config_key_modifiers *mods2) +{ + bool shift = mods1->shift == mods2->shift; + bool alt = mods1->alt == mods2->alt; + bool ctrl = mods1->ctrl == mods2->ctrl; + bool meta = mods1->meta == mods2->meta; + return shift && alt && ctrl && meta; +} + +static bool +modifiers_disjoint(const struct config_key_modifiers *mods1, + const struct config_key_modifiers *mods2) +{ + bool shift = mods1->shift && mods2->shift; + bool alt = mods1->alt && mods2->alt; + bool ctrl = mods1->ctrl && mods2->ctrl; + bool meta = mods1->meta && mods2->meta; + return !(shift || alt || ctrl || meta); +} + +static char * +modifiers_to_str(const struct config_key_modifiers *mods) +{ + char *ret = xasprintf("%s%s%s%s", + mods->ctrl ? "Control+" : "", + mods->alt ? "Alt+": "", + mods->meta ? "Meta+": "", + mods->shift ? "Shift+": ""); + ret[strlen(ret) - 1] = '\0'; + return ret; +} + +static bool +selection_override_interferes_with_mouse_binding(struct context *ctx, + const struct key_combo_list *key_combos) +{ + struct config *conf = ctx->conf; + + const struct config_key_modifiers *override_mods = &conf->mouse.selection_override_modifiers; + for (size_t i = 0; i < key_combos->count; i++) { + const struct key_combo *combo = &key_combos->combos[i]; + if (!modifiers_disjoint(&combo->modifiers, override_mods)) { + char *modifiers_str = modifiers_to_str(override_mods); + LOG_CONTEXTUAL_ERR( + "Selection override modifiers (%s) cannot be used in mouse bindings", + modifiers_str); + free (modifiers_str); + return false; + } + } + + return false; +} + static bool has_mouse_binding_collisions(struct context *ctx, const struct key_combo_list *key_combos) @@ -2071,14 +2134,10 @@ has_mouse_binding_collisions(struct context *ctx, const struct config_key_modifiers *mods1 = &combo1->modifiers; const struct config_key_modifiers *mods2 = &combo2->modifiers; - bool shift = mods1->shift == mods2->shift; - bool alt = mods1->alt == mods2->alt; - bool ctrl = mods1->ctrl == mods2->ctrl; - bool meta = mods1->meta == mods2->meta; bool button = combo1->button == combo2->m.button; bool count = combo1->count == combo2->m.count; - if (shift && alt && ctrl && meta && button && count) { + if (modifiers_equal(mods1, mods2) && button && count) { bool has_pipe = combo1->pipe.argv.args != NULL; LOG_CONTEXTUAL_ERR("%s already mapped to '%s%s%s%s'", combo2->text, @@ -2136,7 +2195,8 @@ parse_section_mouse_bindings(struct context *ctx) struct key_combo_list key_combos = {0}; if (!value_to_mouse_combos(ctx, &key_combos) || - has_mouse_binding_collisions(ctx, &key_combos)) + has_mouse_binding_collisions(ctx, &key_combos) || + selection_override_interferes_with_mouse_binding(ctx, &key_combos)) { free_argv(&pipe_argv); free_key_combo_list(&key_combos); @@ -2780,6 +2840,12 @@ config_load(struct config *conf, const char *conf_path, .mouse = { .hide_when_typing = false, .alternate_scroll_mode = true, + .selection_override_modifiers = { + .shift = true, + .alt = false, + .ctrl = false, + .meta = false, + }, }, .csd = { .preferred = CONF_CSD_PREFER_SERVER, diff --git a/config.h b/config.h index afe9cf74..2ae3a2d5 100644 --- a/config.h +++ b/config.h @@ -193,6 +193,7 @@ struct config { struct { bool hide_when_typing; bool alternate_scroll_mode; + struct config_key_modifiers selection_override_modifiers; } mouse; struct { diff --git a/input.c b/input.c index 055c0fc8..36991567 100644 --- a/input.c +++ b/input.c @@ -701,6 +701,11 @@ keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard, seat->kbd.key_arrow_down = xkb_keymap_key_by_name(seat->kbd.xkb_keymap, "DOWN"); } + /* Set selection-override modmask from configured mods and seat's mod indices */ + const struct config_key_modifiers* override_mods = + &wayl->conf->mouse.selection_override_modifiers; + seat->kbd.selection_override_modmask = conf_modifiers_to_mask(seat, override_mods); + munmap(map_str, size); close(fd); @@ -983,7 +988,7 @@ UNITTEST xassert(strcmp(info->seq, "\033[27;3;13~") == 0); } -static void +void get_current_modifiers(const struct seat *seat, xkb_mod_mask_t *effective, xkb_mod_mask_t *consumed, uint32_t key) @@ -2372,11 +2377,8 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer, get_current_modifiers(seat, &mods, NULL, 0); mods &= seat->kbd.bind_significant; - /* Ignore Shift when matching modifiers, since it is - * used to enable selection in mouse grabbing client - * applications */ - if (seat->kbd.mod_shift != XKB_MOD_INVALID) - mods &= ~(1 << seat->kbd.mod_shift); + /* Ignore selection override modifiers when matching modifiers */ + mods &= ~seat->kbd.selection_override_modmask; const struct mouse_binding *match = NULL; diff --git a/input.h b/input.h index da887ef2..8430eef9 100644 --- a/input.h +++ b/input.h @@ -27,4 +27,9 @@ extern const struct wl_pointer_listener pointer_listener; void input_repeat(struct seat *seat, uint32_t key); +void get_current_modifiers(const struct seat *seat, + xkb_mod_mask_t *effective, + xkb_mod_mask_t *consumed, + uint32_t key); + const char *xcursor_for_csd_border(struct terminal *term, int x, int y); diff --git a/terminal.c b/terminal.c index 25310d36..1d27693a 100644 --- a/terminal.c +++ b/terminal.c @@ -2826,10 +2826,15 @@ term_mouse_grabbed(const struct terminal *term, struct seat *seat) /* * Mouse is grabbed by us, regardless of whether mouse tracking has been enabled or not. */ + + xkb_mod_mask_t mods; + get_current_modifiers(seat, &mods, NULL, 0); + + const xkb_mod_mask_t override_modmask = seat->kbd.selection_override_modmask; + bool override_mods_pressed = (mods & override_modmask) == override_modmask; + return term->mouse_tracking == MOUSE_NONE || - (seat->kbd_focus == term && - seat->kbd.shift && - !seat->kbd.alt && /*!seat->kbd.ctrl &&*/ !seat->kbd.super); + (seat->kbd_focus == term && override_mods_pressed); } void diff --git a/wayland.h b/wayland.h index d415588b..e84ce237 100644 --- a/wayland.h +++ b/wayland.h @@ -201,6 +201,8 @@ struct seat { xkb_mod_mask_t bind_significant; xkb_mod_mask_t kitty_significant; + xkb_mod_mask_t selection_override_modmask; + xkb_keycode_t key_arrow_up; xkb_keycode_t key_arrow_down;