From 442cf594f8f367ce6e48818ccb6de5f29f582de4 Mon Sep 17 00:00:00 2001 From: Bernardo Meurer Costa Date: Thu, 26 Mar 2026 01:37:21 +0000 Subject: [PATCH] fix: parse SS3 cursor key sequences in read_key Terminals in application cursor key mode (DECCKM) send SS3 sequences (ESC O A..F) instead of CSI (ESC [ A..F) for arrow/Home/End keys. zsh's line editor enables this mode via smkx and doesn't always reset it before running external commands, so programs using read_key() see arrows as UnknownEscSeq(['O']) with the trailing letter left unread. Add an ESC O branch mirroring the ESC [ branch for A/B/C/D/H/F. c.f. - https://vt100.net/docs/vt510-rm/DECCKM.html - https://www.zsh.org/mla/users/2016/msg00133.html - https://github.com/cli/cli/issues/3071 - https://github.com/PowerShell/PowerShell/issues/12268 - https://github.com/gui-cs/Terminal.Gui/issues/418 --- src/unix_term.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/unix_term.rs b/src/unix_term.rs index ec445d4b..7f382c19 100644 --- a/src/unix_term.rs +++ b/src/unix_term.rs @@ -293,8 +293,26 @@ fn read_single_key_impl(fd: RawFd) -> Result { // \x1b[ and no more input Ok(Key::UnknownEscSeq(vec![c1])) } + } else if c1 == 'O' { + // SS3 (Single Shift 3) sequences. Sent by terminals in + // application cursor key mode (DECCKM, enabled via + // `ESC [ ? 1 h` / terminfo smkx). zsh's ZLE commonly + // leaves DECCKM on when running external commands. + if let Some(c2) = read_single_char(fd)? { + match c2 { + 'A' => Ok(Key::ArrowUp), + 'B' => Ok(Key::ArrowDown), + 'C' => Ok(Key::ArrowRight), + 'D' => Ok(Key::ArrowLeft), + 'H' => Ok(Key::Home), + 'F' => Ok(Key::End), + _ => Ok(Key::UnknownEscSeq(vec![c1, c2])), + } + } else { + Ok(Key::UnknownEscSeq(vec![c1])) + } } else { - // char after escape is not [ + // char after escape is not [ or O Ok(Key::UnknownEscSeq(vec![c1])) } } else {