mirror of
https://github.com/swaywm/sway.git
synced 2024-12-27 15:36:29 +01:00
bindsym/code: add group support
This adds support for specifying a binding for a specific group. Any binding without a group listed will be available in all groups. The priority for matching bindings is as follows: input device, group, and locked state. For full compatibility with i3, this also adds Mode_switch as an alias for Group2. Since i3 only supports this for backwards compatibility with older versions of i3, it is implemented here, but not documented.
This commit is contained in:
parent
14562fdbee
commit
8ee054b1b9
4 changed files with 76 additions and 15 deletions
|
@ -53,6 +53,7 @@ struct sway_binding {
|
|||
list_t *keys; // sorted in ascending order
|
||||
list_t *syms; // sorted in ascending order; NULL if BINDING_CODE is not set
|
||||
uint32_t modifiers;
|
||||
xkb_layout_index_t group;
|
||||
char *command;
|
||||
};
|
||||
|
||||
|
|
|
@ -78,6 +78,10 @@ static bool binding_key_compare(struct sway_binding *binding_a,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (binding_a->group != binding_b->group) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (binding_a->modifiers ^ binding_b->modifiers) {
|
||||
return false;
|
||||
}
|
||||
|
@ -337,6 +341,7 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
|
|||
}
|
||||
binding->input = strdup("*");
|
||||
binding->keys = create_list();
|
||||
binding->group = XKB_LAYOUT_INVALID;
|
||||
binding->modifiers = 0;
|
||||
binding->flags = 0;
|
||||
binding->type = bindcode ? BINDING_KEYCODE : BINDING_KEYSYM;
|
||||
|
@ -387,6 +392,34 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
|
|||
|
||||
list_t *split = split_string(argv[0], "+");
|
||||
for (int i = 0; i < split->length; ++i) {
|
||||
// Check for group
|
||||
if (strncmp(split->items[i], "Group", strlen("Group")) == 0) {
|
||||
if (binding->group != XKB_LAYOUT_INVALID) {
|
||||
free_sway_binding(binding);
|
||||
list_free_items_and_destroy(split);
|
||||
return cmd_results_new(CMD_FAILURE,
|
||||
"Only one group can be specified");
|
||||
}
|
||||
char *end;
|
||||
int group = strtol(split->items[i] + strlen("Group"), &end, 10);
|
||||
if (group < 1 || group > 4 || end[0] != '\0') {
|
||||
free_sway_binding(binding);
|
||||
list_free_items_and_destroy(split);
|
||||
return cmd_results_new(CMD_FAILURE, "Invalid group");
|
||||
}
|
||||
binding->group = group - 1;
|
||||
continue;
|
||||
} else if (strcmp(split->items[i], "Mode_switch") == 0) {
|
||||
// For full i3 compatibility, Mode_switch is an alias for Group2
|
||||
if (binding->group != XKB_LAYOUT_INVALID) {
|
||||
free_sway_binding(binding);
|
||||
list_free_items_and_destroy(split);
|
||||
return cmd_results_new(CMD_FAILURE,
|
||||
"Only one group can be specified");
|
||||
}
|
||||
binding->group = 1;
|
||||
}
|
||||
|
||||
// Check for a modifier key
|
||||
uint32_t mod;
|
||||
if ((mod = get_modifier_mask_by_name(split->items[i])) > 0) {
|
||||
|
|
|
@ -143,7 +143,8 @@ static void update_shortcut_state(struct sway_shortcut_state *state,
|
|||
*/
|
||||
static void get_active_binding(const struct sway_shortcut_state *state,
|
||||
list_t *bindings, struct sway_binding **current_binding,
|
||||
uint32_t modifiers, bool release, bool locked, const char *input) {
|
||||
uint32_t modifiers, bool release, bool locked, const char *input,
|
||||
xkb_layout_index_t group) {
|
||||
for (int i = 0; i < bindings->length; ++i) {
|
||||
struct sway_binding *binding = bindings->items[i];
|
||||
bool binding_locked = (binding->flags & BINDING_LOCKED) != 0;
|
||||
|
@ -152,6 +153,8 @@ static void get_active_binding(const struct sway_shortcut_state *state,
|
|||
if (modifiers ^ binding->modifiers ||
|
||||
release != binding_release ||
|
||||
locked > binding_locked ||
|
||||
(binding->group != XKB_LAYOUT_INVALID &&
|
||||
binding->group != group) ||
|
||||
(strcmp(binding->input, input) != 0 &&
|
||||
strcmp(binding->input, "*") != 0)) {
|
||||
continue;
|
||||
|
@ -186,10 +189,14 @@ static void get_active_binding(const struct sway_shortcut_state *state,
|
|||
bool current_locked =
|
||||
((*current_binding)->flags & BINDING_LOCKED) != 0;
|
||||
bool current_input = strcmp((*current_binding)->input, input) == 0;
|
||||
bool current_group_set =
|
||||
(*current_binding)->group != XKB_LAYOUT_INVALID;
|
||||
bool binding_input = strcmp(binding->input, input) == 0;
|
||||
bool binding_group_set = binding->group != XKB_LAYOUT_INVALID;
|
||||
|
||||
if (current_input == binding_input
|
||||
&& current_locked == binding_locked) {
|
||||
&& current_locked == binding_locked
|
||||
&& current_group_set == binding_group_set) {
|
||||
sway_log(SWAY_DEBUG,
|
||||
"Encountered conflicting bindings %d and %d",
|
||||
(*current_binding)->order, binding->order);
|
||||
|
@ -200,14 +207,22 @@ static void get_active_binding(const struct sway_shortcut_state *state,
|
|||
continue; // Prefer the correct input
|
||||
}
|
||||
|
||||
if (current_input == binding_input && current_locked == locked) {
|
||||
continue; // Prefer correct lock state for matching inputs
|
||||
if (current_input == binding_input &&
|
||||
(*current_binding)->group == group) {
|
||||
continue; // Prefer correct group for matching inputs
|
||||
}
|
||||
|
||||
if (current_input == binding_input &&
|
||||
current_group_set == binding_group_set &&
|
||||
current_locked == locked) {
|
||||
continue; // Prefer correct lock state for matching input+group
|
||||
}
|
||||
}
|
||||
|
||||
*current_binding = binding;
|
||||
if (strcmp((*current_binding)->input, input) == 0 &&
|
||||
(((*current_binding)->flags & BINDING_LOCKED) == locked)) {
|
||||
(((*current_binding)->flags & BINDING_LOCKED) == locked) &&
|
||||
(*current_binding)->group == group) {
|
||||
return; // If a perfect match is found, quit searching
|
||||
}
|
||||
}
|
||||
|
@ -344,13 +359,16 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) {
|
|||
struct sway_binding *binding_released = NULL;
|
||||
get_active_binding(&keyboard->state_keycodes,
|
||||
config->current_mode->keycode_bindings, &binding_released,
|
||||
code_modifiers, true, input_inhibited, device_identifier);
|
||||
code_modifiers, true, input_inhibited, device_identifier,
|
||||
keyboard->effective_layout);
|
||||
get_active_binding(&keyboard->state_keysyms_raw,
|
||||
config->current_mode->keysym_bindings, &binding_released,
|
||||
raw_modifiers, true, input_inhibited, device_identifier);
|
||||
raw_modifiers, true, input_inhibited, device_identifier,
|
||||
keyboard->effective_layout);
|
||||
get_active_binding(&keyboard->state_keysyms_translated,
|
||||
config->current_mode->keysym_bindings, &binding_released,
|
||||
translated_modifiers, true, input_inhibited, device_identifier);
|
||||
translated_modifiers, true, input_inhibited, device_identifier,
|
||||
keyboard->effective_layout);
|
||||
|
||||
// Execute stored release binding once no longer active
|
||||
if (keyboard->held_binding && binding_released != keyboard->held_binding &&
|
||||
|
@ -370,14 +388,16 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) {
|
|||
if (event->state == WLR_KEY_PRESSED) {
|
||||
get_active_binding(&keyboard->state_keycodes,
|
||||
config->current_mode->keycode_bindings, &binding,
|
||||
code_modifiers, false, input_inhibited, device_identifier);
|
||||
code_modifiers, false, input_inhibited, device_identifier,
|
||||
keyboard->effective_layout);
|
||||
get_active_binding(&keyboard->state_keysyms_raw,
|
||||
config->current_mode->keysym_bindings, &binding,
|
||||
raw_modifiers, false, input_inhibited, device_identifier);
|
||||
raw_modifiers, false, input_inhibited, device_identifier,
|
||||
keyboard->effective_layout);
|
||||
get_active_binding(&keyboard->state_keysyms_translated,
|
||||
config->current_mode->keysym_bindings, &binding,
|
||||
translated_modifiers, false, input_inhibited,
|
||||
device_identifier);
|
||||
device_identifier, keyboard->effective_layout);
|
||||
}
|
||||
|
||||
// Set up (or clear) keyboard repeat for a pressed binding. Since the
|
||||
|
|
|
@ -328,14 +328,17 @@ runtime.
|
|||
|
||||
for_window <criteria> move container to output <output>
|
||||
|
||||
*bindsym* [--whole-window] [--border] [--exclude-titlebar] [--release] [--locked] [--to-code] [--input-device=<device>] [--no-warn] <key combo> <command>
|
||||
*bindsym* [--whole-window] [--border] [--exclude-titlebar] [--release] [--locked] \
|
||||
[--to-code] [--input-device=<device>] [--no-warn] [Group<1-4>+]<key combo> \
|
||||
<command>
|
||||
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. 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.
|
||||
generic to all devices. If a group number is given, then the binding will
|
||||
only be available for that group. 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
|
||||
|
@ -356,6 +359,9 @@ runtime.
|
|||
6=scroll left, 7=scroll right, 8=back, 9=forward). For the latter option,
|
||||
you can find the event names using _libinput debug-events_.
|
||||
|
||||
The priority for matching bindings is as follows: input device, group,
|
||||
and locked state.
|
||||
|
||||
_--whole-window_, _--border_, and _--exclude-titlebar_ are mouse-only options
|
||||
which affect the region in which the mouse bindings can be triggered. By
|
||||
default, mouse bindings are only triggered when over the title bar. With the
|
||||
|
@ -375,7 +381,8 @@ runtime.
|
|||
bindsym Mod1+Shift+f exec firefox
|
||||
```
|
||||
|
||||
*bindcode* [--whole-window] [--border] [--exclude-titlebar] [--release] [--locked] [--input-device=<device>] [--no-warn] <code> <command>
|
||||
*bindcode* [--whole-window] [--border] [--exclude-titlebar] [--release] \
|
||||
[--locked] [--input-device=<device>] [--no-warn] [Group<1-4>+]<code> <command>
|
||||
is also available for binding with key/button codes instead of key/button names.
|
||||
|
||||
*bindswitch* [--locked] [--no-warn] [--reload] <switch>:<state> <command>
|
||||
|
|
Loading…
Reference in a new issue