From a4d53bdf88ea112d1d802a6a004a84732297f01b Mon Sep 17 00:00:00 2001 From: "feeptr@codeberg.org" Date: Mon, 27 Sep 2021 19:09:07 +0000 Subject: [PATCH 1/8] 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; From fade19b51209fa130bc6f9513307c9614721a0fb Mon Sep 17 00:00:00 2001 From: "feeptr@codeberg.org" Date: Mon, 27 Sep 2021 19:39:39 +0000 Subject: [PATCH 2/8] doc: document select-override-mods --- doc/foot.ini.5.scd | 17 ++++++++++++++--- foot.ini | 1 + 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/doc/foot.ini.5.scd b/doc/foot.ini.5.scd index 1b6c4d8c..f84cc9f6 100644 --- a/doc/foot.ini.5.scd +++ b/doc/foot.ini.5.scd @@ -470,6 +470,16 @@ applications can change these at runtime. Default: _yes_. +*selection-override-modifiers* + Modifiers. The set of modifiers which, when held, will override + attempts by programs running in the terminal to capture mouse + input. + + Any modifiers in this set cannot be used for mouse bindings + themselves. + + Default: Shift + # SECTION: colors @@ -865,9 +875,10 @@ of the modifiers *must* be valid XKB key names, and the button name *must* be a valid libinput name. You can find the button names using *libinput debug-events*. -Note that *Shift* cannot be used as a modifier in mouse bindings since -it is used to enable selection when the client application is grabbing -the mouse. +Note that the modifiers set in *mouse.selection-override-modifiers* +(by default, *Shift*) cannot be used as modifiers in mouse bindings +since they are used to enable selection when the client application is +grabbing the mouse. The trailing *COUNT* is optional and specifies the click count required to trigger the binding. The default if *COUNT* is omitted is diff --git a/foot.ini b/foot.ini index 09049b68..d756a7e4 100644 --- a/foot.ini +++ b/foot.ini @@ -63,6 +63,7 @@ [mouse] # hide-when-typing=no # alternate-scroll-mode=yes +# selection-override-modifiers=Shift [colors] # alpha=1.0 From 300acda8132a66dd5f88a159f883cd2f80ecc6cf Mon Sep 17 00:00:00 2001 From: "feeptr@codeberg.org" Date: Sat, 9 Oct 2021 21:40:11 +0000 Subject: [PATCH 3/8] changelog: list new mouse.selection-override-modifiers option --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc9e0e95..cc9c864b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,12 @@ ## Unreleased ### Added + +* `[mouse].selection-override-modifiers` option, specifying which modifiers + to hold to override mouse grabs by client applications and force selection + instead. + + ### Changed ### Deprecated ### Removed From 46cadee80f596ce9c50e6b4e191471a4186dce1c Mon Sep 17 00:00:00 2001 From: "feeptr@codeberg.org" Date: Mon, 29 Nov 2021 21:45:00 +0000 Subject: [PATCH 4/8] config: parse 'none' as empty modifiers value --- config.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/config.c b/config.c index 5dd59384..d4eac3ac 100644 --- a/config.c +++ b/config.c @@ -1485,6 +1485,11 @@ parse_modifiers(struct context *ctx, const char *text, size_t len, bool ret = false; *modifiers = (struct config_key_modifiers){0}; + + /* Handle "none" separately because e.g. none+shift is nonsense */ + if (strncmp(text, "none", len) == 0) + return true; + char *copy = xstrndup(text, len); for (char *tok_ctx = NULL, *key = strtok_r(copy, "+", &tok_ctx); From b52cd67467cb5e5f334f00680b42f8e071be1e79 Mon Sep 17 00:00:00 2001 From: "feeptr@codeberg.org" Date: Mon, 29 Nov 2021 22:06:35 +0000 Subject: [PATCH 5/8] config, doc, changelog: move selection-override-modifiers to [mouse-bindings] and validate other case specifically, check for conflicts both when mouse bindings are set and when the selection-override-modifiers setting itself is set --- CHANGELOG.md | 6 +++--- config.c | 38 +++++++++++++++++++++++++++++++------- doc/foot.ini.5.scd | 20 ++++++-------------- foot.ini | 2 +- 4 files changed, 41 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc9c864b..23f10509 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,9 +38,9 @@ ## Unreleased ### Added -* `[mouse].selection-override-modifiers` option, specifying which modifiers - to hold to override mouse grabs by client applications and force selection - instead. +* `[mouse-bindings].selection-override-modifiers` option, specifying + which modifiers to hold to override mouse grabs by client + applications and force selection instead. ### Changed diff --git a/config.c b/config.c index d4eac3ac..59d7bdab 100644 --- a/config.c +++ b/config.c @@ -1349,13 +1349,6 @@ 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; @@ -2166,6 +2159,37 @@ parse_section_mouse_bindings(struct context *ctx) const char *key = ctx->key; const char *value = ctx->value; + if (strcmp(ctx->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; + } + + /* Ensure no existing bindings use these modifiers */ + for (size_t i = 0; i < conf->bindings.mouse.count; i++) { + const struct config_mouse_binding *binding = &conf->bindings.mouse.arr[i]; + struct key_combo combo = { + .modifiers = binding->modifiers, + .m = { + .button = binding->button, + .count = binding->count, + }, + }; + + struct key_combo_list key_combos = { + .count = 1, + .combos = &combo, + }; + + if (selection_override_interferes_with_mouse_binding(ctx, &key_combos)) { + return false; + } + } + + return true; + } + struct argv pipe_argv; ssize_t pipe_remove_len = pipe_argv_from_value(ctx, &pipe_argv); diff --git a/doc/foot.ini.5.scd b/doc/foot.ini.5.scd index f84cc9f6..5f55dc45 100644 --- a/doc/foot.ini.5.scd +++ b/doc/foot.ini.5.scd @@ -470,16 +470,6 @@ applications can change these at runtime. Default: _yes_. -*selection-override-modifiers* - Modifiers. The set of modifiers which, when held, will override - attempts by programs running in the terminal to capture mouse - input. - - Any modifiers in this set cannot be used for mouse bindings - themselves. - - Default: Shift - # SECTION: colors @@ -875,10 +865,12 @@ of the modifiers *must* be valid XKB key names, and the button name *must* be a valid libinput name. You can find the button names using *libinput debug-events*. -Note that the modifiers set in *mouse.selection-override-modifiers* -(by default, *Shift*) cannot be used as modifiers in mouse bindings -since they are used to enable selection when the client application is -grabbing the mouse. +The modifiers set in *[mouse-bindings].selection-override-modifiers* +(by default, *Shift*) cannot be used as modifiers in mouse bindings, +and are instead used to enable selecting text with the mouse +irrespective of whether a client application currently has the mouse +grabbed. Because the order of bindings is significant, it's best to +set this prior to any other mouse bindings that might use *Shift*. The trailing *COUNT* is optional and specifies the click count required to trigger the binding. The default if *COUNT* is omitted is diff --git a/foot.ini b/foot.ini index d756a7e4..399becaa 100644 --- a/foot.ini +++ b/foot.ini @@ -63,7 +63,6 @@ [mouse] # hide-when-typing=no # alternate-scroll-mode=yes -# selection-override-modifiers=Shift [colors] # alpha=1.0 @@ -170,6 +169,7 @@ # toggle-url-visible=t [mouse-bindings] +# selection-override-modifiers=Shift # primary-paste=BTN_MIDDLE # select-begin=BTN_LEFT # select-begin-block=Control+BTN_LEFT From 9e111118d62a4c3264b010f71aa8622b92fb814e Mon Sep 17 00:00:00 2001 From: "feeptr@codeberg.org" Date: Mon, 29 Nov 2021 22:52:06 +0000 Subject: [PATCH 6/8] config: move button_map out of value_to_mouse_combos for reuse this mapping is only available here or in libevdev (libevdev_event_code_get_name) and it's simpler to factor it out here --- config.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/config.c b/config.c index 59d7bdab..1903e83c 100644 --- a/config.c +++ b/config.c @@ -1956,6 +1956,20 @@ parse_section_url_bindings(struct context *ctx) &ctx->conf->bindings.url); } +static const struct { + const char *name; + int code; +} button_map[] = { + {"BTN_LEFT", BTN_LEFT}, + {"BTN_RIGHT", BTN_RIGHT}, + {"BTN_MIDDLE", BTN_MIDDLE}, + {"BTN_SIDE", BTN_SIDE}, + {"BTN_EXTRA", BTN_EXTRA}, + {"BTN_FORWARD", BTN_FORWARD}, + {"BTN_BACK", BTN_BACK}, + {"BTN_TASK", BTN_TASK}, +}; + static bool value_to_mouse_combos(struct context *ctx, struct key_combo_list *key_combos) { @@ -2004,24 +2018,10 @@ value_to_mouse_combos(struct context *ctx, struct key_combo_list *key_combos) } } - static const struct { - const char *name; - int code; - } map[] = { - {"BTN_LEFT", BTN_LEFT}, - {"BTN_RIGHT", BTN_RIGHT}, - {"BTN_MIDDLE", BTN_MIDDLE}, - {"BTN_SIDE", BTN_SIDE}, - {"BTN_EXTRA", BTN_EXTRA}, - {"BTN_FORWARD", BTN_FORWARD}, - {"BTN_BACK", BTN_BACK}, - {"BTN_TASK", BTN_TASK}, - }; - int button = 0; - for (size_t i = 0; i < ALEN(map); i++) { - if (strcmp(key, map[i].name) == 0) { - button = map[i].code; + for (size_t i = 0; i < ALEN(button_map); i++) { + if (strcmp(key, button_map[i].name) == 0) { + button = button_map[i].code; break; } } From a15c6025ecc301cc3fb1f0c2fb42d7b86f47b5d8 Mon Sep 17 00:00:00 2001 From: "feeptr@codeberg.org" Date: Sat, 4 Dec 2021 01:33:25 +0000 Subject: [PATCH 7/8] config: improve error reporting when selection-override-modifiers conflict with mouse bindings --- config.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/config.c b/config.c index 1903e83c..92a0fb53 100644 --- a/config.c +++ b/config.c @@ -1970,6 +1970,17 @@ static const struct { {"BTN_TASK", BTN_TASK}, }; +static const char* +mouse_event_code_get_name(int code) +{ + for (size_t i = 0; i < ALEN(button_map); i++) { + if (code == button_map[i].code) + return button_map[i].name; + } + + return NULL; +} + static bool value_to_mouse_combos(struct context *ctx, struct key_combo_list *key_combos) { @@ -2093,21 +2104,57 @@ modifiers_to_str(const struct config_key_modifiers *mods) return ret; } +static char * +mouse_combo_to_str(const struct key_combo *combo) +{ + char *combo_modifiers_str = modifiers_to_str(&combo->modifiers); + const char *combo_button_str = mouse_event_code_get_name(combo->m.button); + xassert(combo_button_str != NULL); + + char *ret; + if (combo->m.count == 1) + ret = xasprintf("%s+%s", combo_modifiers_str, combo_button_str); + else + ret = xasprintf("%s+%s-%d", + combo_modifiers_str, + combo_button_str, + combo->m.count); + + free (combo_modifiers_str); + return ret; +} + static bool selection_override_interferes_with_mouse_binding(struct context *ctx, - const struct key_combo_list *key_combos) + int action, + const struct key_combo_list *key_combos, + bool blame_modifiers) { struct config *conf = ctx->conf; - const struct config_key_modifiers *override_mods = &conf->mouse.selection_override_modifiers; + if (action == BIND_ACTION_NONE) + return false; + + 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); + char *combo_str = mouse_combo_to_str(combo); + if (blame_modifiers) { + LOG_CONTEXTUAL_ERR( + "modifiers conflict with existing binding %s=%s", + binding_action_map[action], + combo_str); + } else { + LOG_CONTEXTUAL_ERR( + "binding conflicts with selection override modifiers (%s)", + modifiers_str); + } free (modifiers_str); + free (combo_str); return false; } } @@ -2182,7 +2229,7 @@ parse_section_mouse_bindings(struct context *ctx) .combos = &combo, }; - if (selection_override_interferes_with_mouse_binding(ctx, &key_combos)) { + if (selection_override_interferes_with_mouse_binding(ctx, binding->action, &key_combos, true)) { return false; } } @@ -2225,7 +2272,7 @@ 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) || - selection_override_interferes_with_mouse_binding(ctx, &key_combos)) + selection_override_interferes_with_mouse_binding(ctx, action, &key_combos, false)) { free_argv(&pipe_argv); free_key_combo_list(&key_combos); From a6c543a32c51226282e90f47ae9ac13f37430009 Mon Sep 17 00:00:00 2001 From: "feeptr@codeberg.org" Date: Sat, 4 Dec 2021 16:22:33 +0000 Subject: [PATCH 8/8] improve documentation for [mouse-bindings].selection-override-modifiers --- doc/foot.ini.5.scd | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/doc/foot.ini.5.scd b/doc/foot.ini.5.scd index 5f55dc45..e1922634 100644 --- a/doc/foot.ini.5.scd +++ b/doc/foot.ini.5.scd @@ -865,13 +865,6 @@ of the modifiers *must* be valid XKB key names, and the button name *must* be a valid libinput name. You can find the button names using *libinput debug-events*. -The modifiers set in *[mouse-bindings].selection-override-modifiers* -(by default, *Shift*) cannot be used as modifiers in mouse bindings, -and are instead used to enable selecting text with the mouse -irrespective of whether a client application currently has the mouse -grabbed. Because the order of bindings is significant, it's best to -set this prior to any other mouse bindings that might use *Shift*. - The trailing *COUNT* is optional and specifies the click count required to trigger the binding. The default if *COUNT* is omitted is _1_. @@ -882,7 +875,19 @@ say you want to bind *BTN\_MIDDLE* to *fullscreen*. Since need to unmap the default binding. This can be done by setting _action=none_; e.g. *primary-paste=none*. -All actions listed under *key-bindings* can be used here as well. +*selection-override-modifiers* + The modifiers set in this set (which may be set to any combination + of modifiers, e.g. _mod1+mod2+mod3_, as well as _none_) are used + to enable selecting text with the mouse irrespective of whether a + client application currently has the mouse grabbed. + These modifiers cannot be used as modifiers in mouse bindings. + Because the order of bindings is significant, it is best to set + this prior to any other mouse bindings that might use modifiers in + the default set. + Default: _Shift_ + +The actions to which mouse combos can be bound are listed below. All +actions listed under *key-bindings* can be used here as well. *select-begin* Begin an interactive selection. The selection is finalized, and