aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Brian Ashworth <bosrsf04@gmail.com>2019-07-26 12:02:18 -0400
committerLibravatar Simon Ser <contact@emersion.fr>2019-08-01 18:54:58 +0300
commit8ee054b1b95b7466c0dd89bfc9026f4083fb0016 (patch)
treebce2d4bfba93e6889c1aa57085297e4a997af2d8
parentinput/keyboard: don't reset layout for same keymap (diff)
downloadsway-8ee054b1b95b7466c0dd89bfc9026f4083fb0016.tar.gz
sway-8ee054b1b95b7466c0dd89bfc9026f4083fb0016.tar.zst
sway-8ee054b1b95b7466c0dd89bfc9026f4083fb0016.zip
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 f1426453..c65d9353 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -53,6 +53,7 @@ struct sway_binding {
53 list_t *keys; // sorted in ascending order 53 list_t *keys; // sorted in ascending order
54 list_t *syms; // sorted in ascending order; NULL if BINDING_CODE is not set 54 list_t *syms; // sorted in ascending order; NULL if BINDING_CODE is not set
55 uint32_t modifiers; 55 uint32_t modifiers;
56 xkb_layout_index_t group;
56 char *command; 57 char *command;
57}; 58};
58 59
diff --git a/sway/commands/bind.c b/sway/commands/bind.c
index 767c2fee..5ec89982 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,
78 return false; 78 return false;
79 } 79 }
80 80
81 if (binding_a->group != binding_b->group) {
82 return false;
83 }
84
81 if (binding_a->modifiers ^ binding_b->modifiers) { 85 if (binding_a->modifiers ^ binding_b->modifiers) {
82 return false; 86 return false;
83 } 87 }
@@ -337,6 +341,7 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
337 } 341 }
338 binding->input = strdup("*"); 342 binding->input = strdup("*");
339 binding->keys = create_list(); 343 binding->keys = create_list();
344 binding->group = XKB_LAYOUT_INVALID;
340 binding->modifiers = 0; 345 binding->modifiers = 0;
341 binding->flags = 0; 346 binding->flags = 0;
342 binding->type = bindcode ? BINDING_KEYCODE : BINDING_KEYSYM; 347 binding->type = bindcode ? BINDING_KEYCODE : BINDING_KEYSYM;
@@ -387,6 +392,34 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
387 392
388 list_t *split = split_string(argv[0], "+"); 393 list_t *split = split_string(argv[0], "+");
389 for (int i = 0; i < split->length; ++i) { 394 for (int i = 0; i < split->length; ++i) {
395 // Check for group
396 if (strncmp(split->items[i], "Group", strlen("Group")) == 0) {
397 if (binding->group != XKB_LAYOUT_INVALID) {
398 free_sway_binding(binding);
399 list_free_items_and_destroy(split);
400 return cmd_results_new(CMD_FAILURE,
401 "Only one group can be specified");
402 }
403 char *end;
404 int group = strtol(split->items[i] + strlen("Group"), &end, 10);
405 if (group < 1 || group > 4 || end[0] != '\0') {
406 free_sway_binding(binding);
407 list_free_items_and_destroy(split);
408 return cmd_results_new(CMD_FAILURE, "Invalid group");
409 }
410 binding->group = group - 1;
411 continue;
412 } else if (strcmp(split->items[i], "Mode_switch") == 0) {
413 // For full i3 compatibility, Mode_switch is an alias for Group2
414 if (binding->group != XKB_LAYOUT_INVALID) {
415 free_sway_binding(binding);
416 list_free_items_and_destroy(split);
417 return cmd_results_new(CMD_FAILURE,
418 "Only one group can be specified");
419 }
420 binding->group = 1;
421 }
422
390 // Check for a modifier key 423 // Check for a modifier key
391 uint32_t mod; 424 uint32_t mod;
392 if ((mod = get_modifier_mask_by_name(split->items[i])) > 0) { 425 if ((mod = get_modifier_mask_by_name(split->items[i])) > 0) {
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c
index aecabbf4..680d1f69 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,
143 */ 143 */
144static void get_active_binding(const struct sway_shortcut_state *state, 144static void get_active_binding(const struct sway_shortcut_state *state,
145 list_t *bindings, struct sway_binding **current_binding, 145 list_t *bindings, struct sway_binding **current_binding,
146 uint32_t modifiers, bool release, bool locked, const char *input) { 146 uint32_t modifiers, bool release, bool locked, const char *input,
147 xkb_layout_index_t group) {
147 for (int i = 0; i < bindings->length; ++i) { 148 for (int i = 0; i < bindings->length; ++i) {
148 struct sway_binding *binding = bindings->items[i]; 149 struct sway_binding *binding = bindings->items[i];
149 bool binding_locked = (binding->flags & BINDING_LOCKED) != 0; 150 bool binding_locked = (binding->flags & BINDING_LOCKED) != 0;
@@ -152,6 +153,8 @@ static void get_active_binding(const struct sway_shortcut_state *state,
152 if (modifiers ^ binding->modifiers || 153 if (modifiers ^ binding->modifiers ||
153 release != binding_release || 154 release != binding_release ||
154 locked > binding_locked || 155 locked > binding_locked ||
156 (binding->group != XKB_LAYOUT_INVALID &&
157 binding->group != group) ||
155 (strcmp(binding->input, input) != 0 && 158 (strcmp(binding->input, input) != 0 &&
156 strcmp(binding->input, "*") != 0)) { 159 strcmp(binding->input, "*") != 0)) {
157 continue; 160 continue;
@@ -186,10 +189,14 @@ static void get_active_binding(const struct sway_shortcut_state *state,
186 bool current_locked = 189 bool current_locked =
187 ((*current_binding)->flags & BINDING_LOCKED) != 0; 190 ((*current_binding)->flags & BINDING_LOCKED) != 0;
188 bool current_input = strcmp((*current_binding)->input, input) == 0; 191 bool current_input = strcmp((*current_binding)->input, input) == 0;
192 bool current_group_set =
193 (*current_binding)->group != XKB_LAYOUT_INVALID;
189 bool binding_input = strcmp(binding->input, input) == 0; 194 bool binding_input = strcmp(binding->input, input) == 0;
195 bool binding_group_set = binding->group != XKB_LAYOUT_INVALID;
190 196
191 if (current_input == binding_input 197 if (current_input == binding_input
192 && current_locked == binding_locked) { 198 && current_locked == binding_locked
199 && current_group_set == binding_group_set) {
193 sway_log(SWAY_DEBUG, 200 sway_log(SWAY_DEBUG,
194 "Encountered conflicting bindings %d and %d", 201 "Encountered conflicting bindings %d and %d",
195 (*current_binding)->order, binding->order); 202 (*current_binding)->order, binding->order);
@@ -200,14 +207,22 @@ static void get_active_binding(const struct sway_shortcut_state *state,
200 continue; // Prefer the correct input 207 continue; // Prefer the correct input
201 } 208 }
202 209
203 if (current_input == binding_input && current_locked == locked) { 210 if (current_input == binding_input &&
204 continue; // Prefer correct lock state for matching inputs 211 (*current_binding)->group == group) {
212 continue; // Prefer correct group for matching inputs
213 }
214
215 if (current_input == binding_input &&
216 current_group_set == binding_group_set &&
217 current_locked == locked) {
218 continue; // Prefer correct lock state for matching input+group
205 } 219 }
206 } 220 }
207 221
208 *current_binding = binding; 222 *current_binding = binding;
209 if (strcmp((*current_binding)->input, input) == 0 && 223 if (strcmp((*current_binding)->input, input) == 0 &&
210 (((*current_binding)->flags & BINDING_LOCKED) == locked)) { 224 (((*current_binding)->flags & BINDING_LOCKED) == locked) &&
225 (*current_binding)->group == group) {
211 return; // If a perfect match is found, quit searching 226 return; // If a perfect match is found, quit searching
212 } 227 }
213 } 228 }
@@ -344,13 +359,16 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) {
344 struct sway_binding *binding_released = NULL; 359 struct sway_binding *binding_released = NULL;
345 get_active_binding(&keyboard->state_keycodes, 360 get_active_binding(&keyboard->state_keycodes,
346 config->current_mode->keycode_bindings, &binding_released, 361 config->current_mode->keycode_bindings, &binding_released,
347 code_modifiers, true, input_inhibited, device_identifier); 362 code_modifiers, true, input_inhibited, device_identifier,
363 keyboard->effective_layout);
348 get_active_binding(&keyboard->state_keysyms_raw, 364 get_active_binding(&keyboard->state_keysyms_raw,
349 config->current_mode->keysym_bindings, &binding_released, 365 config->current_mode->keysym_bindings, &binding_released,
350 raw_modifiers, true, input_inhibited, device_identifier); 366 raw_modifiers, true, input_inhibited, device_identifier,
367 keyboard->effective_layout);
351 get_active_binding(&keyboard->state_keysyms_translated, 368 get_active_binding(&keyboard->state_keysyms_translated,
352 config->current_mode->keysym_bindings, &binding_released, 369 config->current_mode->keysym_bindings, &binding_released,
353 translated_modifiers, true, input_inhibited, device_identifier); 370 translated_modifiers, true, input_inhibited, device_identifier,
371 keyboard->effective_layout);
354 372
355 // Execute stored release binding once no longer active 373 // Execute stored release binding once no longer active
356 if (keyboard->held_binding && binding_released != keyboard->held_binding && 374 if (keyboard->held_binding && binding_released != keyboard->held_binding &&
@@ -370,14 +388,16 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) {
370 if (event->state == WLR_KEY_PRESSED) { 388 if (event->state == WLR_KEY_PRESSED) {
371 get_active_binding(&keyboard->state_keycodes, 389 get_active_binding(&keyboard->state_keycodes,
372 config->current_mode->keycode_bindings, &binding, 390 config->current_mode->keycode_bindings, &binding,
373 code_modifiers, false, input_inhibited, device_identifier); 391 code_modifiers, false, input_inhibited, device_identifier,
392 keyboard->effective_layout);
374 get_active_binding(&keyboard->state_keysyms_raw, 393 get_active_binding(&keyboard->state_keysyms_raw,
375 config->current_mode->keysym_bindings, &binding, 394 config->current_mode->keysym_bindings, &binding,
376 raw_modifiers, false, input_inhibited, device_identifier); 395 raw_modifiers, false, input_inhibited, device_identifier,
396 keyboard->effective_layout);
377 get_active_binding(&keyboard->state_keysyms_translated, 397 get_active_binding(&keyboard->state_keysyms_translated,
378 config->current_mode->keysym_bindings, &binding, 398 config->current_mode->keysym_bindings, &binding,
379 translated_modifiers, false, input_inhibited, 399 translated_modifiers, false, input_inhibited,
380 device_identifier); 400 device_identifier, keyboard->effective_layout);
381 } 401 }
382 402
383 // Set up (or clear) keyboard repeat for a pressed binding. Since the 403 // 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 ac80de3c..3e445e0e 100644
--- a/sway/sway.5.scd
+++ b/sway/sway.5.scd
@@ -328,14 +328,17 @@ runtime.
328 328
329 for_window <criteria> move container to output <output> 329 for_window <criteria> move container to output <output>
330 330
331*bindsym* [--whole-window] [--border] [--exclude-titlebar] [--release] [--locked] [--to-code] [--input-device=<device>] [--no-warn] <key combo> <command> 331*bindsym* [--whole-window] [--border] [--exclude-titlebar] [--release] [--locked] \
332 [--to-code] [--input-device=<device>] [--no-warn] [Group<1-4>+]<key combo> \
333 <command>
332 Binds _key combo_ to execute the sway command _command_ when pressed. You 334 Binds _key combo_ to execute the sway command _command_ when pressed. You
333 may use XKB key names here (*xev*(1) is a good tool for discovering these). 335 may use XKB key names here (*xev*(1) is a good tool for discovering these).
334 With the flag _--release_, the command is executed when the key combo is 336 With the flag _--release_, the command is executed when the key combo is
335 released. If _input-device_ is given, the binding will only be executed for 337 released. If _input-device_ is given, the binding will only be executed for
336 that input device and will be executed instead of any binding that is 338 that input device and will be executed instead of any binding that is
337 generic to all devices. By default, if you overwrite a binding, swaynag 339 generic to all devices. If a group number is given, then the binding will
338 will give you a warning. To silence this, use the _--no-warn_ flag. 340 only be available for that group. By default, if you overwrite a binding,
341 swaynag will give you a warning. To silence this, use the _--no-warn_ flag.
339 342
340 Unless the flag _--locked_ is set, the command will not be run when a 343 Unless the flag _--locked_ is set, the command will not be run when a
341 screen locking program is active. If there is a matching binding with 344 screen locking program is active. If there is a matching binding with
@@ -356,6 +359,9 @@ runtime.
356 6=scroll left, 7=scroll right, 8=back, 9=forward). For the latter option, 359 6=scroll left, 7=scroll right, 8=back, 9=forward). For the latter option,
357 you can find the event names using _libinput debug-events_. 360 you can find the event names using _libinput debug-events_.
358 361
362 The priority for matching bindings is as follows: input device, group,
363 and locked state.
364
359 _--whole-window_, _--border_, and _--exclude-titlebar_ are mouse-only options 365 _--whole-window_, _--border_, and _--exclude-titlebar_ are mouse-only options
360 which affect the region in which the mouse bindings can be triggered. By 366 which affect the region in which the mouse bindings can be triggered. By
361 default, mouse bindings are only triggered when over the title bar. With the 367 default, mouse bindings are only triggered when over the title bar. With the
@@ -375,7 +381,8 @@ runtime.
375 bindsym Mod1+Shift+f exec firefox 381 bindsym Mod1+Shift+f exec firefox
376``` 382```
377 383
378 *bindcode* [--whole-window] [--border] [--exclude-titlebar] [--release] [--locked] [--input-device=<device>] [--no-warn] <code> <command> 384 *bindcode* [--whole-window] [--border] [--exclude-titlebar] [--release] \
385 [--locked] [--input-device=<device>] [--no-warn] [Group<1-4>+]<code> <command>
379 is also available for binding with key/button codes instead of key/button names. 386 is also available for binding with key/button codes instead of key/button names.
380 387
381*bindswitch* [--locked] [--no-warn] [--reload] <switch>:<state> <command> 388*bindswitch* [--locked] [--no-warn] [--reload] <switch>:<state> <command>