mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-04 04:06:06 -05:00
key-binding: recognize virtual modifiers, and translate to the corresponding real modifier.
This commit is contained in:
parent
58910856c8
commit
dc99cf7358
2 changed files with 90 additions and 9 deletions
|
|
@ -68,8 +68,9 @@
|
|||
colors has not configured) is now done by linear RGB interpolation,
|
||||
rather than converting to HSL and adjusting the luminance
|
||||
([#2006][2006]).
|
||||
* XKB: virtual modifiers are now ignored. This works around various
|
||||
issues seen when running foot under mutter (GNOME) ([#2009][2009]):
|
||||
* XKB: virtual modifiers in keyboard events from the compositor are
|
||||
now ignored. This works around various issues seen when running foot
|
||||
under mutter (GNOME) ([#2009][2009]):
|
||||
- Some key combinations generating the wrong escape sequence in the
|
||||
kitty keyboard protocol.
|
||||
- some of foot's default shortcuts not working (mainly those using
|
||||
|
|
@ -79,6 +80,10 @@
|
|||
`NumLock`, `ScrollLock`, `LevelThree` or `LevelFive` modifiers,
|
||||
you need to update them; i.e. remove the virtual modifier(s),
|
||||
leaving only the real modifiers (`Mod1`, `Mod2` etc).**
|
||||
* Virtual modifiers (e.g. `Alt` instead of `Mod1`, `Super` instead of
|
||||
`Mod4` etc) in key bindings are now recognized as being virtual, and
|
||||
are automatically mapped to the corresponding real modifier. This
|
||||
means you can use e.g. `Alt+b` instead of `Mod1+b`.
|
||||
|
||||
[2006]: https://codeberg.org/dnkl/foot/issues/2006
|
||||
[2009]: https://codeberg.org/dnkl/foot/issues/2009
|
||||
|
|
|
|||
|
|
@ -13,12 +13,21 @@
|
|||
#include "wayland.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
struct vmod_map {
|
||||
const char *name;
|
||||
xkb_mod_mask_t virtual_mask;
|
||||
xkb_mod_mask_t real_mask;
|
||||
};
|
||||
|
||||
struct key_set {
|
||||
struct key_binding_set public;
|
||||
|
||||
const struct config *conf;
|
||||
const struct seat *seat;
|
||||
size_t conf_ref_count;
|
||||
|
||||
/* Virtual to real modifier mappings */
|
||||
struct vmod_map vmods[8];
|
||||
};
|
||||
typedef tll(struct key_set) bind_set_list_t;
|
||||
|
||||
|
|
@ -44,6 +53,50 @@ key_binding_manager_destroy(struct key_binding_manager *mgr)
|
|||
free(mgr);
|
||||
}
|
||||
|
||||
static void
|
||||
initialize_vmod_mappings(struct key_set *set)
|
||||
{
|
||||
if (set->seat == NULL || set->seat->kbd.xkb_keymap == NULL)
|
||||
return;
|
||||
|
||||
set->vmods[0].name = XKB_VMOD_NAME_ALT;
|
||||
set->vmods[1].name = XKB_VMOD_NAME_HYPER;
|
||||
set->vmods[2].name = XKB_VMOD_NAME_LEVEL3;
|
||||
set->vmods[3].name = XKB_VMOD_NAME_LEVEL5;
|
||||
set->vmods[4].name = XKB_VMOD_NAME_META;
|
||||
set->vmods[5].name = XKB_VMOD_NAME_NUM;
|
||||
set->vmods[6].name = XKB_VMOD_NAME_SCROLL;
|
||||
set->vmods[7].name = XKB_VMOD_NAME_SUPER;
|
||||
|
||||
struct xkb_state *scratch_state = xkb_state_new(set->seat->kbd.xkb_keymap);
|
||||
xassert(scratch_state != NULL);
|
||||
|
||||
for (size_t i = 0; i < ALEN(set->vmods); i++) {
|
||||
xkb_mod_index_t virt_idx = xkb_keymap_mod_get_index(
|
||||
set->seat->kbd.xkb_keymap, set->vmods[i].name);
|
||||
|
||||
if (virt_idx != XKB_MOD_INVALID) {
|
||||
xkb_mod_mask_t vmask = 1 << virt_idx;
|
||||
xkb_state_update_mask(scratch_state, vmask, 0, 0, 0, 0, 0);
|
||||
set->vmods[i].real_mask = xkb_state_serialize_mods(
|
||||
scratch_state, XKB_STATE_MODS_DEPRESSED) & ~vmask;
|
||||
set->vmods[i].virtual_mask = vmask;
|
||||
|
||||
LOG_DBG("%s: 0x%04x -> 0x%04x",
|
||||
set->vmods[i].name,
|
||||
set->vmods[i].virtual_mask,
|
||||
set->vmods[i].real_mask);
|
||||
} else {
|
||||
set->vmods[i].virtual_mask = 0;
|
||||
set->vmods[i].real_mask = 0;
|
||||
|
||||
LOG_DBG("%s: virtual modifier not available", set->vmods[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
xkb_state_unref(scratch_state);
|
||||
}
|
||||
|
||||
void
|
||||
key_binding_new_for_seat(struct key_binding_manager *mgr,
|
||||
const struct seat *seat)
|
||||
|
|
@ -67,6 +120,7 @@ key_binding_new_for_seat(struct key_binding_manager *mgr,
|
|||
};
|
||||
|
||||
tll_push_back(mgr->binding_sets, set);
|
||||
initialize_vmod_mappings(&tll_back(mgr->binding_sets));
|
||||
|
||||
LOG_DBG("new (seat): set=%p, seat=%p, conf=%p, ref-count=1",
|
||||
(void *)&tll_back(mgr->binding_sets),
|
||||
|
|
@ -107,6 +161,7 @@ key_binding_new_for_conf(struct key_binding_manager *mgr,
|
|||
};
|
||||
|
||||
tll_push_back(mgr->binding_sets, set);
|
||||
initialize_vmod_mappings(&tll_back(mgr->binding_sets));
|
||||
|
||||
load_keymap(&tll_back(mgr->binding_sets));
|
||||
|
||||
|
|
@ -405,18 +460,35 @@ sort_binding_list(key_binding_list_t *list)
|
|||
}
|
||||
|
||||
static xkb_mod_mask_t
|
||||
mods_to_mask(const struct seat *seat, const config_modifier_list_t *mods)
|
||||
mods_to_mask(const struct seat *seat,
|
||||
const struct vmod_map *vmods, size_t vmod_count,
|
||||
const config_modifier_list_t *mods)
|
||||
{
|
||||
xkb_mod_mask_t mask = 0;
|
||||
tll_foreach(*mods, it) {
|
||||
xkb_mod_index_t idx = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, it->item);
|
||||
const xkb_mod_index_t idx = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, it->item);
|
||||
|
||||
if (idx == XKB_MOD_INVALID) {
|
||||
LOG_ERR("%s: invalid modifier name", it->item);
|
||||
continue;
|
||||
}
|
||||
|
||||
mask |= 1 << idx;
|
||||
xkb_mod_mask_t mod = 1 << idx;
|
||||
|
||||
/* Check if this is a virtual modifier, and if so, use the
|
||||
real modifier it maps to instead */
|
||||
for (size_t i = 0; i < vmod_count; i++) {
|
||||
if (vmods[i].virtual_mask == mod) {
|
||||
mask |= vmods[i].real_mask;
|
||||
mod = 0;
|
||||
|
||||
LOG_DBG("%s: virtual modifier, mapped to 0x%04x",
|
||||
it->item, vmods[i].real_mask);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mask |= mod;
|
||||
}
|
||||
|
||||
return mask;
|
||||
|
|
@ -429,7 +501,8 @@ convert_key_binding(struct key_set *set,
|
|||
{
|
||||
const struct seat *seat = set->seat;
|
||||
|
||||
xkb_mod_mask_t mods = mods_to_mask(seat, &conf_binding->modifiers);
|
||||
xkb_mod_mask_t mods = mods_to_mask(
|
||||
seat, set->vmods, ALEN(set->vmods), &conf_binding->modifiers);
|
||||
xkb_keysym_t sym = maybe_repair_key_combo(seat, conf_binding->k.sym, mods);
|
||||
|
||||
struct key_binding binding = {
|
||||
|
|
@ -487,7 +560,7 @@ convert_mouse_binding(struct key_set *set,
|
|||
.type = MOUSE_BINDING,
|
||||
.action = conf_binding->action,
|
||||
.aux = &conf_binding->aux,
|
||||
.mods = mods_to_mask(set->seat, &conf_binding->modifiers),
|
||||
.mods = mods_to_mask(set->seat, set->vmods, ALEN(set->vmods), &conf_binding->modifiers),
|
||||
.m = {
|
||||
.button = conf_binding->m.button,
|
||||
.count = conf_binding->m.count,
|
||||
|
|
@ -528,7 +601,8 @@ load_keymap(struct key_set *set)
|
|||
convert_mouse_bindings(set);
|
||||
|
||||
set->public.selection_overrides = mods_to_mask(
|
||||
set->seat, &set->conf->mouse.selection_override_modifiers);
|
||||
set->seat, set->vmods, ALEN(set->vmods),
|
||||
&set->conf->mouse.selection_override_modifiers);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -538,8 +612,10 @@ key_binding_load_keymap(struct key_binding_manager *mgr,
|
|||
tll_foreach(mgr->binding_sets, it) {
|
||||
struct key_set *set = &it->item;
|
||||
|
||||
if (set->seat == seat)
|
||||
if (set->seat == seat) {
|
||||
initialize_vmod_mappings(set);
|
||||
load_keymap(set);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue