diff options
Diffstat (limited to 'sway/commands/bind.c')
-rw-r--r-- | sway/commands/bind.c | 139 |
1 files changed, 107 insertions, 32 deletions
diff --git a/sway/commands/bind.c b/sway/commands/bind.c index d9ea37b7..cbabb07b 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c @@ -1,9 +1,13 @@ +#ifdef __linux__ +#include <linux/input-event-codes.h> +#elif __FreeBSD__ +#include <dev/evdev/input-event-codes.h> +#endif #include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon-names.h> #include <strings.h> #include "sway/commands.h" #include "sway/config.h" -#include "sway/input_state.h" #include "list.h" #include "log.h" #include "stringop.h" @@ -11,13 +15,67 @@ int binding_order = 0; +void free_sway_binding(struct sway_binding *binding) { + if (!binding) { + return; + } + + if (binding->keys) { + free_flat_list(binding->keys); + } + free(binding->command); + free(binding); +} + +/** + * Returns true if the bindings have the same key and modifier combinations. + * Note that keyboard layout is not considered, so the bindings might actually + * not be equivalent on some layouts. + */ +bool binding_key_compare(struct sway_binding *binding_a, + struct sway_binding *binding_b) { + if (binding_a->release != binding_b->release) { + return false; + } + + if (binding_a->bindcode != binding_b->bindcode) { + return false; + } + + if (binding_a->modifiers ^ binding_b->modifiers) { + return false; + } + + if (binding_a->keys->length != binding_b->keys->length) { + return false; + } + + int keys_len = binding_a->keys->length; + for (int i = 0; i < keys_len; ++i) { + uint32_t key_a = *(uint32_t*)binding_a->keys->items[i]; + bool found = false; + for (int j = 0; j < keys_len; ++j) { + uint32_t key_b = *(uint32_t*)binding_b->keys->items[j]; + if (key_b == key_a) { + found = true; + break; + } + } + if (!found) { + return false; + } + } + + return true; +} + struct cmd_results *cmd_bindsym(int argc, char **argv) { struct cmd_results *error = NULL; if ((error = checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1))) { return error; } - struct sway_binding *binding = malloc(sizeof(struct sway_binding)); + struct sway_binding *binding = calloc(1, sizeof(struct sway_binding)); if (!binding) { return cmd_results_new(CMD_FAILURE, "bindsym", "Unable to allocate binding"); @@ -58,7 +116,7 @@ struct cmd_results *cmd_bindsym(int argc, char **argv) { // Check for mouse binding if (strncasecmp(split->items[i], "button", strlen("button")) == 0 && strlen(split->items[i]) == strlen("button0")) { - sym = ((char *)split->items[i])[strlen("button")] - '1' + M_LEFT_CLICK; + sym = ((char *)split->items[i])[strlen("button")] - '1' + BTN_LEFT; } if (!sym) { struct cmd_results *ret = cmd_results_new(CMD_INVALID, "bindsym", @@ -67,7 +125,7 @@ struct cmd_results *cmd_bindsym(int argc, char **argv) { free_flat_list(split); return ret; } - xkb_keysym_t *key = malloc(sizeof(xkb_keysym_t)); + xkb_keysym_t *key = calloc(1, sizeof(xkb_keysym_t)); if (!key) { free_sway_binding(binding); free_flat_list(split); @@ -78,20 +136,29 @@ struct cmd_results *cmd_bindsym(int argc, char **argv) { list_add(binding->keys, key); } free_flat_list(split); + binding->order = binding_order++; - struct sway_mode *mode = config->current_mode; - int i = list_seq_find(mode->bindings, sway_binding_cmp_keys, binding); - if (i > -1) { - sway_log(L_DEBUG, "bindsym - '%s' already exists, overwriting", argv[0]); - struct sway_binding *dup = mode->bindings->items[i]; - free_sway_binding(dup); - list_del(mode->bindings, i); + list_t *mode_bindings = config->current_mode->keysym_bindings; + + // overwrite the binding if it already exists + bool overwritten = false; + for (int i = 0; i < mode_bindings->length; ++i) { + struct sway_binding *config_binding = mode_bindings->items[i]; + if (binding_key_compare(binding, config_binding)) { + wlr_log(L_DEBUG, "overwriting old binding with command '%s'", + config_binding->command); + free_sway_binding(config_binding); + mode_bindings->items[i] = binding; + overwritten = true; + } } - binding->order = binding_order++; - list_add(mode->bindings, binding); - list_qsort(mode->bindings, sway_binding_cmp_qsort); - sway_log(L_DEBUG, "bindsym - Bound %s to command %s", argv[0], binding->command); + if (!overwritten) { + list_add(mode_bindings, binding); + } + + wlr_log(L_DEBUG, "bindsym - Bound %s to command %s", + argv[0], binding->command); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } @@ -101,7 +168,7 @@ struct cmd_results *cmd_bindcode(int argc, char **argv) { return error; } - struct sway_binding *binding = malloc(sizeof(struct sway_binding)); + struct sway_binding *binding = calloc(1, sizeof(struct sway_binding)); if (!binding) { return cmd_results_new(CMD_FAILURE, "bindsym", "Unable to allocate binding"); @@ -138,33 +205,41 @@ struct cmd_results *cmd_bindcode(int argc, char **argv) { // parse keycode xkb_keycode_t keycode = (int)strtol(split->items[i], NULL, 10); if (!xkb_keycode_is_legal_ext(keycode)) { - error = cmd_results_new(CMD_INVALID, "bindcode", "Invalid keycode '%s'", (char *)split->items[i]); + error = + cmd_results_new(CMD_INVALID, "bindcode", + "Invalid keycode '%s'", (char *)split->items[i]); free_sway_binding(binding); list_free(split); return error; } - xkb_keycode_t *key = malloc(sizeof(xkb_keycode_t)); + xkb_keycode_t *key = calloc(1, sizeof(xkb_keycode_t)); *key = keycode - 8; list_add(binding->keys, key); } free_flat_list(split); - struct sway_mode *mode = config->current_mode; - int i = list_seq_find(mode->bindings, sway_binding_cmp_keys, binding); - if (i > -1) { - struct sway_binding *dup = mode->bindings->items[i]; - if (dup->bindcode) { - sway_log(L_DEBUG, "bindcode - '%s' already exists, overwriting", argv[0]); - } else { - sway_log(L_DEBUG, "bindcode - '%s' already exists as bindsym, overwriting", argv[0]); + binding->order = binding_order++; + + list_t *mode_bindings = config->current_mode->keycode_bindings; + + // overwrite the binding if it already exists + bool overwritten = false; + for (int i = 0; i < mode_bindings->length; ++i) { + struct sway_binding *config_binding = mode_bindings->items[i]; + if (binding_key_compare(binding, config_binding)) { + wlr_log(L_DEBUG, "overwriting old binding with command '%s'", + config_binding->command); + free_sway_binding(config_binding); + mode_bindings->items[i] = binding; + overwritten = true; } - free_sway_binding(dup); - list_del(mode->bindings, i); } - binding->order = binding_order++; - list_add(mode->bindings, binding); - list_qsort(mode->bindings, sway_binding_cmp_qsort); - sway_log(L_DEBUG, "bindcode - Bound %s to command %s", argv[0], binding->command); + if (!overwritten) { + list_add(mode_bindings, binding); + } + + wlr_log(L_DEBUG, "bindcode - Bound %s to command %s", + argv[0], binding->command); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } |