diff --git a/sway/commands/bind.c b/sway/commands/bind.c index ea8179bb..d43c87fb 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c @@ -49,6 +49,10 @@ static bool binding_switch_compare(struct sway_switch_binding *binding_a, if (binding_a->state != binding_b->state) { return false; } + if ((binding_a->flags & BINDING_LOCKED) != + (binding_b->flags & BINDING_LOCKED)) { + return false; + } return true; } @@ -68,7 +72,7 @@ static bool binding_key_compare(struct sway_binding *binding_a, } uint32_t conflict_generating_flags = BINDING_RELEASE | BINDING_BORDER - | BINDING_CONTENTS | BINDING_TITLEBAR; + | BINDING_CONTENTS | BINDING_TITLEBAR | BINDING_LOCKED; if ((binding_a->flags & conflict_generating_flags) != (binding_b->flags & conflict_generating_flags)) { return false; diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 78e8fa0c..dcfaa4fa 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -146,7 +146,7 @@ static void get_active_binding(const struct sway_shortcut_state *state, uint32_t modifiers, bool release, bool locked, const char *input) { for (int i = 0; i < bindings->length; ++i) { struct sway_binding *binding = bindings->items[i]; - bool binding_locked = binding->flags & BINDING_LOCKED; + bool binding_locked = (binding->flags & BINDING_LOCKED) != 0; bool binding_release = binding->flags & BINDING_RELEASE; if (modifiers ^ binding->modifiers || @@ -178,18 +178,37 @@ static void get_active_binding(const struct sway_shortcut_state *state, continue; } - if (*current_binding && *current_binding != binding && - strcmp((*current_binding)->input, binding->input) == 0) { - sway_log(SWAY_DEBUG, "encountered duplicate bindings %d and %d", - (*current_binding)->order, binding->order); - } else if (!*current_binding || - strcmp((*current_binding)->input, "*") == 0) { - *current_binding = binding; - - if (strcmp((*current_binding)->input, input) == 0) { - // If a binding is found for the exact input, quit searching - return; + if (*current_binding) { + if (*current_binding == binding) { + continue; } + + bool current_locked = + ((*current_binding)->flags & BINDING_LOCKED) != 0; + bool current_input = strcmp((*current_binding)->input, input) == 0; + bool binding_input = strcmp(binding->input, input) == 0; + + if (current_input == binding_input + && current_locked == binding_locked) { + sway_log(SWAY_DEBUG, + "Encountered conflicting bindings %d and %d", + (*current_binding)->order, binding->order); + continue; + } + + if (current_input && !binding_input) { + continue; // Prefer the correct input + } + + if (current_input == binding_input && current_locked == locked) { + continue; // Prefer correct lock state for matching inputs + } + } + + *current_binding = binding; + if (strcmp((*current_binding)->input, input) == 0 && + (((*current_binding)->flags & BINDING_LOCKED) == locked)) { + return; // If a perfect match is found, quit searching } } } diff --git a/sway/input/switch.c b/sway/input/switch.c index a8769713..d825c5c3 100644 --- a/sway/input/switch.c +++ b/sway/input/switch.c @@ -38,6 +38,7 @@ static void handle_switch_toggle(struct wl_listener *listener, void *data) { sway_log(SWAY_DEBUG, "%s: type %d state %d", device_identifier, type, state); list_t *bindings = config->current_mode->switch_bindings; + struct sway_switch_binding *matched_binding = NULL; for (int i = 0; i < bindings->length; ++i) { struct sway_switch_binding *binding = bindings->items[i]; if (binding->type != type) { @@ -52,10 +53,19 @@ static void handle_switch_toggle(struct wl_listener *listener, void *data) { continue; } - struct sway_binding *dummy_binding = calloc(1, sizeof(struct sway_binding)); + matched_binding = binding; + + if (binding_locked == input_inhibited) { + break; + } + } + + if (matched_binding) { + struct sway_binding *dummy_binding = + calloc(1, sizeof(struct sway_binding)); dummy_binding->type = BINDING_SWITCH; - dummy_binding->flags = binding->flags; - dummy_binding->command = binding->command; + dummy_binding->flags = matched_binding->flags; + dummy_binding->command = matched_binding->command; seat_execute_command(seat, dummy_binding); free(dummy_binding); diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 74963c9d..6d098d94 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -331,12 +331,17 @@ runtime. Binds _key combo_ to execute the sway command _command_ when pressed. You may use XKB key names here (*xev*(1) is a good tool for discovering these). With the flag _--release_, the command is executed when the key combo is - released. Unless the flag _--locked_ is set, the command will not be run - when a screen locking program is active. If _input-device_ is given, the - binding will only be executed for that input device and will be executed - instead of any binding that is generic to all devices. By default, if you - overwrite a binding, swaynag will give you a warning. To silence this, use - the _--no-warn_ flag. + released. If _input-device_ is given, the binding will only be executed for + that input device and will be executed instead of any binding that is + generic to all devices. By default, if you overwrite a binding, swaynag + will give you a warning. To silence this, use the _--no-warn_ flag. + + Unless the flag _--locked_ is set, the command will not be run when a + screen locking program is active. If there is a matching binding with + and without _--locked_, the one with will be preferred when locked and the + one without will be preferred when unlocked. If there are matching bindings + and one has both _--input-device_ and _--locked_ and the other has neither, + the former will be preferred even when unlocked. Bindings to keysyms are layout-dependent. This can be changed with the _--to-code_ flag. In this case, the keysyms will be translated into the @@ -380,10 +385,13 @@ runtime. respectively. _toggle_ is also supported to run a command both when the switch is toggled on or off. - Unless the flag _--locked_ is set, the command will not be run - when a screen locking program is active. By default, if you - overwrite a binding, swaynag will give you a warning. To silence this, use - the _--no-warn_ flag. + Unless the flag _--locked_ is set, the command will not be run when a + screen locking program is active. If there is a matching binding with + and without _--locked_, the one with will be preferred when locked and the + one without will be preferred when unlocked. + + By default, if you overwrite a binding, swaynag will give you a warning. To + silence this, use the _--no-warn_ flag. Example: ```