aboutsummaryrefslogtreecommitdiffstats
path: root/sway/commands/bind.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/commands/bind.c')
-rw-r--r--sway/commands/bind.c169
1 files changed, 150 insertions, 19 deletions
diff --git a/sway/commands/bind.c b/sway/commands/bind.c
index dc7e0b19..e5fd4433 100644
--- a/sway/commands/bind.c
+++ b/sway/commands/bind.c
@@ -24,6 +24,7 @@ void free_sway_binding(struct sway_binding *binding) {
24 } 24 }
25 25
26 list_free_items_and_destroy(binding->keys); 26 list_free_items_and_destroy(binding->keys);
27 list_free_items_and_destroy(binding->syms);
27 free(binding->input); 28 free(binding->input);
28 free(binding->command); 29 free(binding->command);
29 free(binding); 30 free(binding);
@@ -249,31 +250,41 @@ static struct cmd_results *switch_binding_remove(
249 switchcombo); 250 switchcombo);
250} 251}
251 252
252static struct cmd_results *binding_add(struct sway_binding *binding, 253/**
253 list_t *mode_bindings, const char *bindtype, 254 * Insert or update the binding.
254 const char *keycombo, bool warn) { 255 * Return the binding which has been replaced or NULL.
255 // overwrite the binding if it already exists 256 */
256 bool overwritten = false; 257static struct sway_binding *binding_upsert(struct sway_binding *binding,
258 list_t *mode_bindings) {
257 for (int i = 0; i < mode_bindings->length; ++i) { 259 for (int i = 0; i < mode_bindings->length; ++i) {
258 struct sway_binding *config_binding = mode_bindings->items[i]; 260 struct sway_binding *config_binding = mode_bindings->items[i];
259 if (binding_key_compare(binding, config_binding)) { 261 if (binding_key_compare(binding, config_binding)) {
260 sway_log(SWAY_INFO, "Overwriting binding '%s' for device '%s' "
261 "to `%s` from `%s`", keycombo, binding->input,
262 binding->command, config_binding->command);
263 if (warn) {
264 config_add_swaynag_warning("Overwriting binding"
265 "'%s' for device '%s' to `%s` from `%s`",
266 keycombo, binding->input, binding->command,
267 config_binding->command);
268 }
269 free_sway_binding(config_binding);
270 mode_bindings->items[i] = binding; 262 mode_bindings->items[i] = binding;
271 overwritten = true; 263 return config_binding;
272 } 264 }
273 } 265 }
274 266
275 if (!overwritten) { 267 list_add(mode_bindings, binding);
276 list_add(mode_bindings, binding); 268 return NULL;
269}
270
271static struct cmd_results *binding_add(struct sway_binding *binding,
272 list_t *mode_bindings, const char *bindtype,
273 const char *keycombo, bool warn) {
274 struct sway_binding *config_binding = binding_upsert(binding, mode_bindings);
275
276 if (config_binding) {
277 sway_log(SWAY_INFO, "Overwriting binding '%s' for device '%s' "
278 "to `%s` from `%s`", keycombo, binding->input,
279 binding->command, config_binding->command);
280 if (warn) {
281 config_add_swaynag_warning("Overwriting binding"
282 "'%s' for device '%s' to `%s` from `%s`",
283 keycombo, binding->input, binding->command,
284 config_binding->command);
285 }
286 free_sway_binding(config_binding);
287 } else {
277 sway_log(SWAY_DEBUG, "%s - Bound %s to command `%s` for device '%s'", 288 sway_log(SWAY_DEBUG, "%s - Bound %s to command `%s` for device '%s'",
278 bindtype, keycombo, binding->command, binding->input); 289 bindtype, keycombo, binding->command, binding->input);
279 } 290 }
@@ -329,7 +340,6 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
329 bool exclude_titlebar = false; 340 bool exclude_titlebar = false;
330 bool warn = true; 341 bool warn = true;
331 342
332 // Handle --release and --locked
333 while (argc > 0) { 343 while (argc > 0) {
334 if (strcmp("--release", argv[0]) == 0) { 344 if (strcmp("--release", argv[0]) == 0) {
335 binding->flags |= BINDING_RELEASE; 345 binding->flags |= BINDING_RELEASE;
@@ -339,6 +349,10 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
339 binding->flags |= BINDING_BORDER | BINDING_CONTENTS | BINDING_TITLEBAR; 349 binding->flags |= BINDING_BORDER | BINDING_CONTENTS | BINDING_TITLEBAR;
340 } else if (strcmp("--border", argv[0]) == 0) { 350 } else if (strcmp("--border", argv[0]) == 0) {
341 binding->flags |= BINDING_BORDER; 351 binding->flags |= BINDING_BORDER;
352 } else if (strcmp("--to-code", argv[0]) == 0) {
353 if (!bindcode) {
354 binding->flags |= BINDING_CODE;
355 }
342 } else if (strcmp("--exclude-titlebar", argv[0]) == 0) { 356 } else if (strcmp("--exclude-titlebar", argv[0]) == 0) {
343 exclude_titlebar = true; 357 exclude_titlebar = true;
344 } else if (strncmp("--input-device=", argv[0], 358 } else if (strncmp("--input-device=", argv[0],
@@ -410,6 +424,12 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
410 // sort ascending 424 // sort ascending
411 list_qsort(binding->keys, key_qsort_cmp); 425 list_qsort(binding->keys, key_qsort_cmp);
412 426
427 // translate keysyms into keycodes
428 if (!translate_binding(binding)) {
429 sway_log(SWAY_INFO,
430 "Unable to translate bindsym into bindcode: %s", argv[0]);
431 }
432
413 list_t *mode_bindings; 433 list_t *mode_bindings;
414 if (binding->type == BINDING_KEYCODE) { 434 if (binding->type == BINDING_KEYCODE) {
415 mode_bindings = config->current_mode->keycode_bindings; 435 mode_bindings = config->current_mode->keycode_bindings;
@@ -566,3 +586,114 @@ void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding)
566 ipc_event_binding(binding); 586 ipc_event_binding(binding);
567 } 587 }
568} 588}
589
590/**
591 * The last found keycode associated with the keysym
592 * and the total count of matches.
593 */
594struct keycode_matches {
595 xkb_keysym_t keysym;
596 xkb_keycode_t keycode;
597 int count;
598};
599
600/**
601 * Iterate through keycodes in the keymap to find ones matching
602 * the specified keysym.
603 */
604static void find_keycode(struct xkb_keymap *keymap,
605 xkb_keycode_t keycode, void *data) {
606 xkb_keysym_t keysym = xkb_state_key_get_one_sym(
607 config->keysym_translation.xkb_state, keycode);
608
609 if (keysym == XKB_KEY_NoSymbol) {
610 return;
611 }
612
613 struct keycode_matches *matches = data;
614 if (matches->keysym == keysym) {
615 matches->keycode = keycode;
616 matches->count++;
617 }
618}
619
620/**
621 * Return the keycode for the specified keysym.
622 */
623static struct keycode_matches get_keycode_for_keysym(xkb_keysym_t keysym) {
624 struct keycode_matches matches = {
625 .keysym = keysym,
626 .keycode = XKB_KEYCODE_INVALID,
627 .count = 0,
628 };
629
630 xkb_keymap_key_for_each(config->keysym_translation.xkb_keymap,
631 find_keycode, &matches);
632 return matches;
633}
634
635bool translate_binding(struct sway_binding *binding) {
636 if ((binding->flags & BINDING_CODE) == 0) {
637 return true;
638 }
639
640 switch (binding->type) {
641 // a bindsym to translate
642 case BINDING_KEYSYM:
643 binding->syms = binding->keys;
644 binding->keys = create_list();
645 break;
646 // a bindsym to re-translate
647 case BINDING_KEYCODE:
648 list_free_items_and_destroy(binding->keys);
649 binding->keys = create_list();
650 break;
651 default:
652 return true;
653 }
654
655 for (int i = 0; i < binding->syms->length; ++i) {
656 xkb_keysym_t *keysym = binding->syms->items[i];
657 struct keycode_matches matches = get_keycode_for_keysym(*keysym);
658
659 if (matches.count != 1) {
660 sway_log(SWAY_INFO, "Unable to convert keysym %d into"
661 " a single keycode (found %d matches)",
662 *keysym, matches.count);
663 goto error;
664 }
665
666 xkb_keycode_t *keycode = malloc(sizeof(xkb_keycode_t));
667 if (!keycode) {
668 sway_log(SWAY_ERROR, "Unable to allocate memory for a keycode");
669 goto error;
670 }
671
672 *keycode = matches.keycode;
673 list_add(binding->keys, keycode);
674 }
675
676 list_qsort(binding->keys, key_qsort_cmp);
677 binding->type = BINDING_KEYCODE;
678 return true;
679
680error:
681 list_free_items_and_destroy(binding->keys);
682 binding->type = BINDING_KEYSYM;
683 binding->keys = binding->syms;
684 binding->syms = NULL;
685 return false;
686}
687
688void binding_add_translated(struct sway_binding *binding,
689 list_t *mode_bindings) {
690 struct sway_binding *config_binding =
691 binding_upsert(binding, mode_bindings);
692
693 if (config_binding) {
694 sway_log(SWAY_INFO, "Overwriting binding for device '%s' "
695 "to `%s` from `%s`", binding->input,
696 binding->command, config_binding->command);
697 free_sway_binding(config_binding);
698 }
699}