diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b6fd944..828f51aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,8 @@ (mode `0b10`) - [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) + (mode `0b10000`) ### Changed diff --git a/input.c b/input.c index 2b878cd1..869e1c67 100644 --- a/input.c +++ b/input.c @@ -1156,7 +1156,9 @@ kitty_kbd_protocol(struct seat *seat, struct terminal *term, const bool composing = ctx->compose_status == XKB_COMPOSE_COMPOSING; const bool composed = ctx->compose_status == XKB_COMPOSE_COMPOSED; - const enum kitty_kbd_flags flags = term->grid->kitty_kbd.flags[term->grid->kitty_kbd.idx]; + const enum kitty_kbd_flags flags = + term->grid->kitty_kbd.flags[term->grid->kitty_kbd.idx]; + const bool disambiguate = flags & KITTY_KBD_DISAMBIGUATE; const bool report_events = flags & KITTY_KBD_REPORT_EVENT; const bool report_all_as_escapes = flags & KITTY_KBD_REPORT_ALL; @@ -1178,11 +1180,17 @@ kitty_kbd_protocol(struct seat *seat, struct terminal *term, 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 bool is_text = iswprint(utf32) && (effective & ~caps_num) == 0; const size_t count = ctx->utf8.count; + const bool report_associated_text = + (flags & KITTY_KBD_REPORT_ASSOCIATED) && is_text && !released; + if (composing) { /* We never emit anything while composing, *except* modifiers * (and only in report-all-keys-as-escape-codes mode) */ @@ -1201,6 +1209,8 @@ kitty_kbd_protocol(struct seat *seat, struct terminal *term, case XKB_KEY_Super_R: case XKB_KEY_Hyper_R: case XKB_KEY_Meta_R: + case XKB_KEY_ISO_Level3_Shift: + case XKB_KEY_ISO_Level5_Shift: goto emit_escapes; default: @@ -1220,9 +1230,7 @@ kitty_kbd_protocol(struct seat *seat, struct terminal *term, } /* Plain-text without modifiers, or commposed text, is emitted as-is */ - if (((iswprint(utf32) && (effective & ~caps_num) == 0) || composed) - && !released) - { + if (is_text && !released) { term_to_slave(term, utf8, count); return true; } @@ -1361,6 +1369,8 @@ emit_escapes: case XKB_KEY_Super_R: if (report_all_as_escapes) {key = 57450; final = 'u';} break; case XKB_KEY_Hyper_R: if (report_all_as_escapes) {key = 57451; final = 'u';} break; case XKB_KEY_Meta_R: if (report_all_as_escapes) {key = 57452; final = 'u';} break; + case XKB_KEY_ISO_Level3_Shift: if (report_all_as_escapes) {key = 57453; final = 'u';} break; + case XKB_KEY_ISO_Level5_Shift: if (report_all_as_escapes) {key = 57454; final = 'u';} break; default: { /* @@ -1419,17 +1429,14 @@ emit_escapes: ? ctx->level0_syms.syms[0] : sym; - if (composed) { - wchar_t wc; - if (mbtowc(&wc, (const char *)utf8, count) == count) - key = wc; - } - - if (key < 0) { + if (composed && is_text) + key = utf32; + else { key = xkb_keysym_to_utf32(sym_to_use); if (key == 0) key = sym_to_use; } + final = 'u'; break; } @@ -1447,26 +1454,40 @@ emit_escapes: } else event[0] = '\0'; - char buf[16]; - int bytes; + char buf[64], *p = buf; + size_t left = sizeof(buf); + size_t bytes; if (key < 0) return false; if (final == 'u' || final == '~') { - if (encoded_mods > 1 || event[0] != '\0') - bytes = snprintf(buf, sizeof(buf), "\x1b[%u;%u%s%c", - key, encoded_mods, event, final); - else - bytes = snprintf(buf, sizeof(buf), "\x1b[%u%c", key, final); + 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_associated_text) { + bytes = snprintf(p, left, ";%u", utf32); + p += bytes; left -= bytes; + } + } + + bytes = snprintf(p, left, "%c", final); + p += bytes; left -= bytes; } else { - if (encoded_mods > 1 || event[0] != '\0') - bytes = snprintf(buf, sizeof(buf), "\x1b[1;%u%s%c", encoded_mods, event, final); - else - bytes = snprintf(buf, sizeof(buf), "\x1b[%c", final); + if (encoded_mods > 1 || event[0] != '\0') { + bytes = snprintf(p, left, "\x1b[1;%u%s%c", encoded_mods, event, final); + p += bytes; left -= bytes; + } else { + bytes = snprintf(p, left, "\x1b[%c", final); + p += bytes; left -= bytes; + } } - term_to_slave(term, buf, bytes); + term_to_slave(term, buf, sizeof(buf) - left); return true; } @@ -1639,6 +1660,10 @@ key_press_release(struct seat *seat, struct terminal *term, uint32_t serial, if (composed) { xkb_compose_state_get_utf8( seat->kbd.xkb_compose_state, (char *)utf8, count + 1); + + wchar_t wc; + if (mbtowc(&wc, (const char *)utf8, count) == count) + utf32 = wc; } else { xkb_state_key_get_utf8( seat->kbd.xkb_state, key, (char *)utf8, count + 1); diff --git a/terminal.h b/terminal.h index 15d263d5..394871f6 100644 --- a/terminal.h +++ b/terminal.h @@ -135,7 +135,8 @@ enum kitty_kbd_flags { KITTY_KBD_REPORT_ASSOCIATED = 0x10, KITTY_KBD_SUPPORTED = (KITTY_KBD_DISAMBIGUATE | KITTY_KBD_REPORT_EVENT | - KITTY_KBD_REPORT_ALL), + KITTY_KBD_REPORT_ALL | + KITTY_KBD_REPORT_ASSOCIATED), }; struct grid {