diff --git a/CHANGELOG.md b/CHANGELOG.md index 828f51aa..6a16da7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,9 @@ * Kitty keyboard protocol: - [Report event types](https://sw.kovidgoyal.net/kitty/keyboard-protocol/#report-events) (mode `0b10`) + - [Report alternate keys](https://sw.kovidgoyal.net/kitty/keyboard-protocol/#report-alternates) + (mode `0b100`, but not that only the _shifted_ key is reported, + not the _base layout key_) - [Report all keys as escape codes](https://sw.kovidgoyal.net/kitty/keyboard-protocol/#report-all-keys) (mode `0b1000`) - [Report associated text](https://sw.kovidgoyal.net/kitty/keyboard-protocol/#report-text) diff --git a/input.c b/input.c index 869e1c67..41349d9a 100644 --- a/input.c +++ b/input.c @@ -1161,6 +1161,7 @@ kitty_kbd_protocol(struct seat *seat, struct terminal *term, const bool disambiguate = flags & KITTY_KBD_DISAMBIGUATE; const bool report_events = flags & KITTY_KBD_REPORT_EVENT; + const bool report_alternate = flags & KITTY_KBD_REPORT_ALTERNATE; const bool report_all_as_escapes = flags & KITTY_KBD_REPORT_ALL; if (!report_events && released) @@ -1252,7 +1253,7 @@ emit_escapes: encoded_mods |= mods & (1 << seat->kbd.mod_num) ? (1 << 7) : 0; encoded_mods++; - int key = -1; + int key = -1, alternate = -1, base = -1; char final; switch (sym) { @@ -1435,8 +1436,22 @@ emit_escapes: key = xkb_keysym_to_utf32(sym_to_use); if (key == 0) key = sym_to_use; + + /* 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) */ + 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]); + final = 'u'; break; } @@ -1445,7 +1460,7 @@ emit_escapes: xassert(encoded_mods >= 1); char event[4]; - if (report_events) { + if (report_events /*&& !pressed*/) { /* Note: this deviates slightly from Kitty, which omits the * “:1” subparameter for key press events */ event[0] = ':'; @@ -1465,14 +1480,32 @@ emit_escapes: bytes = snprintf(p, left, "\x1b[%u", key); p += bytes; left -= bytes; - if (encoded_mods > 1 || event[0] != '\0' || report_associated_text) { - bytes = snprintf(p, left, ";%u%s", encoded_mods, event); - p += bytes; left -= bytes; + if (report_alternate) { + bool emit_alternate = alternate > 0 && alternate != key; + bool emit_base = base > 0 && base != key && base != alternate; - if (report_associated_text) { - bytes = snprintf(p, left, ";%u", utf32); + if (emit_alternate) { + bytes = snprintf(p, left, ":%u", alternate); p += bytes; left -= bytes; } + + if (emit_base) { + bytes = snprintf( + p, left, "%s:%u", !emit_alternate ? ":" : "", base); + p += bytes; left -= bytes; + } + } + + bool emit_mods = encoded_mods > 1 || event[0] != '\0'; + + if (emit_mods) { + bytes = snprintf(p, left, ";%u%s", encoded_mods, event); + p += bytes; left -= bytes; + } + + if (report_associated_text) { + bytes = snprintf(p, left, "%s;%u", !emit_mods ? ";" : "", utf32); + p += bytes; left -= bytes; } bytes = snprintf(p, left, "%c", final); diff --git a/terminal.h b/terminal.h index 394871f6..09b04614 100644 --- a/terminal.h +++ b/terminal.h @@ -135,6 +135,7 @@ enum kitty_kbd_flags { KITTY_KBD_REPORT_ASSOCIATED = 0x10, KITTY_KBD_SUPPORTED = (KITTY_KBD_DISAMBIGUATE | KITTY_KBD_REPORT_EVENT | + KITTY_KBD_REPORT_ALTERNATE | KITTY_KBD_REPORT_ALL | KITTY_KBD_REPORT_ASSOCIATED), };