mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-04-01 07:15:32 -04: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 <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <linux/input-event-codes.h>
|
||||||
#include <xkbcommon/xkbcommon.h>
|
#include <xkbcommon/xkbcommon.h>
|
||||||
|
|
||||||
#define LOG_MODULE "config"
|
#define LOG_MODULE "config"
|
||||||
|
|
@ -448,8 +449,9 @@ parse_section_csd(const char *key, const char *value, struct config *conf,
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
parse_section_key_bindings(const char *key, const char *value, struct config *conf,
|
parse_section_key_bindings(
|
||||||
const char *path, unsigned lineno)
|
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++) {
|
for (enum binding_action action = 0; action < BIND_ACTION_COUNT; action++) {
|
||||||
if (strcmp(key, binding_action_map[action]) != 0)
|
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(
|
struct xkb_keymap *keymap = xkb_keymap_new_from_names(
|
||||||
ctx, &(struct xkb_rule_names){0}, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
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_keymap_unref(keymap);
|
||||||
xkb_context_unref(ctx);
|
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
|
static bool
|
||||||
parse_config_file(FILE *f, struct config *conf, const char *path)
|
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_CURSOR,
|
||||||
SECTION_CSD,
|
SECTION_CSD,
|
||||||
SECTION_KEY_BINDINGS,
|
SECTION_KEY_BINDINGS,
|
||||||
|
SECTION_MOUSE_BINDINGS,
|
||||||
SECTION_COUNT,
|
SECTION_COUNT,
|
||||||
} section = SECTION_MAIN;
|
} section = SECTION_MAIN;
|
||||||
|
|
||||||
|
|
@ -500,11 +541,12 @@ parse_config_file(FILE *f, struct config *conf, const char *path)
|
||||||
parser_fun_t fun;
|
parser_fun_t fun;
|
||||||
const char *name;
|
const char *name;
|
||||||
} section_info[] = {
|
} section_info[] = {
|
||||||
[SECTION_MAIN] = {&parse_section_main, "main"},
|
[SECTION_MAIN] = {&parse_section_main, "main"},
|
||||||
[SECTION_COLORS] = {&parse_section_colors, "colors"},
|
[SECTION_COLORS] = {&parse_section_colors, "colors"},
|
||||||
[SECTION_CURSOR] = {&parse_section_cursor, "cursor"},
|
[SECTION_CURSOR] = {&parse_section_cursor, "cursor"},
|
||||||
[SECTION_CSD] = {&parse_section_csd, "csd"},
|
[SECTION_CSD] = {&parse_section_csd, "csd"},
|
||||||
[SECTION_KEY_BINDINGS] = {&parse_section_key_bindings, "key-bindings"},
|
[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");
|
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"),
|
[BIND_ACTION_SPAWN_TERMINAL] = strdup("Control+Shift+Return"),
|
||||||
},
|
},
|
||||||
.mouse = {
|
.mouse = {
|
||||||
[BIND_ACTION_PRIMARY_PASTE] = strdup("BTN_MIDDLE"),
|
[BIND_ACTION_PRIMARY_PASTE] = {BTN_MIDDLE, 1, BIND_ACTION_PRIMARY_PASTE},
|
||||||
},
|
},
|
||||||
.search = {
|
.search = {
|
||||||
},
|
},
|
||||||
|
|
@ -760,7 +802,6 @@ config_free(struct config conf)
|
||||||
|
|
||||||
for (size_t i = 0; i < BIND_ACTION_COUNT; i++) {
|
for (size_t i = 0; i < BIND_ACTION_COUNT; i++) {
|
||||||
free(conf.bindings.key[i]);
|
free(conf.bindings.key[i]);
|
||||||
free(conf.bindings.mouse[i]);
|
|
||||||
free(conf.bindings.search[i]);
|
free(conf.bindings.search[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
config.h
2
config.h
|
|
@ -39,7 +39,7 @@ struct config {
|
||||||
struct {
|
struct {
|
||||||
/* Bindings for "normal" mode */
|
/* Bindings for "normal" mode */
|
||||||
char *key[BIND_ACTION_COUNT];
|
char *key[BIND_ACTION_COUNT];
|
||||||
char *mouse[BIND_ACTION_COUNT];
|
struct mouse_binding mouse[BIND_ACTION_COUNT];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Special modes
|
* Special modes
|
||||||
|
|
|
||||||
|
|
@ -203,6 +203,18 @@ Note that _Alt_ is usually called *Mod1*.
|
||||||
*fullscreen*
|
*fullscreen*
|
||||||
Toggles the fullscreen state. Default: _not bound_.
|
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
|
# FONT FORMAT
|
||||||
|
|
||||||
The font is specified in FontConfig syntax. That is, a colon-separated
|
The font is specified in FontConfig syntax. That is, a colon-separated
|
||||||
|
|
|
||||||
3
footrc
3
footrc
|
|
@ -56,3 +56,6 @@
|
||||||
# # minimize=<not bound>
|
# # minimize=<not bound>
|
||||||
# # maximize=<not bound>
|
# # maximize=<not bound>
|
||||||
# # fullscreen=<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 "terminal.h"
|
||||||
#include "vt.h"
|
#include "vt.h"
|
||||||
|
|
||||||
|
#define ALEN(v) (sizeof(v) / sizeof(v[0]))
|
||||||
|
|
||||||
void
|
void
|
||||||
input_execute_binding(struct terminal *term, enum binding_action action,
|
input_execute_binding(struct terminal *term, enum binding_action action,
|
||||||
uint32_t serial)
|
uint32_t serial)
|
||||||
|
|
@ -54,8 +56,7 @@ input_execute_binding(struct terminal *term, enum binding_action action,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BIND_ACTION_PRIMARY_PASTE:
|
case BIND_ACTION_PRIMARY_PASTE:
|
||||||
LOG_ERR("unimplemented");
|
selection_from_primary(term);
|
||||||
assert(false);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BIND_ACTION_SEARCH_START:
|
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 *
|
static const struct key_data *
|
||||||
keymap_data_for_sym(xkb_keysym_t sym, size_t *count)
|
keymap_data_for_sym(xkb_keysym_t sym, size_t *count)
|
||||||
{
|
{
|
||||||
#define ALEN(a) (sizeof(a) / sizeof(a[0]))
|
|
||||||
switch (sym) {
|
switch (sym) {
|
||||||
case XKB_KEY_Escape: *count = ALEN(key_escape); return key_escape;
|
case XKB_KEY_Escape: *count = ALEN(key_escape); return key_escape;
|
||||||
case XKB_KEY_Return: *count = ALEN(key_return); return key_return;
|
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;
|
case XKB_KEY_KP_9: *count = ALEN(key_kp_9); return key_kp_9;
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef ALEN
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1151,11 +1150,24 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
|
||||||
selection_mark_row(term, wayl->mouse.row, serial);
|
selection_mark_row(term, wayl->mouse.row, serial);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if (wayl->mouse.count == 1 && button == BTN_MIDDLE &&
|
|
||||||
selection_enabled(term))
|
else {
|
||||||
{
|
for (size_t i = 0; i < ALEN(wayl->conf->bindings.mouse); i++) {
|
||||||
selection_from_primary(term);
|
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);
|
selection_cancel(term);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,12 @@ struct key_binding {
|
||||||
};
|
};
|
||||||
typedef tll(struct key_binding) key_binding_list_t;
|
typedef tll(struct key_binding) key_binding_list_t;
|
||||||
|
|
||||||
|
struct mouse_binding {
|
||||||
|
uint32_t button;
|
||||||
|
int count;
|
||||||
|
enum binding_action action;
|
||||||
|
};
|
||||||
|
|
||||||
struct kbd {
|
struct kbd {
|
||||||
struct xkb_context *xkb;
|
struct xkb_context *xkb;
|
||||||
struct xkb_keymap *xkb_keymap;
|
struct xkb_keymap *xkb_keymap;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue