bindings: allow unlocked and locked bindings

This changes the behavior of bindings to make the `BINDING_LOCKED` flag
conflicting, which will allow for both unlocked and locked bindings.

If there are two matching bindings and one has `--locked` and the other
does not, the one with `--locked` will be preferred when locked and
the one without will be preferred when unlocked.

If there are two matching bindings and one has both a matching
`--input-device=<input>` and `--locked` and the other has neither, the
former will be preferred for both unlocked and locked.

This also refactors `get_active_binding` in `sway/input/keyboard.c`
to make it easier to read.
This commit is contained in:
Brian Ashworth 2019-05-30 03:30:08 -04:00 committed by Simon Ser
parent 2c6a10c4ba
commit 6afb392823
4 changed files with 67 additions and 26 deletions

View File

@ -49,6 +49,10 @@ static bool binding_switch_compare(struct sway_switch_binding *binding_a,
if (binding_a->state != binding_b->state) { if (binding_a->state != binding_b->state) {
return false; return false;
} }
if ((binding_a->flags & BINDING_LOCKED) !=
(binding_b->flags & BINDING_LOCKED)) {
return false;
}
return true; 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 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) != if ((binding_a->flags & conflict_generating_flags) !=
(binding_b->flags & conflict_generating_flags)) { (binding_b->flags & conflict_generating_flags)) {
return false; return false;

View File

@ -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) { uint32_t modifiers, bool release, bool locked, const char *input) {
for (int i = 0; i < bindings->length; ++i) { for (int i = 0; i < bindings->length; ++i) {
struct sway_binding *binding = bindings->items[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; bool binding_release = binding->flags & BINDING_RELEASE;
if (modifiers ^ binding->modifiers || if (modifiers ^ binding->modifiers ||
@ -178,18 +178,37 @@ static void get_active_binding(const struct sway_shortcut_state *state,
continue; continue;
} }
if (*current_binding && *current_binding != binding && if (*current_binding) {
strcmp((*current_binding)->input, binding->input) == 0) { if (*current_binding == binding) {
sway_log(SWAY_DEBUG, "encountered duplicate bindings %d and %d", continue;
(*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;
} }
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
} }
} }
} }

View File

@ -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); sway_log(SWAY_DEBUG, "%s: type %d state %d", device_identifier, type, state);
list_t *bindings = config->current_mode->switch_bindings; list_t *bindings = config->current_mode->switch_bindings;
struct sway_switch_binding *matched_binding = NULL;
for (int i = 0; i < bindings->length; ++i) { for (int i = 0; i < bindings->length; ++i) {
struct sway_switch_binding *binding = bindings->items[i]; struct sway_switch_binding *binding = bindings->items[i];
if (binding->type != type) { if (binding->type != type) {
@ -52,10 +53,19 @@ static void handle_switch_toggle(struct wl_listener *listener, void *data) {
continue; 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->type = BINDING_SWITCH;
dummy_binding->flags = binding->flags; dummy_binding->flags = matched_binding->flags;
dummy_binding->command = binding->command; dummy_binding->command = matched_binding->command;
seat_execute_command(seat, dummy_binding); seat_execute_command(seat, dummy_binding);
free(dummy_binding); free(dummy_binding);

View File

@ -331,12 +331,17 @@ runtime.
Binds _key combo_ to execute the sway command _command_ when pressed. You 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). 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 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 released. If _input-device_ is given, the binding will only be executed for
when a screen locking program is active. If _input-device_ is given, the that input device and will be executed instead of any binding that is
binding will only be executed for that input device and will be executed generic to all devices. By default, if you overwrite a binding, swaynag
instead of any binding that is generic to all devices. By default, if you will give you a warning. To silence this, use the _--no-warn_ flag.
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 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 _--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 respectively. _toggle_ is also supported to run a command both when the
switch is toggled on or off. switch is toggled on or off.
Unless the flag _--locked_ is set, the command will not be run Unless the flag _--locked_ is set, the command will not be run when a
when a screen locking program is active. By default, if you screen locking program is active. If there is a matching binding with
overwrite a binding, swaynag will give you a warning. To silence this, use and without _--locked_, the one with will be preferred when locked and the
the _--no-warn_ flag. 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: Example:
``` ```