input: kitty: improve handling of alternate+base keys even more

* Always do a base key lookup. Before this, we didn't do that if we
  matched the XKB sym to a lookup table entry (i.e. keypads, cursor keys
  etc.)
* Try to retrieve the unshifted symbol also when we matched the symbol
  to a lookup table entry. When successful, we now report an alternate
  key for keypad and cursor keys; before this patch, we only did that
  for keys that didn't have an entry in the lookup table (i.e. ASCII
  chars etc).

This improves compatibility with kitty (and the kitty keyboard
protocol) in more corner cases. One particular example is the neo
keyboard layout, where part of the regular keys act as keypad keys
when num-lock is active.
This commit is contained in:
Daniel Eklöf 2025-01-20 10:34:45 +01:00
parent 2ff38e86a7
commit 786037791c
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F

74
input.c
View file

@ -1279,75 +1279,83 @@ emit_escapes:
int key = -1, alternate = -1, base = -1; int key = -1, alternate = -1, base = -1;
char final; char final;
const bool use_level0_sym =
(ctx->mods & ~seat->kbd.kitty_significant) == 0 && ctx->level0_syms.count > 0;
if (info != NULL) { if (info != NULL) {
if (!info->is_modifier || report_all_as_escapes) { if (!info->is_modifier || report_all_as_escapes) {
key = info->key; key = info->key;
final = info->final; final = info->final;
if (use_level0_sym) {
xkb_keysym_t unshifted = xkb_keysym_to_utf32(ctx->level0_syms.syms[0]);
if (unshifted > 0) {
alternate = key;
key = unshifted;
}
}
} }
} else { } else {
/* /*
* Use keysym (typically its Unicode codepoint value). * Use keysym (typically its Unicode codepoint value).
* *
* If the keysym is shifted, use its unshifted codepoint * If the keysym is shifted, use its unshifted codepoint
* instead. In other words, ctrl+a and ctrl+shift+a should * instead. In other words, ctrl+a and ctrl+shift+a should both
* both use the same value for 'key' (97 - i.a. 'a'). * use the same value for 'key' (97 - i.a. 'a').
* *
* However, don't do this if a non-significant modifier was * However, don't do this if a non-significant modifier was used
* used to generate the symbol. This is needed since we cannot * to generate the symbol. This is needed since we cannot encode
* encode non-significant modifiers, and thus the "extra" * non-significant modifiers, and thus the "extra" modifier(s)
* modifier(s) would get lost. * would get lost.
* *
* Example: * Example:
* *
* the Swedish layout has '2', QUOTATION MARK ("double * the Swedish layout has '2', QUOTATION MARK ("double quote"),
* quote"), '@', and '²' on the same key. '2' is the base * '@', and '²' on the same key. '2' is the base symbol.
* symbol.
* *
* Shift+2 results in QUOTATION MARK * Shift+2 results in QUOTATION MARK
* AltGr+2 results in '@' * AltGr+2 results in '@'
* AltGr+Shift+2 results in '²' * AltGr+Shift+2 results in '²'
* *
* The kitty kbd protocol can't encode AltGr. So, if we * The kitty kbd protocol can't encode AltGr. So, if we always
* always used the base symbol ('2'), Alt+Shift+2 would * used the base symbol ('2'), Alt+Shift+2 would result in the
* result in the same escape sequence as * same escape sequence as AltGr+Alt+Shift+2.
* AltGr+Alt+Shift+2.
* *
* (yes, this matches what kitty does, as of 0.23.1) * (yes, this matches what kitty does, as of 0.23.1)
*/ */
const bool use_level0_sym = (ctx->mods & ~seat->kbd.kitty_significant) == 0;
const xkb_keysym_t sym_to_use = use_level0_sym && ctx->level0_syms.count > 0
? ctx->level0_syms.syms[0]
: sym;
if (composed) if (composed)
key = utf32[0]; /* TODO: what if there are multiple codepoints? */ key = utf32[0]; /* TODO: what if there are multiple codepoints? */
else { else {
key = xkb_keysym_to_utf32(sym_to_use); key = xkb_keysym_to_utf32(
use_level0_sym ? ctx->level0_syms.syms[0] : sym);
if (key == 0) if (key == 0)
return false; return false;
/* The *shifted* key. May be the same as the unshifted
* key - if so, this is filtered out below, when
* emitting the CSI */
alternate = xkb_keysym_to_utf32(sym);
} }
/* Base layout key. I.e the symbol the pressed key produces in /*
* the base/default layout (layout idx 0) */ * The *shifted* key. May be the same as the unshifted key -
const xkb_keysym_t *base_syms; * if so, this is filtered out below, when emitting the CSI.
int base_sym_count = xkb_keymap_key_get_syms_by_level( *
seat->kbd.xkb_keymap, ctx->key, 0, 0, &base_syms); * Note that normally, only the *unshifted* key is emitted - see below
*/
if (base_sym_count > 0) alternate = xkb_keysym_to_utf32(sym);
base = xkb_keysym_to_utf32(base_syms[0]);
final = 'u'; final = 'u';
} }
if (key < 0) if (key < 0)
return false; return false;
/* Base layout key. I.e the symbol the pressed key produces in
* the base/default layout (layout idx 0) */
const xkb_keysym_t *base_syms;
int base_sym_count = xkb_keymap_key_get_syms_by_level(
seat->kbd.xkb_keymap, ctx->key, 0, 0, &base_syms);
if (base_sym_count > 0)
base = xkb_keysym_to_utf32(base_syms[0]);
xassert(encoded_mods >= 1); xassert(encoded_mods >= 1);
char event[4]; char event[4];