diff options
| author | user <user@clank> | 2026-09-09 20:14:03 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-09-09 20:14:03 +0200 |
| commit | a1e2c1817ac8d967519cd978742f6a59591ff959 (patch) | |
| tree | eca5b858d7c60a18d261d5c64fbc3a45ffcce255 /src | |
| parent | search: a scrollback search bar on /, matches highlighted (diff) | |
| download | slosh-a1e2c1817ac8d967519cd978742f6a59591ff959.tar.gz slosh-a1e2c1817ac8d967519cd978742f6a59591ff959.tar.xz slosh-a1e2c1817ac8d967519cd978742f6a59591ff959.zip | |
pane: shift consumed by the character is consumed, tell the encoder
935fb7e9 taught the legacy decoder to read the shift out of shifted
punctuation, so / and ? could be two keys. But pane_send_key never set
the consumed mods on the re-encoded event, and libghostty's kitty path
only passes text through as text when no unconsumed modifier remains:
a kitty-protocol pane (nvim) received : as CSI 59;2u -- shift+semicolon,
no text -- and the command line never opened. :wq! was unreachable.
Mark shift consumed when the event carries text, shift is held, and the
text is not the unshifted character -- the same call a real terminal
makes. Text the shift produced goes through as text; chords whose shift
is real (shift+up, ctrl+shift+a, back-tab) keep their escapes, and a
legacy pane sees no change.
Diffstat (limited to 'src')
| -rw-r--r-- | src/pane.c | 23 |
1 files changed, 23 insertions, 0 deletions
@@ -794,6 +794,29 @@ void pane_send_key(pane_t *p, const input_event_t *ev) { ev->text_len); ghostty_key_event_set_unshifted_codepoint(p->kev, ev->unshifted); + /* Shift that produced the character is consumed, and the encoder must be + * told so: its kitty path only passes text through as text when no + * unconsumed modifier remains. Without this, `:` (shift+; in the decoder's + * eyes) reaches a kitty-protocol pane as CSI 59;2u -- shift+semicolon, no + * text -- and nvim's command line never opens. A real terminal marks the + * shift consumed for exactly this case; so do we: text present, shift + * held, and the text is not the unshifted character. */ + GhosttyMods consumed = 0; + if (ev->text_len && (ev->mods & MOD_SHIFT)) { + const uint8_t *t = (const uint8_t *)ev->text; + uint32_t cp = t[0]; + if ((t[0] & 0xe0) == 0xc0 && ev->text_len >= 2) + cp = (uint32_t)(t[0] & 0x1f) << 6 | (t[1] & 0x3f); + else if ((t[0] & 0xf0) == 0xe0 && ev->text_len >= 3) + cp = (uint32_t)(t[0] & 0x0f) << 12 | (uint32_t)(t[1] & 0x3f) << 6 | + (t[2] & 0x3f); + else if ((t[0] & 0xf8) == 0xf0 && ev->text_len >= 4) + cp = (uint32_t)(t[0] & 0x07) << 18 | (uint32_t)(t[1] & 0x3f) << 12 | + (uint32_t)(t[2] & 0x3f) << 6 | (t[3] & 0x3f); + if (cp != ev->unshifted) consumed |= GHOSTTY_MODS_SHIFT; + } + ghostty_key_event_set_consumed_mods(p->kev, consumed); + char out[128]; size_t n = 0; if (ghostty_key_encoder_encode(p->kenc, p->kev, out, sizeof out, &n) == |
