diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-07-15 00:59:38 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-07-15 00:59:38 +0300 |
| commit | 5d24d0d214d05858e344a9e15a63856dc1328eae (patch) | |
| tree | bcd720acb376e453b0904a41b8c544af7fbf7b10 /src/raw_input.rs | |
| parent | c9676e46ad9298c49bcc66981b2c405936433809 (diff) | |
fix: preserve escape before sgr mouse reports
refs #1334
Diffstat (limited to 'src/raw_input.rs')
| -rw-r--r-- | src/raw_input.rs | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/src/raw_input.rs b/src/raw_input.rs index 445b4be3..848df88d 100644 --- a/src/raw_input.rs +++ b/src/raw_input.rs @@ -766,6 +766,15 @@ fn complete_escape_sequence_len(buffer: &[u8]) -> Option<usize> { return None; } + if buffer.starts_with(b"\x1b\x1b[<") { + if let Some(mouse_len) = find_csi_final(&buffer[1..], b"Mm") { + let mouse_sequence = std::str::from_utf8(&buffer[1..1 + mouse_len]).ok()?; + if parse_sgr_mouse(mouse_sequence).is_some() { + return Some(1); + } + } + } + if buffer.starts_with(b"\x1b\x1b") { return complete_escape_sequence_len(&buffer[1..]).map(|len| len + 1); } @@ -1573,6 +1582,45 @@ mod tests { } #[test] + fn lone_escape_then_complete_sgr_mouse_report_emits_both_events() { + for report in [b"\x1b[<35;10;20M".as_slice(), b"\x1b[<35;10;20m".as_slice()] { + let mut framer = RawInputFramer::default(); + + assert!(framer.push(b"\x1b").is_empty()); + let events = framer.push(report); + + assert_eq!(events.len(), 2); + let mut events = events.into_iter(); + assert_raw_key(events.next().unwrap(), KeyCode::Esc, KeyModifiers::empty()); + assert!(matches!( + events.next().unwrap(), + RawInputEvent::Mouse(MouseEvent { + kind: MouseEventKind::Moved, + column: 9, + row: 19, + .. + }) + )); + assert!(framer.flush_timeout().is_empty()); + } + } + + #[test] + fn legacy_doubled_escape_alt_arrow_remains_one_event() { + let mut framer = RawInputFramer::default(); + + let events = framer.push(b"\x1b\x1b[A"); + + assert_eq!(events.len(), 1); + assert_raw_key( + events.into_iter().next().unwrap(), + KeyCode::Up, + KeyModifiers::ALT, + ); + assert!(framer.flush_timeout().is_empty()); + } + + #[test] fn legacy_reader_extends_only_incomplete_sgr_mouse_timeout() { let mut mouse = RawInputFramer::default(); assert!(mouse.push(b"\x1b[<3").is_empty()); |
