summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Ashworth <bosrsf04@gmail.com>2019-07-26 12:02:18 -0400
committerSimon Ser <contact@emersion.fr>2019-08-01 18:54:58 +0300
commit8ee054b1b95b7466c0dd89bfc9026f4083fb0016 (patch)
treebce2d4bfba93e6889c1aa57085297e4a997af2d8
parent14562fdbeed99e8d608de3dc46f1e04407e9258f (diff)
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.
-rw-r--r--include/sway/config.h1
-rw-r--r--sway/commands/bind.c33
-rw-r--r--sway/input/keyboard.c42
-rw-r--r--sway/sway.5.scd15
4 files changed, 76 insertions, 15 deletions
diff --git a/include/sway/config.h b/include/sway/config.h
index f1426453a..c65d93533 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -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;
};
diff --git a/sway/commands/bind.c b/sway/commands/bind.c
index 767c2fee1..5ec899826 100644
--- a/sway/commands/bind.c
+++ b/sway/commands/bind.c
@@ -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) {
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c
index aecabbf43..680d1f693 100644
--- a/sway/input/keyboard.c
+++ b/sway/input/keyboard.c
@@ -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
diff --git a/sway/sway.5.scd b/sway/sway.5.scd
index ac80de3c9..3e445e0e2 100644
--- a/sway/sway.5.scd
+++ b/sway/sway.5.scd
@@ -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>