conf: bindings: allow several mappings for the same action

If the bindings has different pipe command associated with them, treat
them as different actions.
This commit is contained in:
Daniel Eklöf 2020-07-15 16:39:07 +02:00
parent 062b0eb7ab
commit 1541531765
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
4 changed files with 166 additions and 87 deletions

203
config.c
View file

@ -485,21 +485,19 @@ parse_section_csd(const char *key, const char *value, struct config *conf,
}
static bool
verify_key_combo(const struct config *conf, const char *combo, const char *path,
unsigned lineno)
verify_key_combo(const struct config *conf, enum bind_action_normal action,
const char *combo, const char *path, unsigned lineno)
{
for (enum bind_action_normal action = 0; action < BIND_ACTION_COUNT; action++) {
if (conf->bindings.key[action] == NULL)
continue;
char *copy = strdup(conf->bindings.key[action]);
tll_foreach(conf->bindings.key, it) {
char *copy = strdup(it->item.key);
for (char *save = NULL, *collision = strtok_r(copy, " ", &save);
collision != NULL;
collision = strtok_r(NULL, " ", &save))
{
if (strcmp(combo, collision) == 0) {
LOG_ERR("%s:%d: %s already mapped to %s", path, lineno, combo, binding_action_map[action]);
LOG_ERR("%s:%d: %s already mapped to %s", path, lineno, combo,
binding_action_map[it->item.action]);
free(copy);
return false;
}
@ -530,11 +528,11 @@ parse_section_key_bindings(
const char *key, const char *value, struct config *conf,
const char *path, unsigned lineno)
{
const char *spawn = strchr(key, ':');
if (spawn != NULL)
spawn++;
const char *pipe_cmd = strchr(key, ':');
if (pipe_cmd != NULL)
pipe_cmd++;
const size_t key_len = spawn != NULL ? spawn - key - 1: strlen(key);
const size_t key_len = pipe_cmd != NULL ? pipe_cmd - key - 1: strlen(key);
for (enum bind_action_normal action = 0;
action < BIND_ACTION_COUNT;
@ -547,19 +545,46 @@ parse_section_key_bindings(
continue;
if (strcasecmp(value, "none") == 0) {
free(conf->bindings.key[action]);
conf->bindings.key[action] = NULL;
tll_foreach(conf->bindings.key, it) {
if (it->item.action == action) {
free(it->item.key);
free(it->item.pipe_cmd);
tll_remove(conf->bindings.key, it);
}
}
return true;
}
if (!verify_key_combo(conf, value, path, lineno)) {
if (!verify_key_combo(conf, action, value, path, lineno)) {
return false;
}
free(conf->bindings.key[action]);
free(conf->bindings.spawn[action]);
conf->bindings.key[action] = strdup(value);
conf->bindings.spawn[action] = spawn != NULL ? strdup(spawn) : NULL;
bool already_added = false;
tll_foreach(conf->bindings.key, it) {
if (it->item.action == action &&
((it->item.pipe_cmd == NULL && pipe_cmd == NULL) ||
(it->item.pipe_cmd != NULL && pipe_cmd != NULL &&
strcmp(it->item.pipe_cmd, pipe_cmd) == 0)))
{
free(it->item.key);
free(it->item.pipe_cmd);
it->item.key = strdup(value);
it->item.pipe_cmd = pipe_cmd != NULL ? strdup(pipe_cmd) : NULL;
already_added = true;
break;
}
}
if (!already_added) {
struct config_key_binding_normal binding = {
.action = action,
.key = strdup(value),
.pipe_cmd = pipe_cmd != NULL ? strdup(pipe_cmd) : NULL,
};
tll_push_back(conf->bindings.key, binding);
}
return true;
}
@ -581,7 +606,12 @@ parse_section_mouse_bindings(
continue;
if (strcmp(value, "NONE") == 0) {
conf->bindings.mouse[action] = (struct mouse_binding){0, 0, BIND_ACTION_NONE};
tll_foreach(conf->bindings.mouse, it) {
if (it->item.action == action) {
tll_remove(conf->bindings.mouse, it);
break;
}
}
return true;
}
@ -603,16 +633,32 @@ parse_section_mouse_bindings(
const int count = 1;
/* Make sure button isn't already mapped to another action */
for (enum bind_action_normal j = 0; j < BIND_ACTION_COUNT; j++) {
const struct mouse_binding *collision = &conf->bindings.mouse[j];
if (collision->button == i && collision->count == count) {
tll_foreach(conf->bindings.mouse, it) {
if (it->item.button == i && it->item.count == count) {
LOG_ERR("%s:%d: %s already mapped to %s", path, lineno,
value, binding_action_map[collision->action]);
value, binding_action_map[it->item.action]);
return false;
}
}
conf->bindings.mouse[action] = (struct mouse_binding){i, count, action};
bool already_added = false;
tll_foreach(conf->bindings.mouse, it) {
if (it->item.action == action) {
it->item.button = i;
it->item.count = count;
already_added = true;
break;
}
}
if (!already_added) {
struct mouse_binding binding = {
.action = action,
.button = i,
.count = count,
};
tll_push_back(conf->bindings.mouse, binding);
}
return true;
}
@ -896,42 +942,6 @@ config_load(struct config *conf, const char *conf_path)
.cursor = 0,
},
},
.bindings = {
.key = {
[BIND_ACTION_SCROLLBACK_UP] = strdup("Shift+Page_Up"),
[BIND_ACTION_SCROLLBACK_DOWN] = strdup("Shift+Page_Down"),
[BIND_ACTION_CLIPBOARD_COPY] = strdup("Control+Shift+C"),
[BIND_ACTION_CLIPBOARD_PASTE] = strdup("Control+Shift+V"),
[BIND_ACTION_SEARCH_START] = strdup("Control+Shift+R"),
[BIND_ACTION_FONT_SIZE_UP] = strdup("Control+plus Control+equal Control+KP_Add"),
[BIND_ACTION_FONT_SIZE_DOWN] = strdup("Control+minus Control+KP_Subtract"),
[BIND_ACTION_FONT_SIZE_RESET] = strdup("Control+0 Control+KP_0"),
[BIND_ACTION_SPAWN_TERMINAL] = strdup("Control+Shift+N"),
},
.mouse = {
[BIND_ACTION_PRIMARY_PASTE] = {BTN_MIDDLE, 1, BIND_ACTION_PRIMARY_PASTE},
},
.search = {
[BIND_ACTION_SEARCH_CANCEL] = strdup("Control+g Escape"),
[BIND_ACTION_SEARCH_COMMIT] = strdup("Return"),
[BIND_ACTION_SEARCH_FIND_PREV] = strdup("Control+r"),
[BIND_ACTION_SEARCH_FIND_NEXT] = strdup("Control+s"),
[BIND_ACTION_SEARCH_EDIT_LEFT] = strdup("Left Control+b"),
[BIND_ACTION_SEARCH_EDIT_LEFT_WORD] = strdup("Control+Left Mod1+b"),
[BIND_ACTION_SEARCH_EDIT_RIGHT] = strdup("Right Control+f"),
[BIND_ACTION_SEARCH_EDIT_RIGHT_WORD] = strdup("Control+Right Mod1+f"),
[BIND_ACTION_SEARCH_EDIT_HOME] = strdup("Home Control+a"),
[BIND_ACTION_SEARCH_EDIT_END] = strdup("End Control+e"),
[BIND_ACTION_SEARCH_DELETE_PREV] = strdup("BackSpace"),
[BIND_ACTION_SEARCH_DELETE_PREV_WORD] = strdup("Mod1+BackSpace Control+BackSpace"),
[BIND_ACTION_SEARCH_DELETE_NEXT] = strdup("Delete "),
[BIND_ACTION_SEARCH_DELETE_NEXT_WORD] = strdup("Mod1+d Control+Delete"),
[BIND_ACTION_SEARCH_EXTEND_WORD] = strdup("Control+w"),
[BIND_ACTION_SEARCH_EXTEND_WORD_WS] = strdup("Control+Shift+W"),
},
},
.csd = {
.preferred = CONF_CSD_PREFER_SERVER,
.title_height = 26,
@ -951,6 +961,63 @@ config_load(struct config *conf, const char *conf_path)
},
};
struct config_key_binding_normal scrollback_up = {BIND_ACTION_SCROLLBACK_UP, strdup("Shift+Page_Up")};
struct config_key_binding_normal scrollback_down = {BIND_ACTION_SCROLLBACK_DOWN, strdup("Shift+Page_Down")};
struct config_key_binding_normal clipboard_copy = {BIND_ACTION_CLIPBOARD_COPY, strdup("Control+Shift+C")};
struct config_key_binding_normal clipboard_paste = {BIND_ACTION_CLIPBOARD_PASTE, strdup("Control+Shift+V")};
struct config_key_binding_normal search_start = {BIND_ACTION_SEARCH_START, strdup("Control+Shift+R")};
struct config_key_binding_normal font_size_up = {BIND_ACTION_FONT_SIZE_UP, strdup("Control+plus Control+equal Control+KP_Add")};
struct config_key_binding_normal font_size_down = {BIND_ACTION_FONT_SIZE_DOWN, strdup("Control+minus Control+KP_Subtract")};
struct config_key_binding_normal font_size_reset = {BIND_ACTION_FONT_SIZE_RESET, strdup("Control+0 Control+KP_0")};
struct config_key_binding_normal spawn_terminal = {BIND_ACTION_SPAWN_TERMINAL, strdup("Control+Shift+N")};
tll_push_back(conf->bindings.key, scrollback_up);
tll_push_back(conf->bindings.key, scrollback_down);
tll_push_back(conf->bindings.key, clipboard_copy);
tll_push_back(conf->bindings.key, clipboard_paste);
tll_push_back(conf->bindings.key, search_start);
tll_push_back(conf->bindings.key, font_size_up);
tll_push_back(conf->bindings.key, font_size_down);
tll_push_back(conf->bindings.key, font_size_reset);
tll_push_back(conf->bindings.key, spawn_terminal);
struct mouse_binding primary_paste = {BIND_ACTION_PRIMARY_PASTE, BTN_MIDDLE, 1};
tll_push_back(conf->bindings.mouse, primary_paste);
struct config_key_binding_search search_cancel = {BIND_ACTION_SEARCH_CANCEL, strdup("Control+g Escape")};
struct config_key_binding_search search_commit = {BIND_ACTION_SEARCH_COMMIT, strdup("Return")};
struct config_key_binding_search search_find_prev = {BIND_ACTION_SEARCH_FIND_PREV, strdup("Control+r")};
struct config_key_binding_search search_find_next = {BIND_ACTION_SEARCH_FIND_NEXT, strdup("Control+s")};
struct config_key_binding_search search_edit_left = {BIND_ACTION_SEARCH_EDIT_LEFT, strdup("Left Control+b")};
struct config_key_binding_search search_edit_left_word = {BIND_ACTION_SEARCH_EDIT_LEFT_WORD, strdup("Control+Left Mod1+b")};
struct config_key_binding_search search_edit_right = {BIND_ACTION_SEARCH_EDIT_RIGHT, strdup("Right Control+f")};
struct config_key_binding_search search_edit_right_word = {BIND_ACTION_SEARCH_EDIT_RIGHT_WORD, strdup("Control+Right Mod1+f")};
struct config_key_binding_search search_edit_home = {BIND_ACTION_SEARCH_EDIT_HOME, strdup("Home Control+a")};
struct config_key_binding_search search_edit_end = {BIND_ACTION_SEARCH_EDIT_END, strdup("End Control+e")};
struct config_key_binding_search search_del_prev = {BIND_ACTION_SEARCH_DELETE_PREV, strdup("BackSpace")};
struct config_key_binding_search search_del_prev_word = {BIND_ACTION_SEARCH_DELETE_PREV_WORD, strdup("Mod1+BackSpace Control+BackSpace")};
struct config_key_binding_search search_del_next = {BIND_ACTION_SEARCH_DELETE_NEXT, strdup("Delete")};
struct config_key_binding_search search_del_next_word = {BIND_ACTION_SEARCH_DELETE_NEXT_WORD, strdup("Mod1+d Control+Delete")};
struct config_key_binding_search search_ext_word = {BIND_ACTION_SEARCH_EXTEND_WORD, strdup("Control+w")};
struct config_key_binding_search search_ext_word_ws = {BIND_ACTION_SEARCH_EXTEND_WORD_WS, strdup("Control+Shift+W")};
tll_push_back(conf->bindings.search, search_cancel);
tll_push_back(conf->bindings.search, search_commit);
tll_push_back(conf->bindings.search, search_find_prev);
tll_push_back(conf->bindings.search, search_find_next);
tll_push_back(conf->bindings.search, search_edit_left);
tll_push_back(conf->bindings.search, search_edit_left_word);
tll_push_back(conf->bindings.search, search_edit_right);
tll_push_back(conf->bindings.search, search_edit_right_word);
tll_push_back(conf->bindings.search, search_edit_home);
tll_push_back(conf->bindings.search, search_edit_end);
tll_push_back(conf->bindings.search, search_del_prev);
tll_push_back(conf->bindings.search, search_del_prev_word);
tll_push_back(conf->bindings.search, search_del_next);
tll_push_back(conf->bindings.search, search_del_next_word);
tll_push_back(conf->bindings.search, search_ext_word);
tll_push_back(conf->bindings.search, search_ext_word_ws);
char *default_path = NULL;
if (conf_path == NULL) {
if ((default_path = get_config_path()) == NULL) {
@ -995,12 +1062,16 @@ config_free(struct config conf)
tll_free(conf.fonts);
free(conf.server_socket_path);
for (enum bind_action_normal i = 0; i < BIND_ACTION_COUNT; i++) {
free(conf.bindings.key[i]);
free(conf.bindings.spawn[i]);
tll_foreach(conf.bindings.key, it) {
free(it->item.key);
free(it->item.pipe_cmd);
}
for (enum bind_action_search i = 0; i < BIND_ACTION_SEARCH_COUNT; i++)
free(conf.bindings.search[i]);
tll_foreach(conf.bindings.search, it)
free(it->item.key);
tll_free(conf.bindings.key);
tll_free(conf.bindings.mouse);
tll_free(conf.bindings.search);
}
struct config_font

View file

@ -6,6 +6,7 @@
#include <tllist.h>
#include "terminal.h"
#include "wayland.h"
struct config_font {
char *pattern;
@ -13,6 +14,17 @@ struct config_font {
int px_size;
};
struct config_key_binding_normal {
enum bind_action_normal action;
char *key;
char *pipe_cmd;
};
struct config_key_binding_search {
enum bind_action_search action;
char *key;
};
struct config {
char *term;
char *shell;
@ -48,10 +60,8 @@ struct config {
struct {
/* Bindings for "normal" mode */
char *key[BIND_ACTION_COUNT];
char *spawn[BIND_ACTION_COUNT];
struct mouse_binding mouse[BIND_ACTION_COUNT];
tll(struct config_key_binding_normal) key;
tll(struct mouse_binding) mouse;
/*
* Special modes
@ -59,7 +69,7 @@ struct config {
/* While searching (not - action to *start* a search is in the
* 'key' bindings above */
char *search[BIND_ACTION_SEARCH_COUNT];
tll(struct config_key_binding_search) search;
} bindings;
struct {

28
input.c
View file

@ -398,34 +398,33 @@ keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard,
munmap(map_str, size);
close(fd);
for (enum bind_action_normal i = 0; i < BIND_ACTION_COUNT; i++) {
tll_foreach(wayl->conf->bindings.key, it) {
key_binding_list_t bindings = tll_init();
input_parse_key_binding(
seat->kbd.xkb_keymap, wayl->conf->bindings.key[i], &bindings);
seat->kbd.xkb_keymap, it->item.key, &bindings);
tll_foreach(bindings, it) {
tll_foreach(bindings, it2) {
tll_push_back(
seat->kbd.bindings.key,
((struct key_binding_normal){
.bind = it->item,
.action = i,
.pipe_cmd = wayl->conf->bindings.spawn[i]}));
.bind = it2->item,
.action = it->item.action,
.pipe_cmd = it->item.pipe_cmd}));
}
tll_free(bindings);
}
for (enum bind_action_search i = 0; i < BIND_ACTION_SEARCH_COUNT; i++) {
tll_foreach(wayl->conf->bindings.search, it) {
key_binding_list_t bindings = tll_init();
input_parse_key_binding(
seat->kbd.xkb_keymap, wayl->conf->bindings.search[i], &bindings);
seat->kbd.xkb_keymap, it->item.key, &bindings);
tll_foreach(bindings, it) {
tll_foreach(bindings, it2) {
tll_push_back(
seat->kbd.bindings.search,
((struct key_binding_search){.bind = it->item, .action = i}));
((struct key_binding_search){
.bind = it2->item, .action = it->item.action}));
}
tll_free(bindings);
}
}
@ -1370,9 +1369,8 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
}
else {
for (size_t i = 0; i < ALEN(wayl->conf->bindings.mouse); i++) {
const struct mouse_binding *binding =
&wayl->conf->bindings.mouse[i];
tll_foreach(wayl->conf->bindings.mouse, it) {
const struct mouse_binding *binding = &it->item;
if (binding->button != button) {
/* Wrong button */

View file

@ -51,9 +51,9 @@ struct key_binding_normal {
};
struct mouse_binding {
enum bind_action_normal action;
uint32_t button;
int count;
enum bind_action_normal action;
};
enum bind_action_search {