mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-04 04:06:06 -05:00
input: kitty: update to latest version of the spec
Starting with kitty 0.32.0, the modifier bits during modifier key events behave differently, compared to before. Or, rather, they have now been spec:ed; before, behavior was different on e.g. MacOS, and Linux. The new behavior is this: On key press, the modifier bits in the kitty key event *includes* the pressed modifier key. On key release, the modifier bits in the kitty key event does *not* include the released modifier key. In other words, The modifier bits reflects the state *after* the key event. This is the exact opposite of what foot did before this patch. The patch is really pretty small: in order to include the key in the modifier set, we simulate a key press to update the XKB state, using xkb_state_uppate_key(). For key pressed, we simulate an XKB_KEY_DOWN event, and for key releases we simulate an XKB_KEY_UP event. Then we re-retrieve the modifers, both the full set, and the consumed set. Closes #1561
This commit is contained in:
parent
6ed1c28d2c
commit
4ee4f47065
2 changed files with 71 additions and 14 deletions
|
|
@ -65,9 +65,14 @@
|
|||
process. This ensures the terminal itself does not "lock" a
|
||||
directory; for example, preventing a mount point from being
|
||||
unmounted ([#1528][1528]).
|
||||
* Kitty keyboard protocol: updated behavior of modifiers bits during
|
||||
modifier key events, to match the (new [#6913][kitty-6913]) behavior
|
||||
in kitty >= 0.32.0 ([#1561][1561]).
|
||||
|
||||
[1526]: https://codeberg.org/dnkl/foot/issues/1526
|
||||
[1528]: https://codeberg.org/dnkl/foot/issues/1528
|
||||
[1561]: https://codeberg.org/dnkl/foot/issues/1561
|
||||
[kitty-6913]: https://github.com/kovidgoyal/kitty/issues/6913
|
||||
|
||||
|
||||
### Deprecated
|
||||
|
|
|
|||
80
input.c
80
input.c
|
|
@ -1135,19 +1135,77 @@ kitty_kbd_protocol(struct seat *seat, struct terminal *term,
|
|||
if (!disambiguate && !report_all_as_escapes && pressed)
|
||||
return legacy_kbd_protocol(seat, term, ctx);
|
||||
|
||||
const xkb_mod_mask_t mods = ctx->mods & seat->kbd.kitty_significant;
|
||||
const xkb_mod_mask_t consumed = xkb_state_key_get_consumed_mods2(
|
||||
seat->kbd.xkb_state, ctx->key, XKB_CONSUMED_MODE_GTK) & seat->kbd.kitty_significant;
|
||||
const xkb_mod_mask_t effective = mods & ~consumed;
|
||||
const xkb_mod_mask_t caps_num =
|
||||
(seat->kbd.mod_caps != XKB_MOD_INVALID ? 1 << seat->kbd.mod_caps : 0) |
|
||||
(seat->kbd.mod_num != XKB_MOD_INVALID ? 1 << seat->kbd.mod_num : 0);
|
||||
|
||||
const xkb_keysym_t sym = ctx->sym;
|
||||
const uint32_t *utf32 = ctx->utf32;
|
||||
const uint8_t *const utf8 = ctx->utf8.buf;
|
||||
const size_t count = ctx->utf8.count;
|
||||
|
||||
/* Lookup sym in the pre-defined keysym table */
|
||||
const struct kitty_key_data *info = bsearch(
|
||||
&sym, kitty_keymap, ALEN(kitty_keymap), sizeof(kitty_keymap[0]),
|
||||
&kitty_search);
|
||||
xassert(info == NULL || info->sym == sym);
|
||||
|
||||
xkb_mod_mask_t mods = 0;
|
||||
xkb_mod_mask_t consumed = 0;
|
||||
|
||||
if (info != NULL && info->is_modifier) {
|
||||
/*
|
||||
* Special-case modifier keys.
|
||||
*
|
||||
* Normally, the "current" XKB state reflects the state
|
||||
* *before* the current key event. In other words, the
|
||||
* modifiers for key events that affect the modifier state
|
||||
* (e.g. one of the control keys, or shift keys etc) does
|
||||
* *not* include the key itself.
|
||||
*
|
||||
* Put another way, if you press "control", the modifier set
|
||||
* is empty in the key press event, but contains "ctrl" in the
|
||||
* release event.
|
||||
*
|
||||
* The kitty protocol mandates the modifier list contain the
|
||||
* key itself, in *both* the press and release event.
|
||||
*
|
||||
* We handle this by updating the XKB state to *include* the
|
||||
* current key, retrieve the set of modifiers (including the
|
||||
* set of consumed modifiers), and then revert the XKB update.
|
||||
*/
|
||||
xkb_state_update_key(
|
||||
seat->kbd.xkb_state, ctx->key, pressed ? XKB_KEY_DOWN : XKB_KEY_UP);
|
||||
|
||||
get_current_modifiers(seat, &mods, NULL, ctx->key);
|
||||
consumed = xkb_state_key_get_consumed_mods2(
|
||||
seat->kbd.xkb_state, ctx->key, XKB_CONSUMED_MODE_GTK);
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* TODO: according to the XKB docs, state updates should
|
||||
* always be in pairs: each press should be followed by a
|
||||
* release. However, doing this just breaks the xkb state.
|
||||
*
|
||||
* *Not* pairing the above press/release with a corresponding
|
||||
* release/press appears to do exactly what we want.
|
||||
*/
|
||||
xkb_state_update_key(
|
||||
seat->kbd.xkb_state, ctx->key, pressed ? XKB_KEY_UP : XKB_KEY_DOWN);
|
||||
#endif
|
||||
} else {
|
||||
mods = ctx->mods;
|
||||
|
||||
/* Re-retrieve the consumed modifiers using the GTK mode, to
|
||||
better match kitty. */
|
||||
consumed = xkb_state_key_get_consumed_mods2(
|
||||
seat->kbd.xkb_state, ctx->key, XKB_CONSUMED_MODE_GTK);
|
||||
}
|
||||
|
||||
mods &= seat->kbd.kitty_significant;
|
||||
consumed &= seat->kbd.kitty_significant;
|
||||
|
||||
const xkb_mod_mask_t effective = mods & ~consumed;
|
||||
const xkb_mod_mask_t caps_num =
|
||||
(seat->kbd.mod_caps != XKB_MOD_INVALID ? 1 << seat->kbd.mod_caps : 0) |
|
||||
(seat->kbd.mod_num != XKB_MOD_INVALID ? 1 << seat->kbd.mod_num : 0);
|
||||
|
||||
bool is_text = count > 0 && utf32 != NULL && (effective & ~caps_num) == 0;
|
||||
for (size_t i = 0; utf32[i] != U'\0'; i++) {
|
||||
if (!iswprint(utf32[i])) {
|
||||
|
|
@ -1159,12 +1217,6 @@ kitty_kbd_protocol(struct seat *seat, struct terminal *term,
|
|||
const bool report_associated_text =
|
||||
(flags & KITTY_KBD_REPORT_ASSOCIATED) && is_text && !released;
|
||||
|
||||
/* Lookup sym in the pre-defined keysym table */
|
||||
const struct kitty_key_data *info = bsearch(
|
||||
&sym, kitty_keymap, ALEN(kitty_keymap), sizeof(kitty_keymap[0]),
|
||||
&kitty_search);
|
||||
xassert(info == NULL || info->sym == sym);
|
||||
|
||||
if (composing) {
|
||||
/* We never emit anything while composing, *except* modifiers
|
||||
* (and only in report-all-keys-as-escape-codes mode) */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue