mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-05-02 06:46:32 -04:00
config: unify key- and mouse bindings
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.
This commit is contained in:
parent
4c50c44cf7
commit
f6a591b80a
3 changed files with 242 additions and 411 deletions
608
config.c
608
config.c
|
|
@ -1501,26 +1501,7 @@ free_key_binding_list(struct config_key_binding_list *bindings)
|
||||||
bindings->count = 0;
|
bindings->count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static bool NOINLINE
|
||||||
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
|
|
||||||
parse_modifiers(struct context *ctx, const char *text, size_t len,
|
parse_modifiers(struct context *ctx, const char *text, size_t len,
|
||||||
struct config_key_modifiers *modifiers)
|
struct config_key_modifiers *modifiers)
|
||||||
{
|
{
|
||||||
|
|
@ -1588,8 +1569,8 @@ argv_compare(const struct argv *argv1, const struct argv *argv2)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void NOINLINE
|
static void NOINLINE
|
||||||
remove_action_from_key_bindings_list(struct config_key_binding_list *bindings,
|
remove_from_key_bindings_list(struct config_key_binding_list *bindings,
|
||||||
int action, const struct argv *pipe_argv)
|
int action, const struct argv *pipe_argv)
|
||||||
{
|
{
|
||||||
size_t remove_first_idx = 0;
|
size_t remove_first_idx = 0;
|
||||||
size_t remove_count = 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;
|
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
|
static bool NOINLINE
|
||||||
value_to_key_combos(struct context *ctx, int action, struct argv *argv,
|
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) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1663,20 +1680,57 @@ value_to_key_combos(struct context *ctx, int action, struct argv *argv,
|
||||||
key = combo;
|
key = combo;
|
||||||
new_combo->modifiers = (struct config_key_modifiers){0};
|
new_combo->modifiers = (struct config_key_modifiers){0};
|
||||||
} else {
|
} else {
|
||||||
|
*key = '\0';
|
||||||
if (!parse_modifiers(ctx, combo, key - combo, &new_combo->modifiers))
|
if (!parse_modifiers(ctx, combo, key - combo, &new_combo->modifiers))
|
||||||
goto err;
|
goto err;
|
||||||
key++; /* Skip past the '+' */
|
key++; /* Skip past the '+' */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Translate key name to symbol */
|
switch (type) {
|
||||||
new_combo->sym = xkb_keysym_from_name(key, 0);
|
case KEY_BINDING:
|
||||||
if (new_combo->sym == XKB_KEY_NoSymbol) {
|
/* Translate key name to symbol */
|
||||||
LOG_CONTEXTUAL_ERR("not a valid XKB key name: %s", key);
|
new_combo->k.sym = xkb_keysym_from_name(key, 0);
|
||||||
goto err;
|
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 = xrealloc(
|
||||||
bindings->arr,
|
bindings->arr,
|
||||||
|
|
@ -1729,81 +1783,6 @@ modifiers_to_str(const struct config_key_modifiers *mods)
|
||||||
return ret;
|
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
|
* Parses a key binding value on the form
|
||||||
* "[cmd-to-exec arg1 arg2] Mods+Key"
|
* "[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.
|
* - cmd: allocated string containing "cmd arg1 arg2...". Caller frees.
|
||||||
* - argv: allocated array containing {"cmd", "arg1", "arg2", NULL}. 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)
|
pipe_argv_from_value(struct context *ctx, struct argv *argv)
|
||||||
{
|
{
|
||||||
argv->args = NULL;
|
argv->args = NULL;
|
||||||
|
|
@ -1878,7 +1857,9 @@ parse_key_binding_section(struct context *ctx,
|
||||||
if (strcmp(ctx->key, action_map[action]) != 0)
|
if (strcmp(ctx->key, action_map[action]) != 0)
|
||||||
continue;
|
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);
|
free_argv(&pipe_argv);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -1925,7 +1906,7 @@ UNITTEST
|
||||||
xassert(parse_key_binding_section(&ctx, ALEN(map), map, &bindings));
|
xassert(parse_key_binding_section(&ctx, ALEN(map), map, &bindings));
|
||||||
xassert(bindings.count == 1);
|
xassert(bindings.count == 1);
|
||||||
xassert(bindings.arr[0].action == TEST_ACTION_FOO);
|
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
|
* ADD bar=Control+g Control+Shift+x
|
||||||
|
|
@ -1938,10 +1919,10 @@ UNITTEST
|
||||||
xassert(bindings.count == 3);
|
xassert(bindings.count == 3);
|
||||||
xassert(bindings.arr[0].action == TEST_ACTION_FOO);
|
xassert(bindings.arr[0].action == TEST_ACTION_FOO);
|
||||||
xassert(bindings.arr[1].action == TEST_ACTION_BAR);
|
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[1].modifiers.ctrl);
|
||||||
xassert(bindings.arr[2].action == TEST_ACTION_BAR);
|
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);
|
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[0].action == TEST_ACTION_BAR);
|
||||||
xassert(bindings.arr[1].action == TEST_ACTION_BAR);
|
xassert(bindings.arr[1].action == TEST_ACTION_BAR);
|
||||||
xassert(bindings.arr[2].action == TEST_ACTION_FOO);
|
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[2].modifiers.alt);
|
||||||
xassert(bindings.arr[3].action == TEST_ACTION_FOO);
|
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);
|
xassert(bindings.arr[3].modifiers.shift);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -2011,176 +1992,11 @@ parse_section_url_bindings(struct context *ctx)
|
||||||
&ctx->conf->bindings.url);
|
&ctx->conf->bindings.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct {
|
static bool NOINLINE
|
||||||
const char *name;
|
resolve_key_binding_collisions(struct config *conf, const char *section_name,
|
||||||
int code;
|
const char *const action_map[],
|
||||||
} button_map[] = {
|
struct config_key_binding_list *bindings,
|
||||||
{"BTN_LEFT", BTN_LEFT},
|
enum config_key_binding_type type)
|
||||||
{"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)
|
|
||||||
{
|
{
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
|
|
||||||
|
|
@ -2188,23 +2004,27 @@ resolve_mouse_binding_collisions(struct config *conf, const char *section_name,
|
||||||
enum {COLLISION_NONE,
|
enum {COLLISION_NONE,
|
||||||
COLLISION_OVERRIDE,
|
COLLISION_OVERRIDE,
|
||||||
COLLISION_BINDING} collision_type = COLLISION_NONE;
|
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);
|
xassert(binding1->action != BIND_ACTION_NONE);
|
||||||
|
|
||||||
const struct config_key_modifiers *mods1 = &binding1->modifiers;
|
const struct config_key_modifiers *mods1 = &binding1->modifiers;
|
||||||
|
|
||||||
/* Does our modifiers collide with the selection override mods? */
|
/* 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;
|
collision_type = COLLISION_OVERRIDE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Does our binding collide with another binding? */
|
/* Does our binding collide with another binding? */
|
||||||
for (ssize_t j = i - 1;
|
for (ssize_t j = i - 1;
|
||||||
collision_type == COLLISION_NONE && j >= 0;
|
collision_type == COLLISION_NONE && j >= 0;
|
||||||
j--)
|
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);
|
xassert(binding2->action != BIND_ACTION_NONE);
|
||||||
|
|
||||||
if (binding2->action == binding1->action) {
|
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;
|
const struct config_key_modifiers *mods2 = &binding2->modifiers;
|
||||||
|
|
||||||
bool mods_equal = modifiers_equal(mods1, mods2);
|
bool mods_equal = modifiers_equal(mods1, mods2);
|
||||||
bool button_equal = binding1->button == binding2->button;
|
bool sym_equal;
|
||||||
bool count_equal = binding1->count == binding2->count;
|
|
||||||
|
|
||||||
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;
|
continue;
|
||||||
|
|
||||||
collision_binding = binding2;
|
collision_binding = binding2;
|
||||||
|
|
@ -2228,13 +2058,25 @@ resolve_mouse_binding_collisions(struct config *conf, const char *section_name,
|
||||||
|
|
||||||
if (collision_type != COLLISION_NONE) {
|
if (collision_type != COLLISION_NONE) {
|
||||||
char *modifier_names = modifiers_to_str(mods1);
|
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];
|
switch (type){
|
||||||
if (binding1->count > 1)
|
case KEY_BINDING:
|
||||||
sprintf(click_count, "-%d", binding1->count);
|
xkb_keysym_get_name(binding1->k.sym, sym_name, sizeof(sym_name));
|
||||||
else
|
break;
|
||||||
click_count[0] = '\0';
|
|
||||||
|
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) {
|
switch (collision_type) {
|
||||||
case COLLISION_NONE:
|
case COLLISION_NONE:
|
||||||
|
|
@ -2243,10 +2085,10 @@ resolve_mouse_binding_collisions(struct config *conf, const char *section_name,
|
||||||
case COLLISION_BINDING: {
|
case COLLISION_BINDING: {
|
||||||
bool has_pipe = collision_binding->pipe.argv.args != NULL;
|
bool has_pipe = collision_binding->pipe.argv.args != NULL;
|
||||||
LOG_AND_NOTIFY_ERR(
|
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,
|
binding1->path, binding1->lineno, section_name,
|
||||||
action_map[binding1->action],
|
action_map[binding1->action],
|
||||||
modifier_names, button_name, click_count,
|
modifier_names, sym_name,
|
||||||
action_map[collision_binding->action],
|
action_map[collision_binding->action],
|
||||||
has_pipe ? " [" : "",
|
has_pipe ? " [" : "",
|
||||||
has_pipe ? collision_binding->pipe.argv.args[0] : "",
|
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';
|
override_names[strlen(override_names) - 1] = '\0';
|
||||||
|
|
||||||
LOG_AND_NOTIFY_ERR(
|
LOG_AND_NOTIFY_ERR(
|
||||||
"%s:%d: [%s].%s: %s%s%s: "
|
"%s:%d: [%s].%s: %s%s: "
|
||||||
"modifiers conflict with 'selection-override-modifiers=%s'",
|
"modifiers conflict with 'selection-override-modifiers=%s'",
|
||||||
binding1->path, binding1->lineno, section_name,
|
binding1->path, binding1->lineno, section_name,
|
||||||
action_map[binding1->action],
|
action_map[binding1->action],
|
||||||
modifier_names, button_name, click_count,
|
modifier_names, sym_name, override_names);
|
||||||
override_names);
|
|
||||||
free(override_names);
|
free(override_names);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(modifier_names);
|
free(modifier_names);
|
||||||
|
|
||||||
if (binding1->pipe.master_copy && i + 1 < bindings->count) {
|
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 &&
|
if (next->action == binding1->action &&
|
||||||
argv_compare(&binding1->pipe.argv, &next->pipe.argv) == 0)
|
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 */
|
/* Remove the most recent binding */
|
||||||
size_t move_count = bindings->count - (i + 1);
|
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)
|
if (strcmp(key, binding_action_map[action]) != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!value_to_mouse_combos(
|
if (!value_to_key_combos(
|
||||||
ctx, action, &pipe_argv, &conf->bindings.mouse))
|
ctx, action, &pipe_argv, &conf->bindings.mouse, MOUSE_BINDING))
|
||||||
{
|
{
|
||||||
free_argv(&pipe_argv);
|
free_argv(&pipe_argv);
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -2743,21 +2585,21 @@ static void
|
||||||
add_default_key_bindings(struct config *conf)
|
add_default_key_bindings(struct config *conf)
|
||||||
{
|
{
|
||||||
static const struct config_key_binding bindings[] = {
|
static const struct config_key_binding bindings[] = {
|
||||||
{BIND_ACTION_SCROLLBACK_UP_PAGE, m_shift, XKB_KEY_Prior},
|
{BIND_ACTION_SCROLLBACK_UP_PAGE, m_shift, {{XKB_KEY_Prior}}},
|
||||||
{BIND_ACTION_SCROLLBACK_DOWN_PAGE, m_shift, XKB_KEY_Next},
|
{BIND_ACTION_SCROLLBACK_DOWN_PAGE, m_shift, {{XKB_KEY_Next}}},
|
||||||
{BIND_ACTION_CLIPBOARD_COPY, m_ctrl_shift, XKB_KEY_c},
|
{BIND_ACTION_CLIPBOARD_COPY, m_ctrl_shift, {{XKB_KEY_c}}},
|
||||||
{BIND_ACTION_CLIPBOARD_PASTE, m_ctrl_shift, XKB_KEY_v},
|
{BIND_ACTION_CLIPBOARD_PASTE, m_ctrl_shift, {{XKB_KEY_v}}},
|
||||||
{BIND_ACTION_PRIMARY_PASTE, m_shift, XKB_KEY_Insert},
|
{BIND_ACTION_PRIMARY_PASTE, m_shift, {{XKB_KEY_Insert}}},
|
||||||
{BIND_ACTION_SEARCH_START, m_ctrl_shift, XKB_KEY_r},
|
{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_plus}}},
|
||||||
{BIND_ACTION_FONT_SIZE_UP, m_ctrl, XKB_KEY_equal},
|
{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_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_minus}}},
|
||||||
{BIND_ACTION_FONT_SIZE_DOWN, m_ctrl, XKB_KEY_KP_Subtract},
|
{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_0}}},
|
||||||
{BIND_ACTION_FONT_SIZE_RESET, m_ctrl, XKB_KEY_KP_0},
|
{BIND_ACTION_FONT_SIZE_RESET, m_ctrl, {{XKB_KEY_KP_0}}},
|
||||||
{BIND_ACTION_SPAWN_TERMINAL, m_ctrl_shift, XKB_KEY_n},
|
{BIND_ACTION_SPAWN_TERMINAL, m_ctrl_shift, {{XKB_KEY_n}}},
|
||||||
{BIND_ACTION_SHOW_URLS_LAUNCH, m_ctrl_shift, XKB_KEY_u},
|
{BIND_ACTION_SHOW_URLS_LAUNCH, m_ctrl_shift, {{XKB_KEY_u}}},
|
||||||
};
|
};
|
||||||
|
|
||||||
conf->bindings.key.count = ALEN(bindings);
|
conf->bindings.key.count = ALEN(bindings);
|
||||||
|
|
@ -2770,35 +2612,35 @@ static void
|
||||||
add_default_search_bindings(struct config *conf)
|
add_default_search_bindings(struct config *conf)
|
||||||
{
|
{
|
||||||
static const struct config_key_binding bindings[] = {
|
static const struct config_key_binding bindings[] = {
|
||||||
{BIND_ACTION_SEARCH_CANCEL, m_ctrl, XKB_KEY_c},
|
{BIND_ACTION_SEARCH_CANCEL, m_ctrl, {{XKB_KEY_c}}},
|
||||||
{BIND_ACTION_SEARCH_CANCEL, m_ctrl, XKB_KEY_g},
|
{BIND_ACTION_SEARCH_CANCEL, m_ctrl, {{XKB_KEY_g}}},
|
||||||
{BIND_ACTION_SEARCH_CANCEL, m_none, XKB_KEY_Escape},
|
{BIND_ACTION_SEARCH_CANCEL, m_none, {{XKB_KEY_Escape}}},
|
||||||
{BIND_ACTION_SEARCH_COMMIT, m_none, XKB_KEY_Return},
|
{BIND_ACTION_SEARCH_COMMIT, m_none, {{XKB_KEY_Return}}},
|
||||||
{BIND_ACTION_SEARCH_FIND_PREV, m_ctrl, XKB_KEY_r},
|
{BIND_ACTION_SEARCH_FIND_PREV, m_ctrl, {{XKB_KEY_r}}},
|
||||||
{BIND_ACTION_SEARCH_FIND_NEXT, m_ctrl, XKB_KEY_s},
|
{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_none, {{XKB_KEY_Left}}},
|
||||||
{BIND_ACTION_SEARCH_EDIT_LEFT, m_ctrl, XKB_KEY_b},
|
{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_ctrl, {{XKB_KEY_Left}}},
|
||||||
{BIND_ACTION_SEARCH_EDIT_LEFT_WORD, m_alt, XKB_KEY_b},
|
{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_none, {{XKB_KEY_Right}}},
|
||||||
{BIND_ACTION_SEARCH_EDIT_RIGHT, m_ctrl, XKB_KEY_f},
|
{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_ctrl, {{XKB_KEY_Right}}},
|
||||||
{BIND_ACTION_SEARCH_EDIT_RIGHT_WORD, m_alt, XKB_KEY_f},
|
{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_none, {{XKB_KEY_Home}}},
|
||||||
{BIND_ACTION_SEARCH_EDIT_HOME, m_ctrl, XKB_KEY_a},
|
{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_none, {{XKB_KEY_End}}},
|
||||||
{BIND_ACTION_SEARCH_EDIT_END, m_ctrl, XKB_KEY_e},
|
{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, m_none, {{XKB_KEY_BackSpace}}},
|
||||||
{BIND_ACTION_SEARCH_DELETE_PREV_WORD, m_ctrl, 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_PREV_WORD, m_alt, {{XKB_KEY_BackSpace}}},
|
||||||
{BIND_ACTION_SEARCH_DELETE_NEXT, m_none, XKB_KEY_Delete},
|
{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_ctrl, {{XKB_KEY_Delete}}},
|
||||||
{BIND_ACTION_SEARCH_DELETE_NEXT_WORD, m_alt, XKB_KEY_d},
|
{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, m_ctrl, {{XKB_KEY_w}}},
|
||||||
{BIND_ACTION_SEARCH_EXTEND_WORD_WS, m_ctrl_shift, 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_v}}},
|
||||||
{BIND_ACTION_SEARCH_CLIPBOARD_PASTE, m_ctrl, XKB_KEY_y},
|
{BIND_ACTION_SEARCH_CLIPBOARD_PASTE, m_ctrl, {{XKB_KEY_y}}},
|
||||||
{BIND_ACTION_SEARCH_PRIMARY_PASTE, m_shift, XKB_KEY_Insert},
|
{BIND_ACTION_SEARCH_PRIMARY_PASTE, m_shift, {{XKB_KEY_Insert}}},
|
||||||
};
|
};
|
||||||
|
|
||||||
conf->bindings.search.count = ALEN(bindings);
|
conf->bindings.search.count = ALEN(bindings);
|
||||||
|
|
@ -2810,11 +2652,11 @@ static void
|
||||||
add_default_url_bindings(struct config *conf)
|
add_default_url_bindings(struct config *conf)
|
||||||
{
|
{
|
||||||
static const struct config_key_binding bindings[] = {
|
static const struct config_key_binding bindings[] = {
|
||||||
{BIND_ACTION_URL_CANCEL, m_ctrl, XKB_KEY_c},
|
{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_g}}},
|
||||||
{BIND_ACTION_URL_CANCEL, m_ctrl, XKB_KEY_d},
|
{BIND_ACTION_URL_CANCEL, m_ctrl, {{XKB_KEY_d}}},
|
||||||
{BIND_ACTION_URL_CANCEL, m_none, XKB_KEY_Escape},
|
{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_TOGGLE_URL_ON_JUMP_LABEL, m_none, {{XKB_KEY_t}}},
|
||||||
};
|
};
|
||||||
|
|
||||||
conf->bindings.url.count = ALEN(bindings);
|
conf->bindings.url.count = ALEN(bindings);
|
||||||
|
|
@ -2825,15 +2667,15 @@ add_default_url_bindings(struct config *conf)
|
||||||
static void
|
static void
|
||||||
add_default_mouse_bindings(struct config *conf)
|
add_default_mouse_bindings(struct config *conf)
|
||||||
{
|
{
|
||||||
static const struct config_mouse_binding bindings[] = {
|
static const struct config_key_binding bindings[] = {
|
||||||
{BIND_ACTION_PRIMARY_PASTE, m_none, BTN_MIDDLE, 1},
|
{BIND_ACTION_PRIMARY_PASTE, m_none, {.m = {BTN_MIDDLE, 1}}},
|
||||||
{BIND_ACTION_SELECT_BEGIN, m_none, BTN_LEFT, 1},
|
{BIND_ACTION_SELECT_BEGIN, m_none, {.m = {BTN_LEFT, 1}}},
|
||||||
{BIND_ACTION_SELECT_BEGIN_BLOCK, m_ctrl, BTN_LEFT, 1},
|
{BIND_ACTION_SELECT_BEGIN_BLOCK, m_ctrl, {.m = {BTN_LEFT, 1}}},
|
||||||
{BIND_ACTION_SELECT_EXTEND, m_none, BTN_RIGHT, 1},
|
{BIND_ACTION_SELECT_EXTEND, m_none, {.m = {BTN_RIGHT, 1}}},
|
||||||
{BIND_ACTION_SELECT_EXTEND_CHAR_WISE, m_ctrl, BTN_RIGHT, 1},
|
{BIND_ACTION_SELECT_EXTEND_CHAR_WISE, m_ctrl, {.m = {BTN_RIGHT, 1}}},
|
||||||
{BIND_ACTION_SELECT_WORD, m_none, BTN_LEFT, 2},
|
{BIND_ACTION_SELECT_WORD, m_none, {.m = {BTN_LEFT, 2}}},
|
||||||
{BIND_ACTION_SELECT_WORD_WS, m_ctrl, BTN_LEFT, 2},
|
{BIND_ACTION_SELECT_WORD_WS, m_ctrl, {.m = {BTN_LEFT, 2}}},
|
||||||
{BIND_ACTION_SELECT_ROW, m_none, BTN_LEFT, 3},
|
{BIND_ACTION_SELECT_ROW, m_none, {.m = {BTN_LEFT, 3}}},
|
||||||
};
|
};
|
||||||
|
|
||||||
conf->bindings.mouse.count = ALEN(bindings);
|
conf->bindings.mouse.count = ALEN(bindings);
|
||||||
|
|
@ -3066,16 +2908,16 @@ config_load(struct config *conf, const char *conf_path,
|
||||||
if (ret &&
|
if (ret &&
|
||||||
(!resolve_key_binding_collisions(
|
(!resolve_key_binding_collisions(
|
||||||
conf, section_info[SECTION_KEY_BINDINGS].name,
|
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(
|
!resolve_key_binding_collisions(
|
||||||
conf, section_info[SECTION_SEARCH_BINDINGS].name,
|
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(
|
!resolve_key_binding_collisions(
|
||||||
conf, section_info[SECTION_URL_BINDINGS].name,
|
conf, section_info[SECTION_URL_BINDINGS].name,
|
||||||
url_binding_action_map, &conf->bindings.url) ||
|
url_binding_action_map, &conf->bindings.url, KEY_BINDING) ||
|
||||||
!resolve_mouse_binding_collisions(
|
!resolve_key_binding_collisions(
|
||||||
conf, section_info[SECTION_MOUSE_BINDINGS].name,
|
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;
|
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 *
|
struct config *
|
||||||
config_clone(const struct config *old)
|
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.key, &old->bindings.key);
|
||||||
key_binding_list_clone(&conf->bindings.search, &old->bindings.search);
|
key_binding_list_clone(&conf->bindings.search, &old->bindings.search);
|
||||||
key_binding_list_clone(&conf->bindings.url, &old->bindings.url);
|
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.length = 0;
|
||||||
conf->notifications.head = conf->notifications.tail = 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.key);
|
||||||
free_key_binding_list(&conf.bindings.search);
|
free_key_binding_list(&conf.bindings.search);
|
||||||
free_key_binding_list(&conf.bindings.url);
|
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);
|
user_notifications_free(&conf.notifications);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
23
config.h
23
config.h
|
|
@ -40,10 +40,27 @@ struct config_binding_pipe {
|
||||||
bool master_copy;
|
bool master_copy;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum config_key_binding_type {
|
||||||
|
KEY_BINDING,
|
||||||
|
MOUSE_BINDING,
|
||||||
|
};
|
||||||
|
|
||||||
struct config_key_binding {
|
struct config_key_binding {
|
||||||
int action; /* One of the varios bind_action_* enums from wayland.h */
|
int action; /* One of the varios bind_action_* enums from wayland.h */
|
||||||
struct config_key_modifiers modifiers;
|
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;
|
struct config_binding_pipe pipe;
|
||||||
|
|
||||||
/* For error messages in collision handling */
|
/* For error messages in collision handling */
|
||||||
|
|
@ -52,6 +69,7 @@ struct config_key_binding {
|
||||||
};
|
};
|
||||||
DEFINE_LIST(struct config_key_binding);
|
DEFINE_LIST(struct config_key_binding);
|
||||||
|
|
||||||
|
#if 0
|
||||||
struct config_mouse_binding {
|
struct config_mouse_binding {
|
||||||
enum bind_action_normal action;
|
enum bind_action_normal action;
|
||||||
struct config_key_modifiers modifiers;
|
struct config_key_modifiers modifiers;
|
||||||
|
|
@ -64,6 +82,7 @@ struct config_mouse_binding {
|
||||||
int lineno;
|
int lineno;
|
||||||
};
|
};
|
||||||
DEFINE_LIST(struct config_mouse_binding);
|
DEFINE_LIST(struct config_mouse_binding);
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef tll(char *) config_override_t;
|
typedef tll(char *) config_override_t;
|
||||||
|
|
||||||
|
|
@ -207,7 +226,7 @@ struct config {
|
||||||
struct {
|
struct {
|
||||||
/* Bindings for "normal" mode */
|
/* Bindings for "normal" mode */
|
||||||
struct config_key_binding_list key;
|
struct config_key_binding_list key;
|
||||||
struct config_mouse_binding_list mouse;
|
struct config_key_binding_list mouse;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Special modes
|
* Special modes
|
||||||
|
|
|
||||||
22
input.c
22
input.c
|
|
@ -520,7 +520,7 @@ convert_key_binding(const struct seat *seat,
|
||||||
key_binding_list_t *bindings)
|
key_binding_list_t *bindings)
|
||||||
{
|
{
|
||||||
xkb_mod_mask_t mods = conf_modifiers_to_mask(seat, &conf_binding->modifiers);
|
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 = {
|
struct key_binding binding = {
|
||||||
.mods = mods,
|
.mods = mods,
|
||||||
|
|
@ -561,13 +561,13 @@ convert_url_bindings(const struct config *conf, struct seat *seat)
|
||||||
|
|
||||||
static void
|
static void
|
||||||
convert_mouse_binding(struct seat *seat,
|
convert_mouse_binding(struct seat *seat,
|
||||||
const struct config_mouse_binding *conf_binding)
|
const struct config_key_binding *conf_binding)
|
||||||
{
|
{
|
||||||
struct mouse_binding binding = {
|
struct mouse_binding binding = {
|
||||||
.action = conf_binding->action,
|
.action = conf_binding->action,
|
||||||
.mods = conf_modifiers_to_mask(seat, &conf_binding->modifiers),
|
.mods = conf_modifiers_to_mask(seat, &conf_binding->modifiers),
|
||||||
.button = conf_binding->button,
|
.button = conf_binding->m.button,
|
||||||
.count = conf_binding->count,
|
.count = conf_binding->m.count,
|
||||||
.pipe_argv = conf_binding->pipe.argv.args,
|
.pipe_argv = conf_binding->pipe.argv.args,
|
||||||
};
|
};
|
||||||
tll_push_back(seat->mouse.bindings, binding);
|
tll_push_back(seat->mouse.bindings, binding);
|
||||||
|
|
@ -577,9 +577,7 @@ static void
|
||||||
convert_mouse_bindings(const struct config *conf, struct seat *seat)
|
convert_mouse_bindings(const struct config *conf, struct seat *seat)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < conf->bindings.mouse.count; i++) {
|
for (size_t i = 0; i < conf->bindings.mouse.count; i++) {
|
||||||
const struct config_mouse_binding *binding = &conf->bindings.mouse.arr[i];
|
const struct config_key_binding *binding = &conf->bindings.mouse.arr[i];
|
||||||
if (binding->action == BIND_ACTION_NONE)
|
|
||||||
continue;
|
|
||||||
convert_mouse_binding(seat, binding);
|
convert_mouse_binding(seat, binding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2543,19 +2541,19 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
|
||||||
|
|
||||||
else {
|
else {
|
||||||
/* Seat does NOT have a keyboard - use mouse bindings *without* modifiers */
|
/* 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;
|
const struct config *conf = seat->wayl->conf;
|
||||||
|
|
||||||
for (size_t i = 0; i < conf->bindings.mouse.count; i++) {
|
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];
|
&conf->bindings.mouse.arr[i];
|
||||||
|
|
||||||
if (binding->button != button) {
|
if (binding->m.button != button) {
|
||||||
/* Wrong button */
|
/* Wrong button */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (binding->count > seat->mouse.count) {
|
if (binding->m.count > seat->mouse.count) {
|
||||||
/* Incorrect click count */
|
/* Incorrect click count */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -2566,7 +2564,7 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match == NULL || binding->count > match->count)
|
if (match == NULL || binding->m.count > match->m.count)
|
||||||
match = binding;
|
match = binding;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue