aboutsummaryrefslogtreecommitdiff
path: root/sway/commands/bind.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/commands/bind.c')
-rw-r--r--sway/commands/bind.c139
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);
}