From f6a591b80a820ae5ab6886eb9ba43c90986f302b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 6 Dec 2021 21:04:38 +0100 Subject: [PATCH] config: unify key- and mouse bindings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With this patch, key- and mouse-bindings structs (the non-layout specific ones) are unified into a single struct. The logic that parses, and manages, the key- and mouse binding lists are almost identical. The *only* difference between a key- and a mouse binding is that key bindings have an XKB symbol, and mouse bindings a button and click-count. The new, unified, struct uses a union around these, and all functions that need to know which members to use/operate on now takes a ‘type’ parameter. --- config.c | 608 +++++++++++++++++++------------------------------------ config.h | 23 ++- input.c | 22 +- 3 files changed, 242 insertions(+), 411 deletions(-) diff --git a/config.c b/config.c index 75e5407f..cee4454c 100644 --- a/config.c +++ b/config.c @@ -1501,26 +1501,7 @@ free_key_binding_list(struct config_key_binding_list *bindings) bindings->count = 0; } -static void -free_mouse_binding(struct config_mouse_binding *binding) -{ - free_binding_pipe(&binding->pipe); -} - -static void NOINLINE -free_mouse_binding_list(struct config_mouse_binding_list *bindings) -{ - struct config_mouse_binding *binding = &bindings->arr[0]; - - for (size_t i = 0; i < bindings->count; i++, binding++) - free_mouse_binding(binding); - free(bindings->arr); - - bindings->arr = NULL; - bindings->count = 0; -} - -static bool +static bool NOINLINE parse_modifiers(struct context *ctx, const char *text, size_t len, struct config_key_modifiers *modifiers) { @@ -1588,8 +1569,8 @@ argv_compare(const struct argv *argv1, const struct argv *argv2) } static void NOINLINE -remove_action_from_key_bindings_list(struct config_key_binding_list *bindings, - int action, const struct argv *pipe_argv) +remove_from_key_bindings_list(struct config_key_binding_list *bindings, + int action, const struct argv *pipe_argv) { size_t remove_first_idx = 0; size_t remove_count = 0; @@ -1621,12 +1602,48 @@ remove_action_from_key_bindings_list(struct config_key_binding_list *bindings, bindings->count -= remove_count; } +static const struct { + const char *name; + int code; +} button_map[] = { + {"BTN_LEFT", BTN_LEFT}, + {"BTN_RIGHT", BTN_RIGHT}, + {"BTN_MIDDLE", BTN_MIDDLE}, + {"BTN_SIDE", BTN_SIDE}, + {"BTN_EXTRA", BTN_EXTRA}, + {"BTN_FORWARD", BTN_FORWARD}, + {"BTN_BACK", BTN_BACK}, + {"BTN_TASK", BTN_TASK}, +}; + +static int +mouse_button_name_to_code(const char *name) +{ + for (size_t i = 0; i < ALEN(button_map); i++) { + if (strcmp(button_map[i].name, name) == 0) + return button_map[i].code; + } + return -1; +} + +static const char* +mouse_button_code_to_name(int code) +{ + for (size_t i = 0; i < ALEN(button_map); i++) { + if (code == button_map[i].code) + return button_map[i].name; + } + + return NULL; +} + static bool NOINLINE value_to_key_combos(struct context *ctx, int action, struct argv *argv, - struct config_key_binding_list *bindings) + struct config_key_binding_list *bindings, + enum config_key_binding_type type) { if (strcasecmp(ctx->value, "none") == 0) { - remove_action_from_key_bindings_list(bindings, action, argv); + remove_from_key_bindings_list(bindings, action, argv); return true; } @@ -1663,20 +1680,57 @@ value_to_key_combos(struct context *ctx, int action, struct argv *argv, key = combo; new_combo->modifiers = (struct config_key_modifiers){0}; } else { + *key = '\0'; if (!parse_modifiers(ctx, combo, key - combo, &new_combo->modifiers)) goto err; key++; /* Skip past the '+' */ } - /* Translate key name to symbol */ - new_combo->sym = xkb_keysym_from_name(key, 0); - if (new_combo->sym == XKB_KEY_NoSymbol) { - LOG_CONTEXTUAL_ERR("not a valid XKB key name: %s", key); - goto err; + switch (type) { + case KEY_BINDING: + /* Translate key name to symbol */ + new_combo->k.sym = xkb_keysym_from_name(key, 0); + if (new_combo->k.sym == XKB_KEY_NoSymbol) { + LOG_CONTEXTUAL_ERR("not a valid XKB key name: %s", key); + goto err; + } + break; + + case MOUSE_BINDING: { + new_combo->m.count = 1; + + char *_count = strrchr(key, '-'); + if (_count != NULL) { + *_count = '\0'; + _count++; + + errno = 0; + char *end; + unsigned long value = strtoul(_count, &end, 10); + if (_count[0] == '\0' || *end != '\0' || errno != 0) { + if (errno != 0) + LOG_CONTEXTUAL_ERRNO("invalid click count: %s", _count); + else + LOG_CONTEXTUAL_ERR("invalid click count: %s", _count); + goto err; + } + + new_combo->m.count = value; + } + + new_combo->m.button = mouse_button_name_to_code(key); + if (new_combo->m.button < 0) { + LOG_CONTEXTUAL_ERR("invalid mouse button name: %s", key); + goto err; + } + + break; } + } + } - remove_action_from_key_bindings_list(bindings, action, argv); + remove_from_key_bindings_list(bindings, action, argv); bindings->arr = xrealloc( bindings->arr, @@ -1729,81 +1783,6 @@ modifiers_to_str(const struct config_key_modifiers *mods) return ret; } -static bool -resolve_key_binding_collisions(struct config *conf, const char *section_name, - const char *const action_map[], - struct config_key_binding_list *bindings) -{ - bool ret = true; - - for (size_t i = 1; i < bindings->count; i++) { - struct config_key_binding *binding1 = &bindings->arr[i]; - xassert(binding1->action != BIND_ACTION_NONE); - - for (ssize_t j = i - 1; j >= 0; j--) { - const struct config_key_binding *binding2 = &bindings->arr[j]; - xassert(binding2->action != BIND_ACTION_NONE); - - if (binding2->action == binding1->action) { - if (argv_compare(&binding1->pipe.argv, &binding2->pipe.argv)) - continue; - } - - const struct config_key_modifiers *mods1 = &binding1->modifiers; - const struct config_key_modifiers *mods2 = &binding2->modifiers; - - bool mods_equal = modifiers_equal(mods1, mods2); - bool sym_equal = binding1->sym == binding2->sym; - - if (!mods_equal || !sym_equal) - continue; - - bool has_pipe = binding2->pipe.argv.args != NULL; - - char *modifier_names = modifiers_to_str(mods2); - char sym_name[64]; - xkb_keysym_get_name(binding2->sym, sym_name, sizeof(sym_name)); - - LOG_AND_NOTIFY_ERR( - "%s:%d: [%s].%s: %s%s already mapped to '%s%s%s%s'", - binding1->path, binding1->lineno, section_name, - action_map[binding1->action], - modifier_names, sym_name, - action_map[binding2->action], - has_pipe ? " [" : "", - has_pipe ? binding2->pipe.argv.args[0] : "", - has_pipe ? "]" : ""); - - free(modifier_names); - ret = false; - - if (binding1->pipe.master_copy && i + 1 < bindings->count) { - struct config_key_binding *next = &bindings->arr[i + 1]; - - if (next->action == binding1->action && - argv_compare(&binding1->pipe.argv, &next->pipe.argv) == 0) - { - /* Transfer ownership to next binding */ - next->pipe.master_copy = true; - binding1->pipe.master_copy = false; - } - } - - free_key_binding(binding1); - - /* Remove the most recent binding */ - size_t move_count = bindings->count - (i + 1); - memmove(&bindings->arr[i], &bindings->arr[i + 1], - move_count * sizeof(bindings->arr[0])); - bindings->count--; - i--; - break; - } - } - - return ret; -} - /* * Parses a key binding value on the form * "[cmd-to-exec arg1 arg2] Mods+Key" @@ -1825,7 +1804,7 @@ resolve_key_binding_collisions(struct config *conf, const char *section_name, * - cmd: allocated string containing "cmd arg1 arg2...". Caller frees. * - argv: allocated array containing {"cmd", "arg1", "arg2", NULL}. Caller frees. */ -static ssize_t +static ssize_t NOINLINE pipe_argv_from_value(struct context *ctx, struct argv *argv) { argv->args = NULL; @@ -1878,7 +1857,9 @@ parse_key_binding_section(struct context *ctx, if (strcmp(ctx->key, action_map[action]) != 0) continue; - if (!value_to_key_combos(ctx, action, &pipe_argv, bindings)) { + if (!value_to_key_combos( + ctx, action, &pipe_argv, bindings, KEY_BINDING)) + { free_argv(&pipe_argv); return false; } @@ -1925,7 +1906,7 @@ UNITTEST xassert(parse_key_binding_section(&ctx, ALEN(map), map, &bindings)); xassert(bindings.count == 1); xassert(bindings.arr[0].action == TEST_ACTION_FOO); - xassert(bindings.arr[0].sym == XKB_KEY_Escape); + xassert(bindings.arr[0].k.sym == XKB_KEY_Escape); /* * ADD bar=Control+g Control+Shift+x @@ -1938,10 +1919,10 @@ UNITTEST xassert(bindings.count == 3); xassert(bindings.arr[0].action == TEST_ACTION_FOO); xassert(bindings.arr[1].action == TEST_ACTION_BAR); - xassert(bindings.arr[1].sym == XKB_KEY_g); + xassert(bindings.arr[1].k.sym == XKB_KEY_g); xassert(bindings.arr[1].modifiers.ctrl); xassert(bindings.arr[2].action == TEST_ACTION_BAR); - xassert(bindings.arr[2].sym == XKB_KEY_x); + xassert(bindings.arr[2].k.sym == XKB_KEY_x); xassert(bindings.arr[2].modifiers.ctrl && bindings.arr[2].modifiers.shift); /* @@ -1957,10 +1938,10 @@ UNITTEST xassert(bindings.arr[0].action == TEST_ACTION_BAR); xassert(bindings.arr[1].action == TEST_ACTION_BAR); xassert(bindings.arr[2].action == TEST_ACTION_FOO); - xassert(bindings.arr[2].sym == XKB_KEY_v); + xassert(bindings.arr[2].k.sym == XKB_KEY_v); xassert(bindings.arr[2].modifiers.alt); xassert(bindings.arr[3].action == TEST_ACTION_FOO); - xassert(bindings.arr[3].sym == XKB_KEY_q); + xassert(bindings.arr[3].k.sym == XKB_KEY_q); xassert(bindings.arr[3].modifiers.shift); /* @@ -2011,176 +1992,11 @@ parse_section_url_bindings(struct context *ctx) &ctx->conf->bindings.url); } -static const struct { - const char *name; - int code; -} button_map[] = { - {"BTN_LEFT", BTN_LEFT}, - {"BTN_RIGHT", BTN_RIGHT}, - {"BTN_MIDDLE", BTN_MIDDLE}, - {"BTN_SIDE", BTN_SIDE}, - {"BTN_EXTRA", BTN_EXTRA}, - {"BTN_FORWARD", BTN_FORWARD}, - {"BTN_BACK", BTN_BACK}, - {"BTN_TASK", BTN_TASK}, -}; - -static int -mouse_button_name_to_code(const char *name) -{ - for (size_t i = 0; i < ALEN(button_map); i++) { - if (strcmp(button_map[i].name, name) == 0) - return button_map[i].code; - } - return -1; -} - -static const char* -mouse_button_code_to_name(int code) -{ - for (size_t i = 0; i < ALEN(button_map); i++) { - if (code == button_map[i].code) - return button_map[i].name; - } - - return NULL; -} - -static void NOINLINE -remove_action_from_mouse_bindings_list( - struct config_mouse_binding_list *bindings, - int action, const struct argv *pipe_argv) -{ - size_t remove_first_idx = 0; - size_t remove_count = 0; - - for (size_t i = 0; i < bindings->count; i++) { - struct config_mouse_binding *binding = &bindings->arr[i]; - - if (binding->action != action) - continue; - - if (argv_compare(&binding->pipe.argv, pipe_argv) == 0) { - if (remove_count++ == 0) - remove_first_idx = i; - - xassert(remove_first_idx + remove_count - 1 == i); - free_mouse_binding(binding); - } - } - - if (remove_count == 0) - return; - - size_t move_count = bindings->count - (remove_first_idx + remove_count); - - memmove( - &bindings->arr[remove_first_idx], - &bindings->arr[remove_first_idx + remove_count], - move_count * sizeof(bindings->arr[0])); - bindings->count -= remove_count; -} - -static bool -value_to_mouse_combos(struct context *ctx, int action, struct argv *argv, - struct config_mouse_binding_list *bindings) -{ - if (strcasecmp(ctx->value, "none") == 0) { - remove_action_from_mouse_bindings_list(bindings, action, argv); - return true; - } - - /* Count number of combinations */ - size_t combo_count = 1; - for (const char *p = strchr(ctx->value, ' '); - p != NULL; - p = strchr(p + 1, ' ')) - { - combo_count++; - } - - struct config_mouse_binding new_combos[combo_count]; - - char *copy = xstrdup(ctx->value); - size_t idx = 0; - - for (char *tok_ctx = NULL, *combo = strtok_r(copy, " ", &tok_ctx); - combo != NULL; - combo = strtok_r(NULL, " ", &tok_ctx), - idx++) - { - struct config_mouse_binding *new_combo = &new_combos[idx]; - new_combo->action = action; - new_combo->pipe.master_copy = idx == 0; - new_combo->pipe.argv = *argv; - new_combo->path = ctx->path; - new_combo->lineno = ctx->lineno; - - char *key = strrchr(combo, '+'); - - if (key == NULL) { - /* No modifiers */ - key = combo; - new_combo->modifiers = (struct config_key_modifiers){0}; - } else { - *key = '\0'; - if (!parse_modifiers(ctx, combo, key - combo, &new_combo->modifiers)) - goto err; - key++; /* Skip past the '+' */ - } - - new_combo->count = 1; - { - char *_count = strrchr(key, '-'); - if (_count != NULL) { - *_count = '\0'; - _count++; - - errno = 0; - char *end; - unsigned long value = strtoul(_count, &end, 10); - if (_count[0] == '\0' || *end != '\0' || errno != 0) { - if (errno != 0) - LOG_CONTEXTUAL_ERRNO("invalid click count: %s", _count); - else - LOG_CONTEXTUAL_ERR("invalid click count: %s", _count); - goto err; - } - - new_combo->count = value; - } - } - - new_combo->button = mouse_button_name_to_code(key); - if (new_combo->button < 0) { - LOG_CONTEXTUAL_ERR("invalid mouse button name: %s", key); - goto err; - } - } - - remove_action_from_mouse_bindings_list(bindings, action, argv); - - bindings->arr = xrealloc( - bindings->arr, - (bindings->count + combo_count) * sizeof(bindings->arr[0])); - - memcpy(&bindings->arr[bindings->count], - new_combos, - combo_count * sizeof(bindings->arr[0])); - bindings->count += combo_count; - - free(copy); - return true; - -err: - free(copy); - return false; -} - -static bool -resolve_mouse_binding_collisions(struct config *conf, const char *section_name, - const char *const action_map[], - struct config_mouse_binding_list *bindings) +static bool NOINLINE +resolve_key_binding_collisions(struct config *conf, const char *section_name, + const char *const action_map[], + struct config_key_binding_list *bindings, + enum config_key_binding_type type) { bool ret = true; @@ -2188,23 +2004,27 @@ resolve_mouse_binding_collisions(struct config *conf, const char *section_name, enum {COLLISION_NONE, COLLISION_OVERRIDE, COLLISION_BINDING} collision_type = COLLISION_NONE; - const struct config_mouse_binding *collision_binding = NULL; + const struct config_key_binding *collision_binding = NULL; - struct config_mouse_binding *binding1 = &bindings->arr[i]; + struct config_key_binding *binding1 = &bindings->arr[i]; xassert(binding1->action != BIND_ACTION_NONE); const struct config_key_modifiers *mods1 = &binding1->modifiers; /* Does our modifiers collide with the selection override mods? */ - if (!modifiers_disjoint(mods1, &conf->mouse.selection_override_modifiers)) + if (type == MOUSE_BINDING && + !modifiers_disjoint( + mods1, &conf->mouse.selection_override_modifiers)) + { collision_type = COLLISION_OVERRIDE; + } /* Does our binding collide with another binding? */ for (ssize_t j = i - 1; collision_type == COLLISION_NONE && j >= 0; j--) { - const struct config_mouse_binding *binding2 = &bindings->arr[j]; + const struct config_key_binding *binding2 = &bindings->arr[j]; xassert(binding2->action != BIND_ACTION_NONE); if (binding2->action == binding1->action) { @@ -2215,10 +2035,20 @@ resolve_mouse_binding_collisions(struct config *conf, const char *section_name, const struct config_key_modifiers *mods2 = &binding2->modifiers; bool mods_equal = modifiers_equal(mods1, mods2); - bool button_equal = binding1->button == binding2->button; - bool count_equal = binding1->count == binding2->count; + bool sym_equal; - if (!mods_equal || !button_equal || !count_equal) + switch (type) { + case KEY_BINDING: + sym_equal = binding1->k.sym == binding2->k.sym; + break; + + case MOUSE_BINDING: + sym_equal = (binding1->m.button == binding2->m.button && + binding1->m.count == binding2->m.count); + break; + } + + if (!mods_equal || !sym_equal) continue; collision_binding = binding2; @@ -2228,13 +2058,25 @@ resolve_mouse_binding_collisions(struct config *conf, const char *section_name, if (collision_type != COLLISION_NONE) { char *modifier_names = modifiers_to_str(mods1); - const char *button_name = mouse_button_code_to_name(binding1->button); + char sym_name[64]; - char click_count[16]; - if (binding1->count > 1) - sprintf(click_count, "-%d", binding1->count); - else - click_count[0] = '\0'; + switch (type){ + case KEY_BINDING: + xkb_keysym_get_name(binding1->k.sym, sym_name, sizeof(sym_name)); + break; + + case MOUSE_BINDING: { + const char *button_name = + mouse_button_code_to_name(binding1->m.button); + + if (binding1->m.count > 1) { + snprintf(sym_name, sizeof(sym_name), "%s-%d", + button_name, binding1->m.count); + } else + strcpy(sym_name, button_name); + break; + } + } switch (collision_type) { case COLLISION_NONE: @@ -2243,10 +2085,10 @@ resolve_mouse_binding_collisions(struct config *conf, const char *section_name, case COLLISION_BINDING: { bool has_pipe = collision_binding->pipe.argv.args != NULL; LOG_AND_NOTIFY_ERR( - "%s:%d: [%s].%s: %s%s%s already mapped to '%s%s%s%s'", + "%s:%d: [%s].%s: %s%s already mapped to '%s%s%s%s'", binding1->path, binding1->lineno, section_name, action_map[binding1->action], - modifier_names, button_name, click_count, + modifier_names, sym_name, action_map[collision_binding->action], has_pipe ? " [" : "", has_pipe ? collision_binding->pipe.argv.args[0] : "", @@ -2262,20 +2104,20 @@ resolve_mouse_binding_collisions(struct config *conf, const char *section_name, override_names[strlen(override_names) - 1] = '\0'; LOG_AND_NOTIFY_ERR( - "%s:%d: [%s].%s: %s%s%s: " + "%s:%d: [%s].%s: %s%s: " "modifiers conflict with 'selection-override-modifiers=%s'", binding1->path, binding1->lineno, section_name, action_map[binding1->action], - modifier_names, button_name, click_count, - override_names); + modifier_names, sym_name, override_names); free(override_names); break; } } + free(modifier_names); if (binding1->pipe.master_copy && i + 1 < bindings->count) { - struct config_mouse_binding *next = &bindings->arr[i + 1]; + struct config_key_binding *next = &bindings->arr[i + 1]; if (next->action == binding1->action && argv_compare(&binding1->pipe.argv, &next->pipe.argv) == 0) @@ -2286,7 +2128,7 @@ resolve_mouse_binding_collisions(struct config *conf, const char *section_name, } } - free_mouse_binding(binding1); + free_key_binding(binding1); /* Remove the most recent binding */ size_t move_count = bindings->count - (i + 1); @@ -2336,8 +2178,8 @@ parse_section_mouse_bindings(struct context *ctx) if (strcmp(key, binding_action_map[action]) != 0) continue; - if (!value_to_mouse_combos( - ctx, action, &pipe_argv, &conf->bindings.mouse)) + if (!value_to_key_combos( + ctx, action, &pipe_argv, &conf->bindings.mouse, MOUSE_BINDING)) { free_argv(&pipe_argv); return false; @@ -2743,21 +2585,21 @@ static void add_default_key_bindings(struct config *conf) { static const struct config_key_binding bindings[] = { - {BIND_ACTION_SCROLLBACK_UP_PAGE, m_shift, XKB_KEY_Prior}, - {BIND_ACTION_SCROLLBACK_DOWN_PAGE, m_shift, XKB_KEY_Next}, - {BIND_ACTION_CLIPBOARD_COPY, m_ctrl_shift, XKB_KEY_c}, - {BIND_ACTION_CLIPBOARD_PASTE, m_ctrl_shift, XKB_KEY_v}, - {BIND_ACTION_PRIMARY_PASTE, m_shift, XKB_KEY_Insert}, - {BIND_ACTION_SEARCH_START, m_ctrl_shift, XKB_KEY_r}, - {BIND_ACTION_FONT_SIZE_UP, m_ctrl, XKB_KEY_plus}, - {BIND_ACTION_FONT_SIZE_UP, m_ctrl, XKB_KEY_equal}, - {BIND_ACTION_FONT_SIZE_UP, m_ctrl, XKB_KEY_KP_Add}, - {BIND_ACTION_FONT_SIZE_DOWN, m_ctrl, XKB_KEY_minus}, - {BIND_ACTION_FONT_SIZE_DOWN, m_ctrl, XKB_KEY_KP_Subtract}, - {BIND_ACTION_FONT_SIZE_RESET, m_ctrl, XKB_KEY_0}, - {BIND_ACTION_FONT_SIZE_RESET, m_ctrl, XKB_KEY_KP_0}, - {BIND_ACTION_SPAWN_TERMINAL, m_ctrl_shift, XKB_KEY_n}, - {BIND_ACTION_SHOW_URLS_LAUNCH, m_ctrl_shift, XKB_KEY_u}, + {BIND_ACTION_SCROLLBACK_UP_PAGE, m_shift, {{XKB_KEY_Prior}}}, + {BIND_ACTION_SCROLLBACK_DOWN_PAGE, m_shift, {{XKB_KEY_Next}}}, + {BIND_ACTION_CLIPBOARD_COPY, m_ctrl_shift, {{XKB_KEY_c}}}, + {BIND_ACTION_CLIPBOARD_PASTE, m_ctrl_shift, {{XKB_KEY_v}}}, + {BIND_ACTION_PRIMARY_PASTE, m_shift, {{XKB_KEY_Insert}}}, + {BIND_ACTION_SEARCH_START, m_ctrl_shift, {{XKB_KEY_r}}}, + {BIND_ACTION_FONT_SIZE_UP, m_ctrl, {{XKB_KEY_plus}}}, + {BIND_ACTION_FONT_SIZE_UP, m_ctrl, {{XKB_KEY_equal}}}, + {BIND_ACTION_FONT_SIZE_UP, m_ctrl, {{XKB_KEY_KP_Add}}}, + {BIND_ACTION_FONT_SIZE_DOWN, m_ctrl, {{XKB_KEY_minus}}}, + {BIND_ACTION_FONT_SIZE_DOWN, m_ctrl, {{XKB_KEY_KP_Subtract}}}, + {BIND_ACTION_FONT_SIZE_RESET, m_ctrl, {{XKB_KEY_0}}}, + {BIND_ACTION_FONT_SIZE_RESET, m_ctrl, {{XKB_KEY_KP_0}}}, + {BIND_ACTION_SPAWN_TERMINAL, m_ctrl_shift, {{XKB_KEY_n}}}, + {BIND_ACTION_SHOW_URLS_LAUNCH, m_ctrl_shift, {{XKB_KEY_u}}}, }; conf->bindings.key.count = ALEN(bindings); @@ -2770,35 +2612,35 @@ static void add_default_search_bindings(struct config *conf) { static const struct config_key_binding bindings[] = { - {BIND_ACTION_SEARCH_CANCEL, m_ctrl, XKB_KEY_c}, - {BIND_ACTION_SEARCH_CANCEL, m_ctrl, XKB_KEY_g}, - {BIND_ACTION_SEARCH_CANCEL, m_none, XKB_KEY_Escape}, - {BIND_ACTION_SEARCH_COMMIT, m_none, XKB_KEY_Return}, - {BIND_ACTION_SEARCH_FIND_PREV, m_ctrl, XKB_KEY_r}, - {BIND_ACTION_SEARCH_FIND_NEXT, m_ctrl, XKB_KEY_s}, - {BIND_ACTION_SEARCH_EDIT_LEFT, m_none, XKB_KEY_Left}, - {BIND_ACTION_SEARCH_EDIT_LEFT, m_ctrl, XKB_KEY_b}, - {BIND_ACTION_SEARCH_EDIT_LEFT_WORD, m_ctrl, XKB_KEY_Left}, - {BIND_ACTION_SEARCH_EDIT_LEFT_WORD, m_alt, XKB_KEY_b}, - {BIND_ACTION_SEARCH_EDIT_RIGHT, m_none, XKB_KEY_Right}, - {BIND_ACTION_SEARCH_EDIT_RIGHT, m_ctrl, XKB_KEY_f}, - {BIND_ACTION_SEARCH_EDIT_RIGHT_WORD, m_ctrl, XKB_KEY_Right}, - {BIND_ACTION_SEARCH_EDIT_RIGHT_WORD, m_alt, XKB_KEY_f}, - {BIND_ACTION_SEARCH_EDIT_HOME, m_none, XKB_KEY_Home}, - {BIND_ACTION_SEARCH_EDIT_HOME, m_ctrl, XKB_KEY_a}, - {BIND_ACTION_SEARCH_EDIT_END, m_none, XKB_KEY_End}, - {BIND_ACTION_SEARCH_EDIT_END, m_ctrl, XKB_KEY_e}, - {BIND_ACTION_SEARCH_DELETE_PREV, m_none, XKB_KEY_BackSpace}, - {BIND_ACTION_SEARCH_DELETE_PREV_WORD, m_ctrl, XKB_KEY_BackSpace}, - {BIND_ACTION_SEARCH_DELETE_PREV_WORD, m_alt, XKB_KEY_BackSpace}, - {BIND_ACTION_SEARCH_DELETE_NEXT, m_none, XKB_KEY_Delete}, - {BIND_ACTION_SEARCH_DELETE_NEXT_WORD, m_ctrl, XKB_KEY_Delete}, - {BIND_ACTION_SEARCH_DELETE_NEXT_WORD, m_alt, XKB_KEY_d}, - {BIND_ACTION_SEARCH_EXTEND_WORD, m_ctrl, XKB_KEY_w}, - {BIND_ACTION_SEARCH_EXTEND_WORD_WS, m_ctrl_shift, XKB_KEY_w}, - {BIND_ACTION_SEARCH_CLIPBOARD_PASTE, m_ctrl, XKB_KEY_v}, - {BIND_ACTION_SEARCH_CLIPBOARD_PASTE, m_ctrl, XKB_KEY_y}, - {BIND_ACTION_SEARCH_PRIMARY_PASTE, m_shift, XKB_KEY_Insert}, + {BIND_ACTION_SEARCH_CANCEL, m_ctrl, {{XKB_KEY_c}}}, + {BIND_ACTION_SEARCH_CANCEL, m_ctrl, {{XKB_KEY_g}}}, + {BIND_ACTION_SEARCH_CANCEL, m_none, {{XKB_KEY_Escape}}}, + {BIND_ACTION_SEARCH_COMMIT, m_none, {{XKB_KEY_Return}}}, + {BIND_ACTION_SEARCH_FIND_PREV, m_ctrl, {{XKB_KEY_r}}}, + {BIND_ACTION_SEARCH_FIND_NEXT, m_ctrl, {{XKB_KEY_s}}}, + {BIND_ACTION_SEARCH_EDIT_LEFT, m_none, {{XKB_KEY_Left}}}, + {BIND_ACTION_SEARCH_EDIT_LEFT, m_ctrl, {{XKB_KEY_b}}}, + {BIND_ACTION_SEARCH_EDIT_LEFT_WORD, m_ctrl, {{XKB_KEY_Left}}}, + {BIND_ACTION_SEARCH_EDIT_LEFT_WORD, m_alt, {{XKB_KEY_b}}}, + {BIND_ACTION_SEARCH_EDIT_RIGHT, m_none, {{XKB_KEY_Right}}}, + {BIND_ACTION_SEARCH_EDIT_RIGHT, m_ctrl, {{XKB_KEY_f}}}, + {BIND_ACTION_SEARCH_EDIT_RIGHT_WORD, m_ctrl, {{XKB_KEY_Right}}}, + {BIND_ACTION_SEARCH_EDIT_RIGHT_WORD, m_alt, {{XKB_KEY_f}}}, + {BIND_ACTION_SEARCH_EDIT_HOME, m_none, {{XKB_KEY_Home}}}, + {BIND_ACTION_SEARCH_EDIT_HOME, m_ctrl, {{XKB_KEY_a}}}, + {BIND_ACTION_SEARCH_EDIT_END, m_none, {{XKB_KEY_End}}}, + {BIND_ACTION_SEARCH_EDIT_END, m_ctrl, {{XKB_KEY_e}}}, + {BIND_ACTION_SEARCH_DELETE_PREV, m_none, {{XKB_KEY_BackSpace}}}, + {BIND_ACTION_SEARCH_DELETE_PREV_WORD, m_ctrl, {{XKB_KEY_BackSpace}}}, + {BIND_ACTION_SEARCH_DELETE_PREV_WORD, m_alt, {{XKB_KEY_BackSpace}}}, + {BIND_ACTION_SEARCH_DELETE_NEXT, m_none, {{XKB_KEY_Delete}}}, + {BIND_ACTION_SEARCH_DELETE_NEXT_WORD, m_ctrl, {{XKB_KEY_Delete}}}, + {BIND_ACTION_SEARCH_DELETE_NEXT_WORD, m_alt, {{XKB_KEY_d}}}, + {BIND_ACTION_SEARCH_EXTEND_WORD, m_ctrl, {{XKB_KEY_w}}}, + {BIND_ACTION_SEARCH_EXTEND_WORD_WS, m_ctrl_shift, {{XKB_KEY_w}}}, + {BIND_ACTION_SEARCH_CLIPBOARD_PASTE, m_ctrl, {{XKB_KEY_v}}}, + {BIND_ACTION_SEARCH_CLIPBOARD_PASTE, m_ctrl, {{XKB_KEY_y}}}, + {BIND_ACTION_SEARCH_PRIMARY_PASTE, m_shift, {{XKB_KEY_Insert}}}, }; conf->bindings.search.count = ALEN(bindings); @@ -2810,11 +2652,11 @@ static void add_default_url_bindings(struct config *conf) { static const struct config_key_binding bindings[] = { - {BIND_ACTION_URL_CANCEL, m_ctrl, XKB_KEY_c}, - {BIND_ACTION_URL_CANCEL, m_ctrl, XKB_KEY_g}, - {BIND_ACTION_URL_CANCEL, m_ctrl, XKB_KEY_d}, - {BIND_ACTION_URL_CANCEL, m_none, XKB_KEY_Escape}, - {BIND_ACTION_URL_TOGGLE_URL_ON_JUMP_LABEL, m_none, XKB_KEY_t}, + {BIND_ACTION_URL_CANCEL, m_ctrl, {{XKB_KEY_c}}}, + {BIND_ACTION_URL_CANCEL, m_ctrl, {{XKB_KEY_g}}}, + {BIND_ACTION_URL_CANCEL, m_ctrl, {{XKB_KEY_d}}}, + {BIND_ACTION_URL_CANCEL, m_none, {{XKB_KEY_Escape}}}, + {BIND_ACTION_URL_TOGGLE_URL_ON_JUMP_LABEL, m_none, {{XKB_KEY_t}}}, }; conf->bindings.url.count = ALEN(bindings); @@ -2825,15 +2667,15 @@ add_default_url_bindings(struct config *conf) static void add_default_mouse_bindings(struct config *conf) { - static const struct config_mouse_binding bindings[] = { - {BIND_ACTION_PRIMARY_PASTE, m_none, BTN_MIDDLE, 1}, - {BIND_ACTION_SELECT_BEGIN, m_none, BTN_LEFT, 1}, - {BIND_ACTION_SELECT_BEGIN_BLOCK, m_ctrl, BTN_LEFT, 1}, - {BIND_ACTION_SELECT_EXTEND, m_none, BTN_RIGHT, 1}, - {BIND_ACTION_SELECT_EXTEND_CHAR_WISE, m_ctrl, BTN_RIGHT, 1}, - {BIND_ACTION_SELECT_WORD, m_none, BTN_LEFT, 2}, - {BIND_ACTION_SELECT_WORD_WS, m_ctrl, BTN_LEFT, 2}, - {BIND_ACTION_SELECT_ROW, m_none, BTN_LEFT, 3}, + static const struct config_key_binding bindings[] = { + {BIND_ACTION_PRIMARY_PASTE, m_none, {.m = {BTN_MIDDLE, 1}}}, + {BIND_ACTION_SELECT_BEGIN, m_none, {.m = {BTN_LEFT, 1}}}, + {BIND_ACTION_SELECT_BEGIN_BLOCK, m_ctrl, {.m = {BTN_LEFT, 1}}}, + {BIND_ACTION_SELECT_EXTEND, m_none, {.m = {BTN_RIGHT, 1}}}, + {BIND_ACTION_SELECT_EXTEND_CHAR_WISE, m_ctrl, {.m = {BTN_RIGHT, 1}}}, + {BIND_ACTION_SELECT_WORD, m_none, {.m = {BTN_LEFT, 2}}}, + {BIND_ACTION_SELECT_WORD_WS, m_ctrl, {.m = {BTN_LEFT, 2}}}, + {BIND_ACTION_SELECT_ROW, m_none, {.m = {BTN_LEFT, 3}}}, }; conf->bindings.mouse.count = ALEN(bindings); @@ -3066,16 +2908,16 @@ config_load(struct config *conf, const char *conf_path, if (ret && (!resolve_key_binding_collisions( conf, section_info[SECTION_KEY_BINDINGS].name, - binding_action_map, &conf->bindings.key) || + binding_action_map, &conf->bindings.key, KEY_BINDING) || !resolve_key_binding_collisions( conf, section_info[SECTION_SEARCH_BINDINGS].name, - search_binding_action_map, &conf->bindings.search) || + search_binding_action_map, &conf->bindings.search, KEY_BINDING) || !resolve_key_binding_collisions( conf, section_info[SECTION_URL_BINDINGS].name, - url_binding_action_map, &conf->bindings.url) || - !resolve_mouse_binding_collisions( + url_binding_action_map, &conf->bindings.url, KEY_BINDING) || + !resolve_key_binding_collisions( conf, section_info[SECTION_MOUSE_BINDINGS].name, - binding_action_map, &conf->bindings.mouse))) + binding_action_map, &conf->bindings.mouse, MOUSE_BINDING))) { ret = !errors_are_fatal; } @@ -3198,34 +3040,6 @@ key_binding_list_clone(struct config_key_binding_list *dst, } } -static void NOINLINE -mouse_binding_list_clone(struct config_mouse_binding_list *dst, - const struct config_mouse_binding_list *src) -{ - struct argv *last_master_argv = NULL; - - dst->count = src->count; - dst->arr = xmalloc(src->count * sizeof(dst->arr[0])); - - for (size_t i = 0; i < src->count; i++) { - const struct config_mouse_binding *old = &src->arr[i]; - struct config_mouse_binding *new = &dst->arr[i]; - - *new = *old; - - if (old->pipe.argv.args == NULL) - continue; - - if (old->pipe.master_copy) { - binding_pipe_clone(&new->pipe, &old->pipe); - last_master_argv = &new->pipe.argv; - } else { - xassert(last_master_argv != NULL); - new->pipe.argv = *last_master_argv; - } - } -} - struct config * config_clone(const struct config *old) { @@ -3257,7 +3071,7 @@ config_clone(const struct config *old) key_binding_list_clone(&conf->bindings.key, &old->bindings.key); key_binding_list_clone(&conf->bindings.search, &old->bindings.search); key_binding_list_clone(&conf->bindings.url, &old->bindings.url); - mouse_binding_list_clone(&conf->bindings.mouse, &old->bindings.mouse); + key_binding_list_clone(&conf->bindings.mouse, &old->bindings.mouse); conf->notifications.length = 0; conf->notifications.head = conf->notifications.tail = 0; @@ -3317,7 +3131,7 @@ config_free(struct config conf) free_key_binding_list(&conf.bindings.key); free_key_binding_list(&conf.bindings.search); free_key_binding_list(&conf.bindings.url); - free_mouse_binding_list(&conf.bindings.mouse); + free_key_binding_list(&conf.bindings.mouse); user_notifications_free(&conf.notifications); } diff --git a/config.h b/config.h index 153b9c27..4a724bec 100644 --- a/config.h +++ b/config.h @@ -40,10 +40,27 @@ struct config_binding_pipe { bool master_copy; }; +enum config_key_binding_type { + KEY_BINDING, + MOUSE_BINDING, +}; + struct config_key_binding { int action; /* One of the varios bind_action_* enums from wayland.h */ struct config_key_modifiers modifiers; - xkb_keysym_t sym; + union { + /* Key bindings */ + struct { + xkb_keysym_t sym; + } k; + + /* Mouse bindings */ + struct { + int button; + int count; + } m; + }; + struct config_binding_pipe pipe; /* For error messages in collision handling */ @@ -52,6 +69,7 @@ struct config_key_binding { }; DEFINE_LIST(struct config_key_binding); +#if 0 struct config_mouse_binding { enum bind_action_normal action; struct config_key_modifiers modifiers; @@ -64,6 +82,7 @@ struct config_mouse_binding { int lineno; }; DEFINE_LIST(struct config_mouse_binding); +#endif typedef tll(char *) config_override_t; @@ -207,7 +226,7 @@ struct config { struct { /* Bindings for "normal" mode */ struct config_key_binding_list key; - struct config_mouse_binding_list mouse; + struct config_key_binding_list mouse; /* * Special modes diff --git a/input.c b/input.c index 0bd4b347..3e029ab2 100644 --- a/input.c +++ b/input.c @@ -520,7 +520,7 @@ convert_key_binding(const struct seat *seat, key_binding_list_t *bindings) { xkb_mod_mask_t mods = conf_modifiers_to_mask(seat, &conf_binding->modifiers); - xkb_keysym_t sym = maybe_repair_key_combo(seat, conf_binding->sym, mods); + xkb_keysym_t sym = maybe_repair_key_combo(seat, conf_binding->k.sym, mods); struct key_binding binding = { .mods = mods, @@ -561,13 +561,13 @@ convert_url_bindings(const struct config *conf, struct seat *seat) static void convert_mouse_binding(struct seat *seat, - const struct config_mouse_binding *conf_binding) + const struct config_key_binding *conf_binding) { struct mouse_binding binding = { .action = conf_binding->action, .mods = conf_modifiers_to_mask(seat, &conf_binding->modifiers), - .button = conf_binding->button, - .count = conf_binding->count, + .button = conf_binding->m.button, + .count = conf_binding->m.count, .pipe_argv = conf_binding->pipe.argv.args, }; tll_push_back(seat->mouse.bindings, binding); @@ -577,9 +577,7 @@ static void convert_mouse_bindings(const struct config *conf, struct seat *seat) { for (size_t i = 0; i < conf->bindings.mouse.count; i++) { - const struct config_mouse_binding *binding = &conf->bindings.mouse.arr[i]; - if (binding->action == BIND_ACTION_NONE) - continue; + const struct config_key_binding *binding = &conf->bindings.mouse.arr[i]; convert_mouse_binding(seat, binding); } } @@ -2543,19 +2541,19 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer, else { /* Seat does NOT have a keyboard - use mouse bindings *without* modifiers */ - const struct config_mouse_binding *match = NULL; + const struct config_key_binding *match = NULL; const struct config *conf = seat->wayl->conf; for (size_t i = 0; i < conf->bindings.mouse.count; i++) { - const struct config_mouse_binding *binding = + const struct config_key_binding *binding = &conf->bindings.mouse.arr[i]; - if (binding->button != button) { + if (binding->m.button != button) { /* Wrong button */ continue; } - if (binding->count > seat->mouse.count) { + if (binding->m.count > seat->mouse.count) { /* Incorrect click count */ continue; } @@ -2566,7 +2564,7 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer, continue; } - if (match == NULL || binding->count > match->count) + if (match == NULL || binding->m.count > match->m.count) match = binding; }