diff --git a/include/sway/config.h b/include/sway/config.h index f660a269e..aac89622f 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -26,12 +26,14 @@ struct sway_variable { * A key binding and an associated command. */ struct sway_binding { - int order; - bool release; - bool locked; - bool bindcode; - list_t *keys; // sorted in ascending order + // key part + uint32_t *keys; // sorted in ascending order + size_t length; uint32_t modifiers; + bool release; + // value part + int order; + bool locked; char *command; }; @@ -467,14 +469,8 @@ int workspace_output_cmp_workspace(const void *a, const void *b); int sway_binding_cmp(const void *a, const void *b); -int sway_binding_cmp_qsort(const void *a, const void *b); - -int sway_binding_cmp_keys(const void *a, const void *b); - void free_sway_binding(struct sway_binding *sb); -struct sway_binding *sway_binding_dup(struct sway_binding *sb); - void load_swaybars(); void invoke_swaybar(struct bar_config *bar); diff --git a/sway/commands/bind.c b/sway/commands/bind.c index 83e9e432a..342960e59 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c @@ -20,53 +20,55 @@ void free_sway_binding(struct sway_binding *binding) { return; } - if (binding->keys) { - free_flat_list(binding->keys); - } + free(binding->keys); free(binding->command); free(binding); } +static void *replace_binding(void *old_item, void *new_item) { + struct sway_binding *old_binding = (struct sway_binding *)old_item; + struct sway_binding *new_binding = (struct sway_binding *)new_item; + wlr_log(WLR_DEBUG, "overwriting old binding command '%s' with command '%s'", + old_binding->command, new_binding->command); + free_sway_binding(old_binding); + return new_item; +} + /** - * 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. + * Comparison function for bindings. + * + * Returns -1 if a < b, 0 if a == b, and 1 is a > b */ -static bool binding_key_compare(struct sway_binding *binding_a, - struct sway_binding *binding_b) { +int sway_binding_cmp(const void *a, const void *b) { + const struct sway_binding *binding_a = (const struct sway_binding *)a; + const struct sway_binding *binding_b = (const struct sway_binding *)b; + if (binding_a->release != binding_b->release) { - return false; + return binding_a->release < binding_b->release ? -1 : 1; } - if (binding_a->bindcode != binding_b->bindcode) { - return false; + if (binding_a->modifiers != binding_b->modifiers) { + return binding_a->modifiers < binding_b->modifiers ? -1 : 1; } - if (binding_a->modifiers ^ binding_b->modifiers) { - return false; - } - - if (binding_a->keys->length != binding_b->keys->length) { - return false; + if (binding_a->length != binding_b->length) { + return binding_a->length < binding_b->length ? -1 : 1; } // Keys are sorted - 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]; - uint32_t key_b = *(uint32_t *)binding_b->keys->items[i]; - if (key_a != key_b) { - return false; + for (size_t i = 0; i < binding_a->length; ++i) { + if (binding_a->keys[i] != binding_b->keys[i]) { + return binding_a->keys[i] < binding_b->keys[i] ? -1 : 1; } } - return true; + return 0; } -static int key_qsort_cmp(const void *keyp_a, const void *keyp_b) { - uint32_t key_a = **(uint32_t **)keyp_a; - uint32_t key_b = **(uint32_t **)keyp_b; - return (key_a < key_b) ? -1 : ((key_a > key_b) ? 1 : 0); +static int key_qsort_cmp(const void *pkey_a, const void *pkey_b) { + uint32_t a = *(uint32_t *)pkey_a; + uint32_t b = *(uint32_t *)pkey_b; + return (a < b) ? -1 : ((a > b) ? 1 : 0); } static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, @@ -83,11 +85,11 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, return cmd_results_new(CMD_FAILURE, bindtype, "Unable to allocate binding"); } - binding->keys = create_list(); + binding->keys = NULL; + binding->length = 0; binding->modifiers = 0; binding->release = false; binding->locked = false; - binding->bindcode = bindcode; // Handle --release and --locked while (argc > 0) { @@ -111,19 +113,31 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, binding->command = join_args(argv + 1, argc - 1); list_t *split = split_string(argv[0], "+"); + int nonmodifiers = 0; for (int i = 0; i < split->length; ++i) { // Check for a modifier key uint32_t mod; if ((mod = get_modifier_mask_by_name(split->items[i])) > 0) { binding->modifiers |= mod; continue; + } else { + nonmodifiers++; + } + } + binding->keys = (uint32_t *)calloc(nonmodifiers, sizeof (uint32_t)); + if (!binding->keys) { + return cmd_results_new(CMD_FAILURE, bindtype, + "Unable to allocate binding key list"); + } + for (int i = 0; i < split->length; ++i) { + // Check for a modifier key + if (get_modifier_mask_by_name(split->items[i]) > 0) { + continue; } - xkb_keycode_t keycode; - xkb_keysym_t keysym; if (bindcode) { // parse keycode - keycode = (int)strtol(split->items[i], NULL, 10); + xkb_keycode_t keycode = strtol(split->items[i], NULL, 10); if (!xkb_keycode_is_legal_ext(keycode)) { error = cmd_results_new(CMD_INVALID, "bindcode", @@ -132,9 +146,10 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, list_free(split); return error; } + binding->keys[binding->length++] = (uint32_t)keycode; } else { // Check for xkb key - keysym = xkb_keysym_from_name(split->items[i], + xkb_keysym_t keysym = xkb_keysym_from_name(split->items[i], XKB_KEYSYM_CASE_INSENSITIVE); // Check for mouse binding @@ -149,28 +164,14 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, free_flat_list(split); return ret; } + binding->keys[binding->length++] = (uint32_t)keysym; } - uint32_t *key = calloc(1, sizeof(uint32_t)); - if (!key) { - free_sway_binding(binding); - free_flat_list(split); - return cmd_results_new(CMD_FAILURE, bindtype, - "Unable to allocate binding"); - } - - if (bindcode) { - *key = (uint32_t)keycode; - } else { - *key = (uint32_t)keysym; - } - - list_add(binding->keys, key); } free_flat_list(split); binding->order = binding_order++; // sort ascending - list_qsort(binding->keys, key_qsort_cmp); + qsort(binding->keys, binding->length, sizeof(uint32_t), key_qsort_cmp); list_t *mode_bindings; if (bindcode) { @@ -179,22 +180,7 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, 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(WLR_DEBUG, "overwriting old binding with command '%s'", - config_binding->command); - free_sway_binding(config_binding); - mode_bindings->items[i] = binding; - overwritten = true; - } - } - - if (!overwritten) { - list_add(mode_bindings, binding); - } + list_sortedset_insert(mode_bindings, binding, sway_binding_cmp, replace_binding); wlr_log(WLR_DEBUG, "%s - Bound %s to command %s", bindtype, argv[0], binding->command); diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index ede38519c..71e139c60 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -65,10 +65,10 @@ static void update_shortcut_state(struct sway_shortcut_state *state, bool last_key_was_a_modifier = raw_modifiers != state->last_raw_modifiers; state->last_raw_modifiers = raw_modifiers; - if (last_key_was_a_modifier && state->last_keycode) { - // Last pressed key before this one was a modifier - state_erase_key(state, state->last_keycode); - } + if (last_key_was_a_modifier && state->last_keycode) { + // Last pressed key before this one was a modifier + state_erase_key(state, state->last_keycode); + } if (event->state == WLR_KEY_PRESSED) { // Add current key to set; there may be duplicates @@ -86,36 +86,25 @@ 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) { - for (int i = 0; i < bindings->length; ++i) { - struct sway_binding *binding = bindings->items[i]; + struct sway_binding match_binding = { + (uint32_t *)state->pressed_keys, state->npressed, modifiers, release, + 0, false, NULL + }; - if (modifiers ^ binding->modifiers || - state->npressed != (size_t)binding->keys->length || - locked > binding->locked || - release != binding->release) { - continue; - } - - bool match = true; - for (size_t j = 0; j < state->npressed; j++) { - uint32_t key = *(uint32_t *)binding->keys->items[j]; - if (key != state->pressed_keys[j]) { - match = false; - break; - } - } - if (!match) { - continue; - } - - if (*current_binding && *current_binding != binding) { - wlr_log(WLR_DEBUG, "encountered duplicate bindings %d and %d", - (*current_binding)->order, binding->order); - } else { - *current_binding = binding; - } + int index = list_sortedset_find(bindings, sway_binding_cmp, &match_binding); + if (index < 0) { return; } + struct sway_binding *binding = bindings->items[index]; + if (locked > binding->locked) { + return; + } + if (*current_binding && *current_binding != binding) { + wlr_log(WLR_DEBUG, "encountered duplicate bindings %d and %d", + (*current_binding)->order, binding->order); + } else { + *current_binding = binding; + } } /**