mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-05 04:06:08 -05:00
config/input: implement mouse bindings
* New config section, "mouse-bindings", where bindings are defined on the form "action=BTN_<name> * pointer_button() handler now scans the bindings list instead of hardcoding primary-paste to BTN_MIDDLE. * The implementation handles single- double- and triple clicks in the bindings, but there is currently no way to define anything but a single-click binding in the configuration.
This commit is contained in:
parent
9fae38a4b2
commit
45384839f0
6 changed files with 94 additions and 20 deletions
61
config.c
61
config.c
|
|
@ -12,6 +12,7 @@
|
|||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <linux/input-event-codes.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
#define LOG_MODULE "config"
|
||||
|
|
@ -448,8 +449,9 @@ parse_section_csd(const char *key, const char *value, struct config *conf,
|
|||
}
|
||||
|
||||
static bool
|
||||
parse_section_key_bindings(const char *key, const char *value, struct config *conf,
|
||||
const char *path, unsigned lineno)
|
||||
parse_section_key_bindings(
|
||||
const char *key, const char *value, struct config *conf,
|
||||
const char *path, unsigned lineno)
|
||||
{
|
||||
for (enum binding_action action = 0; action < BIND_ACTION_COUNT; action++) {
|
||||
if (strcmp(key, binding_action_map[action]) != 0)
|
||||
|
|
@ -459,7 +461,8 @@ parse_section_key_bindings(const char *key, const char *value, struct config *co
|
|||
struct xkb_keymap *keymap = xkb_keymap_new_from_names(
|
||||
ctx, &(struct xkb_rule_names){0}, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
|
||||
bool valid_combo = input_parse_key_binding_for_action(keymap, action, value, NULL);
|
||||
bool valid_combo = input_parse_key_binding_for_action(
|
||||
keymap, action, value, NULL);
|
||||
|
||||
xkb_keymap_unref(keymap);
|
||||
xkb_context_unref(ctx);
|
||||
|
|
@ -479,6 +482,43 @@ parse_section_key_bindings(const char *key, const char *value, struct config *co
|
|||
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_section_mouse_bindings(
|
||||
const char *key, const char *value, struct config *conf,
|
||||
const char *path, unsigned lineno)
|
||||
{
|
||||
for (enum binding_action action = 0; action < BIND_ACTION_COUNT; action++) {
|
||||
if (strcmp(key, binding_action_map[action]) != 0)
|
||||
continue;
|
||||
|
||||
const char *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",
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < ALEN(map); i++) {
|
||||
if (map[i] == NULL || strcmp(map[i], value) != 0)
|
||||
continue;
|
||||
|
||||
conf->bindings.mouse[action] = (struct mouse_binding){i, 1, action};
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG_ERR("%s:%d: invalid mouse button: %s", path, lineno, value);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
LOG_ERR("%s:%u: invalid key: %s", path, lineno, key);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_config_file(FILE *f, struct config *conf, const char *path)
|
||||
{
|
||||
|
|
@ -488,6 +528,7 @@ parse_config_file(FILE *f, struct config *conf, const char *path)
|
|||
SECTION_CURSOR,
|
||||
SECTION_CSD,
|
||||
SECTION_KEY_BINDINGS,
|
||||
SECTION_MOUSE_BINDINGS,
|
||||
SECTION_COUNT,
|
||||
} section = SECTION_MAIN;
|
||||
|
||||
|
|
@ -500,11 +541,12 @@ parse_config_file(FILE *f, struct config *conf, const char *path)
|
|||
parser_fun_t fun;
|
||||
const char *name;
|
||||
} section_info[] = {
|
||||
[SECTION_MAIN] = {&parse_section_main, "main"},
|
||||
[SECTION_COLORS] = {&parse_section_colors, "colors"},
|
||||
[SECTION_CURSOR] = {&parse_section_cursor, "cursor"},
|
||||
[SECTION_CSD] = {&parse_section_csd, "csd"},
|
||||
[SECTION_KEY_BINDINGS] = {&parse_section_key_bindings, "key-bindings"},
|
||||
[SECTION_MAIN] = {&parse_section_main, "main"},
|
||||
[SECTION_COLORS] = {&parse_section_colors, "colors"},
|
||||
[SECTION_CURSOR] = {&parse_section_cursor, "cursor"},
|
||||
[SECTION_CSD] = {&parse_section_csd, "csd"},
|
||||
[SECTION_KEY_BINDINGS] = {&parse_section_key_bindings, "key-bindings"},
|
||||
[SECTION_MOUSE_BINDINGS] = {&parse_section_mouse_bindings, "mouse-bindings"},
|
||||
};
|
||||
|
||||
static_assert(ALEN(section_info) == SECTION_COUNT, "section info array size mismatch");
|
||||
|
|
@ -699,7 +741,7 @@ config_load(struct config *conf, const char *conf_path)
|
|||
[BIND_ACTION_SPAWN_TERMINAL] = strdup("Control+Shift+Return"),
|
||||
},
|
||||
.mouse = {
|
||||
[BIND_ACTION_PRIMARY_PASTE] = strdup("BTN_MIDDLE"),
|
||||
[BIND_ACTION_PRIMARY_PASTE] = {BTN_MIDDLE, 1, BIND_ACTION_PRIMARY_PASTE},
|
||||
},
|
||||
.search = {
|
||||
},
|
||||
|
|
@ -760,7 +802,6 @@ config_free(struct config conf)
|
|||
|
||||
for (size_t i = 0; i < BIND_ACTION_COUNT; i++) {
|
||||
free(conf.bindings.key[i]);
|
||||
free(conf.bindings.mouse[i]);
|
||||
free(conf.bindings.search[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
config.h
2
config.h
|
|
@ -39,7 +39,7 @@ struct config {
|
|||
struct {
|
||||
/* Bindings for "normal" mode */
|
||||
char *key[BIND_ACTION_COUNT];
|
||||
char *mouse[BIND_ACTION_COUNT];
|
||||
struct mouse_binding mouse[BIND_ACTION_COUNT];
|
||||
|
||||
/*
|
||||
* Special modes
|
||||
|
|
|
|||
|
|
@ -203,6 +203,18 @@ Note that _Alt_ is usually called *Mod1*.
|
|||
*fullscreen*
|
||||
Toggles the fullscreen state. Default: _not bound_.
|
||||
|
||||
# SECTION: mouse-bindings
|
||||
|
||||
This section lets you override the default mouse bindings.
|
||||
|
||||
The general format is *action*=*BTN\_<name>*, where *BTN\_<name>* is
|
||||
the name of the event code (e.g. *BTN\_LEFT*, *BTN\_RIGHT*). You can
|
||||
find the event names using *libinput debug-events*.
|
||||
|
||||
*primary-paste*
|
||||
Pastes from the _primary selection_. Default: _BTN_MIDDLE_.
|
||||
|
||||
|
||||
# FONT FORMAT
|
||||
|
||||
The font is specified in FontConfig syntax. That is, a colon-separated
|
||||
|
|
|
|||
3
footrc
3
footrc
|
|
@ -56,3 +56,6 @@
|
|||
# # minimize=<not bound>
|
||||
# # maximize=<not bound>
|
||||
# # fullscreen=<not bound>
|
||||
|
||||
[mouse-bindings]
|
||||
# primary-paste=BTN_MIDDLE
|
||||
|
|
|
|||
30
input.c
30
input.c
|
|
@ -31,6 +31,8 @@
|
|||
#include "terminal.h"
|
||||
#include "vt.h"
|
||||
|
||||
#define ALEN(v) (sizeof(v) / sizeof(v[0]))
|
||||
|
||||
void
|
||||
input_execute_binding(struct terminal *term, enum binding_action action,
|
||||
uint32_t serial)
|
||||
|
|
@ -54,8 +56,7 @@ input_execute_binding(struct terminal *term, enum binding_action action,
|
|||
break;
|
||||
|
||||
case BIND_ACTION_PRIMARY_PASTE:
|
||||
LOG_ERR("unimplemented");
|
||||
assert(false);
|
||||
selection_from_primary(term);
|
||||
break;
|
||||
|
||||
case BIND_ACTION_SEARCH_START:
|
||||
|
|
@ -321,7 +322,6 @@ keyboard_leave(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
|||
static const struct key_data *
|
||||
keymap_data_for_sym(xkb_keysym_t sym, size_t *count)
|
||||
{
|
||||
#define ALEN(a) (sizeof(a) / sizeof(a[0]))
|
||||
switch (sym) {
|
||||
case XKB_KEY_Escape: *count = ALEN(key_escape); return key_escape;
|
||||
case XKB_KEY_Return: *count = ALEN(key_return); return key_return;
|
||||
|
|
@ -402,7 +402,6 @@ keymap_data_for_sym(xkb_keysym_t sym, size_t *count)
|
|||
case XKB_KEY_KP_9: *count = ALEN(key_kp_9); return key_kp_9;
|
||||
}
|
||||
|
||||
#undef ALEN
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -1151,11 +1150,24 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
|
|||
selection_mark_row(term, wayl->mouse.row, serial);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (wayl->mouse.count == 1 && button == BTN_MIDDLE &&
|
||||
selection_enabled(term))
|
||||
{
|
||||
selection_from_primary(term);
|
||||
}
|
||||
|
||||
else {
|
||||
for (size_t i = 0; i < ALEN(wayl->conf->bindings.mouse); i++) {
|
||||
const struct mouse_binding *binding =
|
||||
&wayl->conf->bindings.mouse[i];
|
||||
|
||||
if (binding->button != button) {
|
||||
/* Wrong button */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (binding->count != wayl->mouse.count) {
|
||||
/* Not correct click count */
|
||||
continue;
|
||||
}
|
||||
|
||||
input_execute_binding(term, binding->action, serial);
|
||||
}
|
||||
selection_cancel(term);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,6 +65,12 @@ struct key_binding {
|
|||
};
|
||||
typedef tll(struct key_binding) key_binding_list_t;
|
||||
|
||||
struct mouse_binding {
|
||||
uint32_t button;
|
||||
int count;
|
||||
enum binding_action action;
|
||||
};
|
||||
|
||||
struct kbd {
|
||||
struct xkb_context *xkb;
|
||||
struct xkb_keymap *xkb_keymap;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue