1use crate::vendored::termwiz::keymap::{Found, KeyMap};
4use crate::vendored::termwiz::readbuf::ReadBuffer;
5use bitflags::bitflags;
6use std::fmt::Write;
7
8pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
9
10bitflags! {
11 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
12 pub struct Modifiers: u16 {
13 const NONE = 0;
14 const SHIFT = 1 << 1;
15 const ALT = 1 << 2;
16 const CTRL = 1 << 3;
17 const SUPER = 1 << 4;
18 const LEFT_ALT = 1 << 5;
19 const RIGHT_ALT = 1 << 6;
20 const LEADER = 1 << 7;
21 const LEFT_CTRL = 1 << 8;
22 const RIGHT_CTRL = 1 << 9;
23 const LEFT_SHIFT = 1 << 10;
24 const RIGHT_SHIFT = 1 << 11;
25 const ENHANCED_KEY = 1 << 12;
26 }
27}
28
29impl Modifiers {
30 pub fn encode_xterm(self) -> u8 {
31 let mut number = 0;
32 if self.contains(Self::SHIFT) {
33 number |= 1;
34 }
35 if self.contains(Self::ALT) {
36 number |= 2;
37 }
38 if self.contains(Self::CTRL) {
39 number |= 4;
40 }
41 number
42 }
43
44 pub fn remove_positional_mods(self) -> Self {
45 self - (Self::LEFT_ALT
46 | Self::RIGHT_ALT
47 | Self::LEFT_CTRL
48 | Self::RIGHT_CTRL
49 | Self::LEFT_SHIFT
50 | Self::RIGHT_SHIFT
51 | Self::ENHANCED_KEY)
52 }
53}
54
55bitflags! {
56 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
57 pub struct KittyKeyboardFlags: u16 {
58 const NONE = 0;
59 const DISAMBIGUATE_ESCAPE_CODES = 1;
60 const REPORT_EVENT_TYPES = 2;
61 const REPORT_ALTERNATE_KEYS = 4;
62 const REPORT_ALL_KEYS_AS_ESCAPE_CODES = 8;
63 const REPORT_ASSOCIATED_TEXT = 16;
64 }
65}
66
67pub fn ctrl_mapping(c: char) -> Option<char> {
68 Some(match c {
69 '@' | '`' | ' ' | '2' => '\x00',
70 'A' | 'a' => '\x01',
71 'B' | 'b' => '\x02',
72 'C' | 'c' => '\x03',
73 'D' | 'd' => '\x04',
74 'E' | 'e' => '\x05',
75 'F' | 'f' => '\x06',
76 'G' | 'g' => '\x07',
77 'H' | 'h' => '\x08',
78 'I' | 'i' => '\x09',
79 'J' | 'j' => '\x0a',
80 'K' | 'k' => '\x0b',
81 'L' | 'l' => '\x0c',
82 'M' | 'm' => '\x0d',
83 'N' | 'n' => '\x0e',
84 'O' | 'o' => '\x0f',
85 'P' | 'p' => '\x10',
86 'Q' | 'q' => '\x11',
87 'R' | 'r' => '\x12',
88 'S' | 's' => '\x13',
89 'T' | 't' => '\x14',
90 'U' | 'u' => '\x15',
91 'V' | 'v' => '\x16',
92 'W' | 'w' => '\x17',
93 'X' | 'x' => '\x18',
94 'Y' | 'y' => '\x19',
95 'Z' | 'z' => '\x1a',
96 '[' | '3' | '{' => '\x1b',
97 '\\' | '4' | '|' => '\x1c',
98 ']' | '5' | '}' => '\x1d',
99 '^' | '6' | '~' => '\x1e',
100 '_' | '7' | '/' => '\x1f',
101 '8' | '?' => '\x7f',
102 _ => return None,
103 })
104}
105
106bitflags! {
107 #[derive(Debug, Default, Clone, PartialEq, Eq)]
108 pub struct MouseButtons: u8 {
109 const NONE = 0;
110 const LEFT = 1<<1;
111 const RIGHT = 1<<2;
112 const MIDDLE = 1<<3;
113 const VERT_WHEEL = 1<<4;
114 const HORZ_WHEEL = 1<<5;
115 const WHEEL_POSITIVE = 1<<6;
118 }
119}
120
121pub const CSI: &str = "\x1b[";
122pub const SS3: &str = "\x1bO";
123
124#[derive(Debug, Clone, PartialEq, Eq)]
125pub enum InputEvent {
126 Key(KeyEvent),
127 Mouse(MouseEvent),
128 PixelMouse(PixelMouseEvent),
129 Resized {
131 cols: usize,
132 rows: usize,
133 },
134 Paste(String),
137 Wake,
139 OperatingSystemCommand(Vec<u8>),
142 DeviceControlReply {
150 intermediates: Vec<u8>,
151 params: Vec<u8>,
152 final_byte: u8,
153 raw: Vec<u8>,
154 },
155 FocusGained,
156 FocusLost,
157}
158
159#[derive(Debug, Clone, PartialEq, Eq)]
160pub struct MouseEvent {
161 pub x: u16,
162 pub y: u16,
163 pub mouse_buttons: MouseButtons,
164 pub modifiers: Modifiers,
165}
166
167#[derive(Debug, Clone, PartialEq, Eq)]
168pub struct PixelMouseEvent {
169 pub x_pixels: u16,
170 pub y_pixels: u16,
171 pub mouse_buttons: MouseButtons,
172 pub modifiers: Modifiers,
173}
174
175#[derive(Debug, Clone, PartialEq, Eq)]
176pub struct KeyEvent {
177 pub key: KeyCode,
179 pub modifiers: Modifiers,
181}
182
183#[derive(Debug, Clone, Copy, PartialEq, Eq)]
184pub enum KeyboardEncoding {
185 Xterm,
186 CsiU,
188 Win32,
190 Kitty(KittyKeyboardFlags),
192}
193
194#[derive(Debug, Clone, Copy)]
197pub struct KeyCodeEncodeModes {
198 pub encoding: KeyboardEncoding,
199 pub application_cursor_keys: bool,
200 pub newline_mode: bool,
201 pub modify_other_keys: Option<i64>,
202}
203
204#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
208pub enum KeyCode {
209 Char(char),
211
212 Hyper,
213 Super,
214 Meta,
215
216 Cancel,
218 Backspace,
219 Tab,
220 Clear,
221 Enter,
222 Shift,
223 Escape,
224 LeftShift,
225 RightShift,
226 Control,
227 LeftControl,
228 RightControl,
229 Alt,
230 LeftAlt,
231 RightAlt,
232 Menu,
233 LeftMenu,
234 RightMenu,
235 Pause,
236 CapsLock,
237 PageUp,
238 PageDown,
239 End,
240 Home,
241 LeftArrow,
242 RightArrow,
243 UpArrow,
244 DownArrow,
245 Select,
246 Print,
247 Execute,
248 PrintScreen,
249 Insert,
250 Delete,
251 Help,
252 LeftWindows,
253 RightWindows,
254 Applications,
255 Sleep,
256 Numpad0,
257 Numpad1,
258 Numpad2,
259 Numpad3,
260 Numpad4,
261 Numpad5,
262 Numpad6,
263 Numpad7,
264 Numpad8,
265 Numpad9,
266 Multiply,
267 Add,
268 Separator,
269 Subtract,
270 Decimal,
271 Divide,
272 Function(u8),
274 NumLock,
275 ScrollLock,
276 Copy,
277 Cut,
278 Paste,
279 BrowserBack,
280 BrowserForward,
281 BrowserRefresh,
282 BrowserStop,
283 BrowserSearch,
284 BrowserFavorites,
285 BrowserHome,
286 VolumeMute,
287 VolumeDown,
288 VolumeUp,
289 MediaNextTrack,
290 MediaPrevTrack,
291 MediaStop,
292 MediaPlayPause,
293 ApplicationLeftArrow,
294 ApplicationRightArrow,
295 ApplicationUpArrow,
296 ApplicationDownArrow,
297 KeyPadHome,
298 KeyPadEnd,
299 KeyPadPageUp,
300 KeyPadPageDown,
301 KeyPadBegin,
302
303 #[doc(hidden)]
304 InternalPasteStart,
305 #[doc(hidden)]
306 InternalPasteEnd,
307}
308
309impl KeyCode {
310 pub fn normalize_shift_to_upper_case(self, modifiers: Modifiers) -> KeyCode {
313 if modifiers.contains(Modifiers::SHIFT) {
314 match self {
315 KeyCode::Char(c) if c.is_ascii_lowercase() => KeyCode::Char(c.to_ascii_uppercase()),
316 _ => self,
317 }
318 } else {
319 self
320 }
321 }
322
323 pub fn is_modifier(self) -> bool {
325 matches!(
326 self,
327 Self::Hyper
328 | Self::Super
329 | Self::Meta
330 | Self::Shift
331 | Self::LeftShift
332 | Self::RightShift
333 | Self::Control
334 | Self::LeftControl
335 | Self::RightControl
336 | Self::Alt
337 | Self::LeftAlt
338 | Self::RightAlt
339 | Self::LeftWindows
340 | Self::RightWindows
341 )
342 }
343
344 pub fn encode(
346 &self,
347 mods: Modifiers,
348 modes: KeyCodeEncodeModes,
349 is_down: bool,
350 ) -> Result<String> {
351 if !is_down {
352 return Ok(String::new());
354 }
355 let mods = mods.remove_positional_mods();
358
359 use KeyCode::*;
360
361 let key = self.normalize_shift_to_upper_case(mods);
362 let mods = match key {
365 Char(c)
366 if (c.is_ascii_punctuation() || c.is_ascii_uppercase())
367 && mods.contains(Modifiers::SHIFT) =>
368 {
369 mods & !Modifiers::SHIFT
370 },
371 _ => mods,
372 };
373
374 let key = match key {
376 Char('\x7f') => Delete,
377 Char('\x08') => Backspace,
378 c => c,
379 };
380
381 let mut buf = String::new();
382
383 match key {
386 Char(c)
387 if is_ambiguous_ascii_ctrl(c)
388 && mods.contains(Modifiers::CTRL)
389 && modes.encoding == KeyboardEncoding::CsiU =>
390 {
391 csi_u_encode(&mut buf, c, mods, &modes)?;
392 },
393 Char(c) if c.is_ascii_uppercase() && mods.contains(Modifiers::CTRL) => {
394 csi_u_encode(&mut buf, c, mods, &modes)?;
395 },
396
397 Char(c) if mods.contains(Modifiers::CTRL) && modes.modify_other_keys == Some(2) => {
398 csi_u_encode(&mut buf, c, mods, &modes)?;
399 },
400 Char(c) if mods.contains(Modifiers::CTRL) && ctrl_mapping(c).is_some() => {
401 let c = ctrl_mapping(c).unwrap();
402 if mods.contains(Modifiers::ALT) {
403 buf.push(0x1b as char);
404 }
405 buf.push(c);
406 },
407
408 Char(c)
414 if (c.is_ascii_alphanumeric() || c.is_ascii_punctuation())
415 && mods.contains(Modifiers::ALT) =>
416 {
417 buf.push(0x1b as char);
418 buf.push(c);
419 },
420
421 Backspace => {
422 if mods.contains(Modifiers::CTRL) {
426 csi_u_encode(&mut buf, '\x08', mods, &modes)?;
427 } else if mods.contains(Modifiers::SHIFT) {
428 csi_u_encode(&mut buf, '\x7f', mods, &modes)?;
429 } else {
430 if mods.contains(Modifiers::ALT) {
431 buf.push(0x1b as char);
432 }
433 buf.push('\x7f');
434 }
435 },
436
437 Enter | Escape => {
438 let c = match key {
439 Enter => '\r',
440 Escape => '\x1b',
441 _ => unreachable!(),
442 };
443 if mods.contains(Modifiers::SHIFT) || mods.contains(Modifiers::CTRL) {
444 csi_u_encode(&mut buf, c, mods, &modes)?;
445 } else {
446 if mods.contains(Modifiers::ALT) {
447 buf.push(0x1b as char);
448 }
449 buf.push(c);
450 if modes.newline_mode && key == Enter {
451 buf.push(0x0a as char);
452 }
453 }
454 },
455
456 Tab if !mods.is_empty() && modes.modify_other_keys.is_some() => {
457 csi_u_encode(&mut buf, '\t', mods, &modes)?;
458 },
459
460 Tab => {
461 if mods.contains(Modifiers::ALT) {
462 buf.push(0x1b as char);
463 }
464 let mods = mods & !Modifiers::ALT;
465 if mods == Modifiers::CTRL {
466 buf.push_str("\x1b[9;5u");
467 } else if mods == Modifiers::CTRL | Modifiers::SHIFT {
468 buf.push_str("\x1b[1;5Z");
469 } else if mods == Modifiers::SHIFT {
470 buf.push_str("\x1b[Z");
471 } else {
472 buf.push('\t');
473 }
474 },
475
476 Char(c) => {
477 if mods.is_empty() {
478 buf.push(c);
479 } else {
480 csi_u_encode(&mut buf, c, mods, &modes)?;
481 }
482 },
483
484 Home
485 | KeyPadHome
486 | End
487 | KeyPadEnd
488 | UpArrow
489 | DownArrow
490 | RightArrow
491 | LeftArrow
492 | ApplicationUpArrow
493 | ApplicationDownArrow
494 | ApplicationRightArrow
495 | ApplicationLeftArrow => {
496 let (force_app, c) = match key {
497 UpArrow => (false, 'A'),
498 DownArrow => (false, 'B'),
499 RightArrow => (false, 'C'),
500 LeftArrow => (false, 'D'),
501 KeyPadHome | Home => (false, 'H'),
502 End | KeyPadEnd => (false, 'F'),
503 ApplicationUpArrow => (true, 'A'),
504 ApplicationDownArrow => (true, 'B'),
505 ApplicationRightArrow => (true, 'C'),
506 ApplicationLeftArrow => (true, 'D'),
507 _ => unreachable!(),
508 };
509
510 let csi_or_ss3 = if force_app || modes.application_cursor_keys {
511 SS3
513 } else {
514 CSI
516 };
517
518 if mods.contains(Modifiers::ALT)
519 || mods.contains(Modifiers::SHIFT)
520 || mods.contains(Modifiers::CTRL)
521 {
522 write!(buf, "{}1;{}{}", CSI, 1 + mods.encode_xterm(), c)?;
523 } else {
524 write!(buf, "{}{}", csi_or_ss3, c)?;
525 }
526 },
527
528 PageUp | PageDown | KeyPadPageUp | KeyPadPageDown | Insert | Delete => {
529 let c = match key {
530 Insert => 2,
531 Delete => 3,
532 KeyPadPageUp | PageUp => 5,
533 KeyPadPageDown | PageDown => 6,
534 _ => unreachable!(),
535 };
536
537 if mods.contains(Modifiers::ALT)
538 || mods.contains(Modifiers::SHIFT)
539 || mods.contains(Modifiers::CTRL)
540 {
541 write!(buf, "\x1b[{};{}~", c, 1 + mods.encode_xterm())?;
542 } else {
543 write!(buf, "\x1b[{}~", c)?;
544 }
545 },
546
547 Function(n) => {
548 if mods.is_empty() && n < 5 {
549 write!(
551 buf,
552 "{}",
553 match n {
554 1 => "\x1bOP",
555 2 => "\x1bOQ",
556 3 => "\x1bOR",
557 4 => "\x1bOS",
558 _ => unreachable!("wat?"),
559 }
560 )?;
561 } else if n < 5 {
562 let code = match n {
564 1 => 'P',
565 2 => 'Q',
566 3 => 'R',
567 4 => 'S',
568 _ => unreachable!("wat?"),
569 };
570 write!(buf, "\x1b[1;{}{code}", 1 + mods.encode_xterm())?;
571 } else {
572 let intro = match n {
574 1 => "\x1b[11",
575 2 => "\x1b[12",
576 3 => "\x1b[13",
577 4 => "\x1b[14",
578 5 => "\x1b[15",
579 6 => "\x1b[17",
580 7 => "\x1b[18",
581 8 => "\x1b[19",
582 9 => "\x1b[20",
583 10 => "\x1b[21",
584 11 => "\x1b[23",
585 12 => "\x1b[24",
586 13 => "\x1b[25",
587 14 => "\x1b[26",
588 15 => "\x1b[28",
589 16 => "\x1b[29",
590 17 => "\x1b[31",
591 18 => "\x1b[32",
592 19 => "\x1b[33",
593 20 => "\x1b[34",
594 21 => "\x1b[42",
595 22 => "\x1b[43",
596 23 => "\x1b[44",
597 24 => "\x1b[45",
598 _ => return Err(format!("unhandled fkey number {}", n).into()),
599 };
600 let encoded_mods = mods.encode_xterm();
601 if encoded_mods == 0 {
602 write!(buf, "{}~", intro)?;
605 } else {
606 write!(buf, "{};{}~", intro, 1 + encoded_mods)?;
607 }
608 }
609 },
610
611 Numpad0 | Numpad3 | Numpad9 | Decimal => {
612 let intro = match key {
613 Numpad0 => "\x1b[2",
614 Numpad3 => "\x1b[6",
615 Numpad9 => "\x1b[6",
616 Decimal => "\x1b[3",
617 _ => unreachable!(),
618 };
619
620 let encoded_mods = mods.encode_xterm();
621 if encoded_mods == 0 {
622 write!(buf, "{}~", intro)?;
623 } else {
624 write!(buf, "{};{}~", intro, 1 + encoded_mods)?;
625 }
626 },
627
628 Numpad1 | Numpad2 | Numpad4 | Numpad5 | KeyPadBegin | Numpad6 | Numpad7 | Numpad8 => {
629 let c = match key {
630 Numpad1 => "F",
631 Numpad2 => "B",
632 Numpad4 => "D",
633 KeyPadBegin | Numpad5 => "E",
634 Numpad6 => "C",
635 Numpad7 => "H",
636 Numpad8 => "A",
637 _ => unreachable!(),
638 };
639
640 let encoded_mods = mods.encode_xterm();
641 if encoded_mods == 0 {
642 write!(buf, "{}{}", CSI, c)?;
643 } else {
644 write!(buf, "{}1;{}{}", CSI, 1 + encoded_mods, c)?;
645 }
646 },
647
648 Multiply | Add | Separator | Subtract | Divide => {},
649
650 Control | LeftControl | RightControl | Alt | LeftAlt | RightAlt | Menu | LeftMenu
652 | RightMenu | Super | Hyper | Shift | LeftShift | RightShift | Meta | LeftWindows
653 | RightWindows | NumLock | ScrollLock | Cancel | Clear | Pause | CapsLock | Select
654 | Print | PrintScreen | Execute | Help | Applications | Sleep | Copy | Cut | Paste
655 | BrowserBack | BrowserForward | BrowserRefresh | BrowserStop | BrowserSearch
656 | BrowserFavorites | BrowserHome | VolumeMute | VolumeDown | VolumeUp
657 | MediaNextTrack | MediaPrevTrack | MediaStop | MediaPlayPause | InternalPasteStart
658 | InternalPasteEnd => {},
659 };
660
661 Ok(buf)
662 }
663}
664
665fn is_ambiguous_ascii_ctrl(c: char) -> bool {
669 matches!(c, 'i' | 'I' | 'm' | 'M' | '[' | '{' | '@')
670}
671
672fn is_ascii(c: char) -> bool {
673 (c as u32) < 0x80
674}
675
676fn csi_u_encode(
677 buf: &mut String,
678 c: char,
679 mods: Modifiers,
680 modes: &KeyCodeEncodeModes,
681) -> Result<()> {
682 if modes.encoding == KeyboardEncoding::CsiU && is_ascii(c) {
683 write!(buf, "\x1b[{};{}u", c as u32, 1 + mods.encode_xterm())?;
684 return Ok(());
685 }
686
687 match (c, modes.modify_other_keys) {
689 ('c' | 'd' | '\x1b' | '\x7f' | '\x08', Some(1)) => {
690 },
692 (c, Some(_)) => {
693 write!(buf, "\x1b[27;{};{}~", 1 + mods.encode_xterm(), c as u32)?;
694 return Ok(());
695 },
696 _ => {},
697 }
698
699 let c = if mods.contains(Modifiers::CTRL) && ctrl_mapping(c).is_some() {
700 ctrl_mapping(c).unwrap()
701 } else {
702 c
703 };
704 if mods.contains(Modifiers::ALT) {
705 buf.push(0x1b as char);
706 }
707 write!(buf, "{}", c)?;
708 Ok(())
709}
710
711#[derive(Debug, Clone, Copy, PartialEq, Eq)]
712enum MouseButton {
713 Button1Press,
714 Button1Release,
715 Button1Drag,
716 Button2Press,
717 Button2Release,
718 Button2Drag,
719 Button3Press,
720 Button3Release,
721 Button3Drag,
722 Button4Press,
723 Button4Release,
724 Button5Press,
725 Button5Release,
726 Button6Press,
727 Button6Release,
728 Button7Press,
729 Button7Release,
730 None,
731}
732
733fn decode_mouse_button(control: u8, p0: i64) -> Option<MouseButton> {
734 match (control, p0 & 0b110_0011) {
735 (b'M', 0) => Some(MouseButton::Button1Press),
736 (b'm', 0) => Some(MouseButton::Button1Release),
737 (b'M', 1) => Some(MouseButton::Button2Press),
738 (b'm', 1) => Some(MouseButton::Button2Release),
739 (b'M', 2) => Some(MouseButton::Button3Press),
740 (b'm', 2) => Some(MouseButton::Button3Release),
741 (b'M', 64) => Some(MouseButton::Button4Press),
742 (b'm', 64) => Some(MouseButton::Button4Release),
743 (b'M', 65) => Some(MouseButton::Button5Press),
744 (b'm', 65) => Some(MouseButton::Button5Release),
745 (b'M', 66) => Some(MouseButton::Button6Press),
746 (b'm', 66) => Some(MouseButton::Button6Release),
747 (b'M', 67) => Some(MouseButton::Button7Press),
748 (b'm', 67) => Some(MouseButton::Button7Release),
749 (b'M', 32) => Some(MouseButton::Button1Drag),
750 (b'M', 33) => Some(MouseButton::Button2Drag),
751 (b'M', 34) => Some(MouseButton::Button3Drag),
752 (b'M', 35) | (b'm', 35) | (b'M', 3) | (b'm', 3) => Some(MouseButton::None),
753 _ => ::core::option::Option::None,
754 }
755}
756
757impl From<MouseButton> for MouseButtons {
758 fn from(button: MouseButton) -> MouseButtons {
759 match button {
760 MouseButton::Button1Press | MouseButton::Button1Drag => MouseButtons::LEFT,
761 MouseButton::Button2Press | MouseButton::Button2Drag => MouseButtons::MIDDLE,
762 MouseButton::Button3Press | MouseButton::Button3Drag => MouseButtons::RIGHT,
763 MouseButton::Button4Press => MouseButtons::VERT_WHEEL | MouseButtons::WHEEL_POSITIVE,
764 MouseButton::Button5Press => MouseButtons::VERT_WHEEL,
765 MouseButton::Button6Press => MouseButtons::HORZ_WHEEL | MouseButtons::WHEEL_POSITIVE,
766 MouseButton::Button7Press => MouseButtons::HORZ_WHEEL,
767 _ => MouseButtons::NONE,
768 }
769 }
770}
771
772fn decode_mouse_modifiers(p0: i64) -> Modifiers {
773 let mut modifiers = Modifiers::NONE;
774 if p0 & 4 != 0 {
775 modifiers |= Modifiers::SHIFT;
776 }
777 if p0 & 8 != 0 {
778 modifiers |= Modifiers::ALT;
779 }
780 if p0 & 16 != 0 {
781 modifiers |= Modifiers::CTRL;
782 }
783 modifiers
784}
785
786fn parse_sgr_mouse(buf: &[u8]) -> Option<(InputEvent, usize)> {
790 if buf.len() < 6 || !buf.starts_with(b"\x1b[<") {
792 return None;
793 }
794 let rest = &buf[3..]; let term_pos = rest.iter().position(|&b| b == b'M' || b == b'm')?;
798 let control = rest[term_pos];
799 let params_str = std::str::from_utf8(&rest[..term_pos]).ok()?;
800
801 let mut parts = params_str.splitn(3, ';');
803 let p0: i64 = parts.next()?.parse().ok()?;
804 let p1: i64 = parts.next()?.parse().ok()?;
805 let p2: i64 = parts.next()?.parse().ok()?;
806
807 let button = decode_mouse_button(control, p0)?;
808 let modifiers = decode_mouse_modifiers(p0);
809 let mouse_buttons: MouseButtons = button.into();
810
811 let consumed = 3 + term_pos + 1; Some((
814 InputEvent::Mouse(MouseEvent {
815 x: p1 as u16,
816 y: p2 as u16,
817 mouse_buttons,
818 modifiers,
819 }),
820 consumed,
821 ))
822}
823
824fn complete_csi_len(buf: &[u8]) -> Option<usize> {
856 if buf.get(0) != Some(&0x1b) || buf.get(1) != Some(&b'[') {
857 return None;
858 }
859 let mut i = 2;
860 let max_scan = buf.len().min(256);
861 while i < max_scan {
862 let b = buf[i];
863 match b {
864 0x30..=0x3F | 0x20..=0x2F => i += 1,
866 0x40..=0x7E => return Some(i + 1),
868 _ => return None,
870 }
871 }
872 None
873}
874
875fn parse_csi_report(buf: &[u8]) -> Option<(InputEvent, usize)> {
876 if buf.get(0) != Some(&0x1b) || buf.get(1) != Some(&b'[') {
877 return None;
878 }
879 let mut i = 2;
883 let mut intermediates: Vec<u8> = Vec::new();
884 let mut params: Vec<u8> = Vec::new();
885 let max_scan = buf.len().min(256);
889 while i < max_scan {
890 let b = buf[i];
891 match b {
892 0x30..=0x3F => {
894 params.push(b);
895 i += 1;
896 },
897 0x20..=0x2F => {
899 intermediates.push(b);
900 i += 1;
901 },
902 b't' | b'y' | b'c' | b'n' => {
904 let raw = buf[0..=i].to_vec();
905 return Some((
906 InputEvent::DeviceControlReply {
907 intermediates,
908 params,
909 final_byte: b,
910 raw,
911 },
912 i + 1,
913 ));
914 },
915 0x40..=0x7E => {
916 return None;
918 },
919 _ => {
920 return None;
922 },
923 }
924 }
925 None
926}
927
928fn parse_osc(buf: &[u8]) -> Option<(InputEvent, usize)> {
929 if buf.get(0) != Some(&0x1b) || buf.get(1) != Some(&b']') {
931 return None;
932 }
933 let mut i = 2;
934 while i < buf.len() {
935 match buf.get(i) {
936 Some(&0x07) => {
937 let payload = buf.get(2..i).unwrap_or_default().to_vec();
939 return Some((InputEvent::OperatingSystemCommand(payload), i + 1));
940 },
941 Some(&0x1b) => {
942 if buf.get(i + 1) == Some(&b'\\') {
944 let payload = buf.get(2..i).unwrap_or_default().to_vec();
945 return Some((InputEvent::OperatingSystemCommand(payload), i + 2));
946 }
947 return None;
949 },
950 Some(_) => {
951 i += 1;
952 },
953 None => {
954 return None;
956 },
957 }
958 }
959 None }
961
962#[derive(Debug, Clone, Copy, PartialEq, Eq)]
963enum InputState {
964 Normal,
965 EscapeMaybeAlt,
966 Pasting(usize),
967}
968
969#[derive(Debug)]
970pub struct InputParser {
971 key_map: KeyMap<InputEvent>,
972 buf: ReadBuffer,
973 state: InputState,
974}
975
976#[cfg(windows)]
977mod windows {
978 use super::*;
979 use std;
980 use winapi::um::wincon::{
981 INPUT_RECORD, KEY_EVENT, KEY_EVENT_RECORD, MOUSE_EVENT, MOUSE_EVENT_RECORD,
982 WINDOW_BUFFER_SIZE_EVENT, WINDOW_BUFFER_SIZE_RECORD,
983 };
984 use winapi::um::winuser;
985
986 fn modifiers_from_ctrl_key_state(state: u32) -> Modifiers {
987 use winapi::um::wincon::*;
988
989 let mut mods = Modifiers::NONE;
990
991 if (state & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) != 0 {
992 mods |= Modifiers::ALT;
993 }
994
995 if (state & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0 {
996 mods |= Modifiers::CTRL;
997 }
998
999 if (state & SHIFT_PRESSED) != 0 {
1000 mods |= Modifiers::SHIFT;
1001 }
1002
1003 mods
1004 }
1005
1006 impl InputParser {
1007 fn decode_key_record<F: FnMut(InputEvent)>(
1008 &mut self,
1009 event: &KEY_EVENT_RECORD,
1010 callback: &mut F,
1011 ) {
1012 if event.bKeyDown == 0 {
1013 return;
1014 }
1015
1016 let key_code = match std::char::from_u32(*unsafe { event.uChar.UnicodeChar() } as u32) {
1017 Some(unicode) if unicode > '\x00' => {
1018 let mut buf = [0u8; 4];
1019 self.buf
1020 .extend_with(unicode.encode_utf8(&mut buf).as_bytes());
1021 self.process_bytes(|e, _consumed| callback(e), true);
1022 return;
1023 },
1024 _ => match event.wVirtualKeyCode as i32 {
1025 winuser::VK_CANCEL => KeyCode::Cancel,
1026 winuser::VK_BACK => KeyCode::Backspace,
1027 winuser::VK_TAB => KeyCode::Tab,
1028 winuser::VK_CLEAR => KeyCode::Clear,
1029 winuser::VK_RETURN => KeyCode::Enter,
1030 winuser::VK_SHIFT => KeyCode::Shift,
1031 winuser::VK_CONTROL => KeyCode::Control,
1032 winuser::VK_MENU => KeyCode::Menu,
1033 winuser::VK_PAUSE => KeyCode::Pause,
1034 winuser::VK_CAPITAL => KeyCode::CapsLock,
1035 winuser::VK_ESCAPE => KeyCode::Escape,
1036 winuser::VK_PRIOR => KeyCode::PageUp,
1037 winuser::VK_NEXT => KeyCode::PageDown,
1038 winuser::VK_END => KeyCode::End,
1039 winuser::VK_HOME => KeyCode::Home,
1040 winuser::VK_LEFT => KeyCode::LeftArrow,
1041 winuser::VK_RIGHT => KeyCode::RightArrow,
1042 winuser::VK_UP => KeyCode::UpArrow,
1043 winuser::VK_DOWN => KeyCode::DownArrow,
1044 winuser::VK_SELECT => KeyCode::Select,
1045 winuser::VK_PRINT => KeyCode::Print,
1046 winuser::VK_EXECUTE => KeyCode::Execute,
1047 winuser::VK_SNAPSHOT => KeyCode::PrintScreen,
1048 winuser::VK_INSERT => KeyCode::Insert,
1049 winuser::VK_DELETE => KeyCode::Delete,
1050 winuser::VK_HELP => KeyCode::Help,
1051 winuser::VK_LWIN => KeyCode::LeftWindows,
1052 winuser::VK_RWIN => KeyCode::RightWindows,
1053 winuser::VK_APPS => KeyCode::Applications,
1054 winuser::VK_SLEEP => KeyCode::Sleep,
1055 winuser::VK_NUMPAD0 => KeyCode::Numpad0,
1056 winuser::VK_NUMPAD1 => KeyCode::Numpad1,
1057 winuser::VK_NUMPAD2 => KeyCode::Numpad2,
1058 winuser::VK_NUMPAD3 => KeyCode::Numpad3,
1059 winuser::VK_NUMPAD4 => KeyCode::Numpad4,
1060 winuser::VK_NUMPAD5 => KeyCode::Numpad5,
1061 winuser::VK_NUMPAD6 => KeyCode::Numpad6,
1062 winuser::VK_NUMPAD7 => KeyCode::Numpad7,
1063 winuser::VK_NUMPAD8 => KeyCode::Numpad8,
1064 winuser::VK_NUMPAD9 => KeyCode::Numpad9,
1065 winuser::VK_MULTIPLY => KeyCode::Multiply,
1066 winuser::VK_ADD => KeyCode::Add,
1067 winuser::VK_SEPARATOR => KeyCode::Separator,
1068 winuser::VK_SUBTRACT => KeyCode::Subtract,
1069 winuser::VK_DECIMAL => KeyCode::Decimal,
1070 winuser::VK_DIVIDE => KeyCode::Divide,
1071 winuser::VK_F1 => KeyCode::Function(1),
1072 winuser::VK_F2 => KeyCode::Function(2),
1073 winuser::VK_F3 => KeyCode::Function(3),
1074 winuser::VK_F4 => KeyCode::Function(4),
1075 winuser::VK_F5 => KeyCode::Function(5),
1076 winuser::VK_F6 => KeyCode::Function(6),
1077 winuser::VK_F7 => KeyCode::Function(7),
1078 winuser::VK_F8 => KeyCode::Function(8),
1079 winuser::VK_F9 => KeyCode::Function(9),
1080 winuser::VK_F10 => KeyCode::Function(10),
1081 winuser::VK_F11 => KeyCode::Function(11),
1082 winuser::VK_F12 => KeyCode::Function(12),
1083 winuser::VK_F13 => KeyCode::Function(13),
1084 winuser::VK_F14 => KeyCode::Function(14),
1085 winuser::VK_F15 => KeyCode::Function(15),
1086 winuser::VK_F16 => KeyCode::Function(16),
1087 winuser::VK_F17 => KeyCode::Function(17),
1088 winuser::VK_F18 => KeyCode::Function(18),
1089 winuser::VK_F19 => KeyCode::Function(19),
1090 winuser::VK_F20 => KeyCode::Function(20),
1091 winuser::VK_F21 => KeyCode::Function(21),
1092 winuser::VK_F22 => KeyCode::Function(22),
1093 winuser::VK_F23 => KeyCode::Function(23),
1094 winuser::VK_F24 => KeyCode::Function(24),
1095 winuser::VK_NUMLOCK => KeyCode::NumLock,
1096 winuser::VK_SCROLL => KeyCode::ScrollLock,
1097 winuser::VK_LSHIFT => KeyCode::LeftShift,
1098 winuser::VK_RSHIFT => KeyCode::RightShift,
1099 winuser::VK_LCONTROL => KeyCode::LeftControl,
1100 winuser::VK_RCONTROL => KeyCode::RightControl,
1101 winuser::VK_LMENU => KeyCode::LeftMenu,
1102 winuser::VK_RMENU => KeyCode::RightMenu,
1103 winuser::VK_BROWSER_BACK => KeyCode::BrowserBack,
1104 winuser::VK_BROWSER_FORWARD => KeyCode::BrowserForward,
1105 winuser::VK_BROWSER_REFRESH => KeyCode::BrowserRefresh,
1106 winuser::VK_BROWSER_STOP => KeyCode::BrowserStop,
1107 winuser::VK_BROWSER_SEARCH => KeyCode::BrowserSearch,
1108 winuser::VK_BROWSER_FAVORITES => KeyCode::BrowserFavorites,
1109 winuser::VK_BROWSER_HOME => KeyCode::BrowserHome,
1110 winuser::VK_VOLUME_MUTE => KeyCode::VolumeMute,
1111 winuser::VK_VOLUME_DOWN => KeyCode::VolumeDown,
1112 winuser::VK_VOLUME_UP => KeyCode::VolumeUp,
1113 winuser::VK_MEDIA_NEXT_TRACK => KeyCode::MediaNextTrack,
1114 winuser::VK_MEDIA_PREV_TRACK => KeyCode::MediaPrevTrack,
1115 winuser::VK_MEDIA_STOP => KeyCode::MediaStop,
1116 winuser::VK_MEDIA_PLAY_PAUSE => KeyCode::MediaPlayPause,
1117 _ => return,
1118 },
1119 };
1120 let mut modifiers = modifiers_from_ctrl_key_state(event.dwControlKeyState);
1121
1122 let key_code = key_code.normalize_shift_to_upper_case(modifiers);
1123 if let KeyCode::Char(c) = key_code {
1124 if c.is_ascii_uppercase() {
1125 modifiers.remove(Modifiers::SHIFT);
1126 }
1127 }
1128
1129 let input_event = InputEvent::Key(KeyEvent {
1130 key: key_code,
1131 modifiers,
1132 });
1133 for _ in 0..event.wRepeatCount {
1134 callback(input_event.clone());
1135 }
1136 }
1137
1138 fn decode_mouse_record<F: FnMut(InputEvent)>(
1139 &self,
1140 event: &MOUSE_EVENT_RECORD,
1141 callback: &mut F,
1142 ) {
1143 use winapi::um::wincon::*;
1144 let mut buttons = MouseButtons::NONE;
1145
1146 if (event.dwButtonState & FROM_LEFT_1ST_BUTTON_PRESSED) != 0 {
1147 buttons |= MouseButtons::LEFT;
1148 }
1149 if (event.dwButtonState & RIGHTMOST_BUTTON_PRESSED) != 0 {
1150 buttons |= MouseButtons::RIGHT;
1151 }
1152 if (event.dwButtonState & FROM_LEFT_2ND_BUTTON_PRESSED) != 0 {
1153 buttons |= MouseButtons::MIDDLE;
1154 }
1155
1156 let modifiers = modifiers_from_ctrl_key_state(event.dwControlKeyState);
1157
1158 if (event.dwEventFlags & MOUSE_WHEELED) != 0 {
1159 buttons |= MouseButtons::VERT_WHEEL;
1160 if (event.dwButtonState >> 8) != 0 {
1161 buttons |= MouseButtons::WHEEL_POSITIVE;
1162 }
1163 } else if (event.dwEventFlags & MOUSE_HWHEELED) != 0 {
1164 buttons |= MouseButtons::HORZ_WHEEL;
1165 if (event.dwButtonState >> 8) != 0 {
1166 buttons |= MouseButtons::WHEEL_POSITIVE;
1167 }
1168 }
1169
1170 let mouse = InputEvent::Mouse(MouseEvent {
1171 x: event.dwMousePosition.X as u16,
1172 y: event.dwMousePosition.Y as u16,
1173 mouse_buttons: buttons,
1174 modifiers,
1175 });
1176
1177 if (event.dwEventFlags & DOUBLE_CLICK) != 0 {
1178 callback(mouse.clone());
1179 }
1180 callback(mouse);
1181 }
1182
1183 fn decode_resize_record<F: FnMut(InputEvent)>(
1184 &self,
1185 event: &WINDOW_BUFFER_SIZE_RECORD,
1186 callback: &mut F,
1187 ) {
1188 callback(InputEvent::Resized {
1189 rows: event.dwSize.Y as usize,
1190 cols: event.dwSize.X as usize,
1191 });
1192 }
1193
1194 pub fn decode_input_records<F: FnMut(InputEvent)>(
1195 &mut self,
1196 records: &[INPUT_RECORD],
1197 callback: &mut F,
1198 ) {
1199 for record in records {
1200 match record.EventType {
1201 KEY_EVENT => {
1202 self.decode_key_record(unsafe { record.Event.KeyEvent() }, callback)
1203 },
1204 MOUSE_EVENT => {
1205 self.decode_mouse_record(unsafe { record.Event.MouseEvent() }, callback)
1206 },
1207 WINDOW_BUFFER_SIZE_EVENT => self.decode_resize_record(
1208 unsafe { record.Event.WindowBufferSizeEvent() },
1209 callback,
1210 ),
1211 _ => {},
1212 }
1213 }
1214 self.process_bytes(|e, _consumed| callback(e), false);
1215 }
1216 }
1217}
1218
1219impl Default for InputParser {
1220 fn default() -> Self {
1221 Self::new()
1222 }
1223}
1224
1225impl InputParser {
1226 pub fn new() -> Self {
1227 Self {
1228 key_map: Self::build_basic_key_map(),
1229 buf: ReadBuffer::new(),
1230 state: InputState::Normal,
1231 }
1232 }
1233
1234 fn build_basic_key_map() -> KeyMap<InputEvent> {
1235 let mut map = KeyMap::new();
1236
1237 let modifier_combos = &[
1238 ("", Modifiers::NONE),
1239 (";1", Modifiers::NONE),
1240 (";2", Modifiers::SHIFT),
1241 (";3", Modifiers::ALT),
1242 (";4", Modifiers::ALT | Modifiers::SHIFT),
1243 (";5", Modifiers::CTRL),
1244 (";6", Modifiers::CTRL | Modifiers::SHIFT),
1245 (";7", Modifiers::CTRL | Modifiers::ALT),
1246 (";8", Modifiers::CTRL | Modifiers::ALT | Modifiers::SHIFT),
1247 ];
1248 let meta = Modifiers::ALT;
1249 let meta_modifier_combos = &[
1250 (";9", meta),
1251 (";10", meta | Modifiers::SHIFT),
1252 (";11", meta | Modifiers::ALT),
1253 (";12", meta | Modifiers::ALT | Modifiers::SHIFT),
1254 (";13", meta | Modifiers::CTRL),
1255 (";14", meta | Modifiers::CTRL | Modifiers::SHIFT),
1256 (";15", meta | Modifiers::CTRL | Modifiers::ALT),
1257 (
1258 ";16",
1259 meta | Modifiers::CTRL | Modifiers::ALT | Modifiers::SHIFT,
1260 ),
1261 ];
1262
1263 let modifier_combos_including_meta =
1264 || modifier_combos.iter().chain(meta_modifier_combos.iter());
1265
1266 for alpha in b'A'..=b'Z' {
1267 let ctrl = [alpha & 0x1f];
1269 map.insert(
1270 &ctrl,
1271 InputEvent::Key(KeyEvent {
1272 key: KeyCode::Char((alpha as char).to_ascii_lowercase()),
1273 modifiers: Modifiers::CTRL,
1274 }),
1275 );
1276
1277 let alt = [0x1b, alpha];
1279 map.insert(
1280 &alt,
1281 InputEvent::Key(KeyEvent {
1282 key: KeyCode::Char(alpha as char),
1283 modifiers: Modifiers::ALT,
1284 }),
1285 );
1286 }
1287
1288 for c in 0..=0x7fu8 {
1289 for (suffix, modifiers) in modifier_combos {
1290 let key = format!("\x1b[{}{}u", c, suffix);
1293 map.insert(
1294 key,
1295 InputEvent::Key(KeyEvent {
1296 key: KeyCode::Char(c as char),
1297 modifiers: *modifiers,
1298 }),
1299 );
1300
1301 if !suffix.is_empty() {
1302 let key = format!("\x1b[27{};{}~", suffix, c);
1304 map.insert(
1305 key,
1306 InputEvent::Key(KeyEvent {
1307 key: match c {
1308 8 | 0x7f => KeyCode::Backspace,
1309 0x1b => KeyCode::Escape,
1310 9 => KeyCode::Tab,
1311 10 | 13 => KeyCode::Enter,
1312 _ => KeyCode::Char(c as char),
1313 },
1314 modifiers: *modifiers,
1315 }),
1316 );
1317 }
1318 }
1319 }
1320
1321 for (keycode, dir) in &[
1323 (KeyCode::UpArrow, b'A'),
1324 (KeyCode::DownArrow, b'B'),
1325 (KeyCode::RightArrow, b'C'),
1326 (KeyCode::LeftArrow, b'D'),
1327 (KeyCode::Home, b'H'),
1328 (KeyCode::End, b'F'),
1329 ] {
1330 let arrow = [0x1b, b'[', *dir];
1332 map.insert(
1333 &arrow,
1334 InputEvent::Key(KeyEvent {
1335 key: *keycode,
1336 modifiers: Modifiers::NONE,
1337 }),
1338 );
1339 for (suffix, modifiers) in modifier_combos_including_meta() {
1340 let key = format!("\x1b[1{}{}", suffix, *dir as char);
1341 map.insert(
1342 key,
1343 InputEvent::Key(KeyEvent {
1344 key: *keycode,
1345 modifiers: *modifiers,
1346 }),
1347 );
1348 }
1349 }
1350 for &(keycode, dir) in &[
1351 (KeyCode::UpArrow, b'a'),
1352 (KeyCode::DownArrow, b'b'),
1353 (KeyCode::RightArrow, b'c'),
1354 (KeyCode::LeftArrow, b'd'),
1355 ] {
1356 for &(seq, mods) in &[
1358 ([0x1b, b'[', dir], Modifiers::SHIFT),
1359 ([0x1b, b'O', dir], Modifiers::CTRL),
1360 ] {
1361 map.insert(
1362 &seq,
1363 InputEvent::Key(KeyEvent {
1364 key: keycode,
1365 modifiers: mods,
1366 }),
1367 );
1368 }
1369 }
1370
1371 for (keycode, dir) in &[
1372 (KeyCode::ApplicationUpArrow, b'A'),
1373 (KeyCode::ApplicationDownArrow, b'B'),
1374 (KeyCode::ApplicationRightArrow, b'C'),
1375 (KeyCode::ApplicationLeftArrow, b'D'),
1376 ] {
1377 let app = [0x1b, b'O', *dir];
1379 map.insert(
1380 &app,
1381 InputEvent::Key(KeyEvent {
1382 key: *keycode,
1383 modifiers: Modifiers::NONE,
1384 }),
1385 );
1386 for (suffix, modifiers) in modifier_combos {
1387 let key = format!("\x1bO1{}{}", suffix, *dir as char);
1388 map.insert(
1389 key,
1390 InputEvent::Key(KeyEvent {
1391 key: *keycode,
1392 modifiers: *modifiers,
1393 }),
1394 );
1395 }
1396 }
1397
1398 for (keycode, c) in &[
1400 (KeyCode::Function(1), b'P'),
1401 (KeyCode::Function(2), b'Q'),
1402 (KeyCode::Function(3), b'R'),
1403 (KeyCode::Function(4), b'S'),
1404 ] {
1405 let key = [0x1b, b'O', *c];
1406 map.insert(
1407 &key,
1408 InputEvent::Key(KeyEvent {
1409 key: *keycode,
1410 modifiers: Modifiers::NONE,
1411 }),
1412 );
1413 }
1414
1415 for (keycode, c) in &[
1417 (KeyCode::Function(1), b'P'),
1418 (KeyCode::Function(2), b'Q'),
1419 (KeyCode::Function(3), b'R'),
1420 (KeyCode::Function(4), b'S'),
1421 ] {
1422 for (suffix, modifiers) in modifier_combos_including_meta() {
1423 let key = format!("\x1b[1{suffix}{code}", code = *c as char, suffix = suffix);
1424 map.insert(
1425 key,
1426 InputEvent::Key(KeyEvent {
1427 key: *keycode,
1428 modifiers: *modifiers,
1429 }),
1430 );
1431 }
1432 }
1433
1434 for (range, offset) in &[
1437 (1..=5, 10),
1439 (6..=10, 11),
1441 (11..=14, 12),
1443 (15..=16, 13),
1445 (17..=20, 14),
1447 ] {
1448 for n in range.clone() {
1449 for (suffix, modifiers) in modifier_combos_including_meta() {
1450 let key = format!("\x1b[{code}{suffix}~", code = n + offset, suffix = suffix);
1451 map.insert(
1452 key,
1453 InputEvent::Key(KeyEvent {
1454 key: KeyCode::Function(n),
1455 modifiers: *modifiers,
1456 }),
1457 );
1458 }
1459 }
1460 }
1461
1462 for (keycode, c) in &[
1463 (KeyCode::Insert, b'2'),
1464 (KeyCode::Delete, b'3'),
1465 (KeyCode::Home, b'1'),
1466 (KeyCode::End, b'4'),
1467 (KeyCode::PageUp, b'5'),
1468 (KeyCode::PageDown, b'6'),
1469 (KeyCode::Home, b'7'),
1471 (KeyCode::End, b'8'),
1472 ] {
1473 for (suffix, modifiers) in &[
1474 (b'~', Modifiers::NONE),
1475 (b'$', Modifiers::SHIFT),
1476 (b'^', Modifiers::CTRL),
1477 (b'@', Modifiers::SHIFT | Modifiers::CTRL),
1478 ] {
1479 let key = [0x1b, b'[', *c, *suffix];
1480 map.insert(
1481 key,
1482 InputEvent::Key(KeyEvent {
1483 key: *keycode,
1484 modifiers: *modifiers,
1485 }),
1486 );
1487 }
1488 }
1489
1490 map.insert(
1491 &[0x7f],
1492 InputEvent::Key(KeyEvent {
1493 key: KeyCode::Backspace,
1494 modifiers: Modifiers::NONE,
1495 }),
1496 );
1497
1498 map.insert(
1499 &[0x8],
1500 InputEvent::Key(KeyEvent {
1501 key: KeyCode::Backspace,
1502 modifiers: Modifiers::NONE,
1503 }),
1504 );
1505
1506 map.insert(
1507 &[0x1b],
1508 InputEvent::Key(KeyEvent {
1509 key: KeyCode::Escape,
1510 modifiers: Modifiers::NONE,
1511 }),
1512 );
1513
1514 map.insert(
1515 &[b'\t'],
1516 InputEvent::Key(KeyEvent {
1517 key: KeyCode::Tab,
1518 modifiers: Modifiers::NONE,
1519 }),
1520 );
1521 map.insert(
1522 b"\x1b[Z",
1523 InputEvent::Key(KeyEvent {
1524 key: KeyCode::Tab,
1525 modifiers: Modifiers::SHIFT,
1526 }),
1527 );
1528
1529 map.insert(
1530 &[b'\r'],
1531 InputEvent::Key(KeyEvent {
1532 key: KeyCode::Enter,
1533 modifiers: Modifiers::NONE,
1534 }),
1535 );
1536 map.insert(
1537 &[b'\n'],
1538 InputEvent::Key(KeyEvent {
1539 key: KeyCode::Enter,
1540 modifiers: Modifiers::NONE,
1541 }),
1542 );
1543
1544 map.insert(
1545 b"\x1b[200~",
1546 InputEvent::Key(KeyEvent {
1547 key: KeyCode::InternalPasteStart,
1548 modifiers: Modifiers::NONE,
1549 }),
1550 );
1551 map.insert(
1552 b"\x1b[201~",
1553 InputEvent::Key(KeyEvent {
1554 key: KeyCode::InternalPasteEnd,
1555 modifiers: Modifiers::NONE,
1556 }),
1557 );
1558 map.insert(b"\x1b[I", InputEvent::FocusGained);
1559 map.insert(b"\x1b[O", InputEvent::FocusLost);
1560
1561 map.insert(
1562 b"\x1b[",
1563 InputEvent::Key(KeyEvent {
1564 key: KeyCode::Char('['),
1565 modifiers: Modifiers::ALT,
1566 }),
1567 );
1568
1569 map
1570 }
1571
1572 fn first_char_and_len(s: &str) -> (char, usize) {
1575 let mut iter = s.chars();
1576 let c = iter.next().unwrap();
1577 (c, c.len_utf8())
1578 }
1579
1580 fn decode_one_char(bytes: &[u8]) -> Option<(char, usize)> {
1583 let bytes = &bytes[..bytes.len().min(4)];
1584 match std::str::from_utf8(bytes) {
1585 Ok(s) => {
1586 let (c, len) = Self::first_char_and_len(s);
1587 Some((c, len))
1588 },
1589 Err(err) => {
1590 let (valid, _after_valid) = bytes.split_at(err.valid_up_to());
1591 if !valid.is_empty() {
1592 let s = unsafe { std::str::from_utf8_unchecked(valid) };
1593 let (c, len) = Self::first_char_and_len(s);
1594 Some((c, len))
1595 } else {
1596 None
1597 }
1598 },
1599 }
1600 }
1601
1602 fn dispatch_callback<F: FnMut(InputEvent, usize)>(
1603 &mut self,
1604 mut callback: F,
1605 event: InputEvent,
1606 ) {
1607 match (self.state, &event) {
1610 (
1611 InputState::Normal,
1612 InputEvent::Key(KeyEvent {
1613 key: KeyCode::InternalPasteStart,
1614 ..
1615 }),
1616 ) => {
1617 self.state = InputState::Pasting(0);
1618 },
1619 (
1620 InputState::EscapeMaybeAlt,
1621 InputEvent::Key(KeyEvent {
1622 key: KeyCode::InternalPasteStart,
1623 ..
1624 }),
1625 ) => {
1626 callback(
1629 InputEvent::Key(KeyEvent {
1630 key: KeyCode::Escape,
1631 modifiers: Modifiers::NONE,
1632 }),
1633 self.buf.len(),
1634 );
1635 self.state = InputState::Pasting(0);
1636 },
1637 (InputState::EscapeMaybeAlt, InputEvent::Key(KeyEvent { key, modifiers })) => {
1638 let key = *key;
1640 let modifiers = *modifiers;
1641 self.state = InputState::Normal;
1642 callback(
1643 InputEvent::Key(KeyEvent {
1644 key,
1645 modifiers: modifiers | Modifiers::ALT,
1646 }),
1647 self.buf.len(),
1648 );
1649 },
1650 (InputState::EscapeMaybeAlt, _) => {
1651 callback(
1654 InputEvent::Key(KeyEvent {
1655 key: KeyCode::Escape,
1656 modifiers: Modifiers::NONE,
1657 }),
1658 self.buf.len(),
1659 );
1660 callback(event, self.buf.len());
1661 },
1662 (_, _) => callback(event, self.buf.len()),
1663 }
1664 }
1665
1666 fn flush_parked_esc_if_held<F: FnMut(InputEvent, usize)>(&mut self, callback: &mut F) {
1674 if self.state == InputState::EscapeMaybeAlt {
1675 callback(
1676 InputEvent::Key(KeyEvent {
1677 key: KeyCode::Escape,
1678 modifiers: Modifiers::NONE,
1679 }),
1680 self.buf.len(),
1681 );
1682 self.state = InputState::Normal;
1683 }
1684 }
1685
1686 fn process_bytes<F: FnMut(InputEvent, usize)>(&mut self, mut callback: F, maybe_more: bool) {
1687 while !self.buf.is_empty() {
1688 match self.state {
1689 InputState::Pasting(offset) => {
1690 let end_paste = b"\x1b[201~";
1691 if let Some(idx) = self.buf.find_subsequence(offset, end_paste) {
1692 let pasted =
1693 String::from_utf8_lossy(&self.buf.as_slice()[0..idx]).to_string();
1694 self.buf.advance(pasted.len() + end_paste.len());
1695 callback(InputEvent::Paste(pasted), self.buf.len());
1696 self.state = InputState::Normal;
1697 } else {
1698 self.state =
1699 InputState::Pasting(self.buf.len().saturating_sub(end_paste.len()));
1700 return;
1701 }
1702 },
1703 InputState::EscapeMaybeAlt | InputState::Normal => {
1704 if self.buf.as_slice().get(0) == Some(&b'\x1b') {
1716 if let Some((event, len)) = parse_sgr_mouse(self.buf.as_slice()) {
1717 self.flush_parked_esc_if_held(&mut callback);
1718 self.buf.advance(len);
1719 callback(event, self.buf.len());
1720 continue;
1721 }
1722
1723 if let Some((event, len)) = parse_osc(self.buf.as_slice()) {
1725 self.flush_parked_esc_if_held(&mut callback);
1726 self.buf.advance(len);
1727 callback(event, self.buf.len());
1728 continue;
1729 }
1730
1731 if maybe_more && self.buf.as_slice().starts_with(b"\x1b]") {
1733 self.flush_parked_esc_if_held(&mut callback);
1734 return;
1735 }
1736
1737 if maybe_more && self.buf.as_slice().starts_with(b"\x1b[<") {
1738 self.flush_parked_esc_if_held(&mut callback);
1739 return;
1740 }
1741
1742 if let Some((event, len)) = parse_csi_report(self.buf.as_slice()) {
1748 self.flush_parked_esc_if_held(&mut callback);
1749 self.buf.advance(len);
1750 callback(event, self.buf.len());
1751 continue;
1752 }
1753
1754 if maybe_more && self.buf.as_slice().starts_with(b"\x1b[?") {
1759 self.flush_parked_esc_if_held(&mut callback);
1760 return;
1761 }
1762 }
1763
1764 match (
1765 self.key_map.lookup(self.buf.as_slice(), maybe_more),
1766 maybe_more,
1767 ) {
1768 (
1774 Found::Exact(
1775 len,
1776 InputEvent::Key(KeyEvent {
1777 key: KeyCode::Escape,
1778 modifiers: Modifiers::NONE,
1779 }),
1780 ),
1781 _,
1782 ) if self.state == InputState::Normal && self.buf.len() > len => {
1783 self.state = InputState::EscapeMaybeAlt;
1784 self.buf.advance(len);
1785 },
1786 (Found::Exact(len, event), _) | (Found::Ambiguous(len, event), false) => {
1787 self.buf.advance(len);
1790 self.dispatch_callback(&mut callback, event.clone());
1791 },
1792 (Found::Ambiguous(_, _), true) | (Found::NeedData, true) => {
1793 if let Some(len) = complete_csi_len(self.buf.as_slice()) {
1826 self.buf.advance(len);
1827 continue;
1828 }
1829 return;
1830 },
1831 (Found::None, _) | (Found::NeedData, false) => {
1832 if let Some((c, len)) = Self::decode_one_char(self.buf.as_slice()) {
1834 self.buf.advance(len);
1835 self.dispatch_callback(
1836 &mut callback,
1837 InputEvent::Key(KeyEvent {
1838 key: KeyCode::Char(c),
1839 modifiers: Modifiers::NONE,
1840 }),
1841 );
1842 } else {
1843 return;
1846 }
1847 },
1848 }
1849 },
1850 }
1851 }
1852 }
1853
1854 pub fn parse<F: FnMut(InputEvent)>(&mut self, bytes: &[u8], callback: F, maybe_more: bool) {
1869 let mut callback = callback;
1871 self.parse_with_consumed(bytes, |event, _consumed| callback(event), maybe_more);
1872 }
1873
1874 pub fn parse_with_consumed<F: FnMut(InputEvent, usize)>(
1880 &mut self,
1881 bytes: &[u8],
1882 mut callback: F,
1883 maybe_more: bool,
1884 ) {
1885 self.buf.extend_with(bytes);
1886 let mut prev_remaining = self.buf.len();
1889 self.process_bytes(
1890 |event, remaining| {
1891 let consumed = prev_remaining.saturating_sub(remaining);
1892 prev_remaining = remaining;
1893 callback(event, consumed);
1894 },
1895 maybe_more,
1896 );
1897 }
1898
1899 pub fn buffered_len(&self) -> usize {
1904 self.buf.len()
1905 }
1906
1907 pub fn parse_as_vec(&mut self, bytes: &[u8], maybe_more: bool) -> Vec<InputEvent> {
1908 let mut result = Vec::new();
1909 self.parse(bytes, |event| result.push(event), maybe_more);
1910 result
1911 }
1912
1913 #[cfg(windows)]
1914 pub fn decode_input_records_as_vec(
1915 &mut self,
1916 records: &[winapi::um::wincon::INPUT_RECORD],
1917 ) -> Vec<InputEvent> {
1918 let mut result = Vec::new();
1919 self.decode_input_records(records, &mut |event| result.push(event));
1920 result
1921 }
1922}
1923
1924#[cfg(test)]
1925mod test {
1926 use super::*;
1927
1928 const NO_MORE: bool = false;
1929 const MAYBE_MORE: bool = true;
1930
1931 #[test]
1932 fn simple() {
1933 let mut p = InputParser::new();
1934 let inputs = p.parse_as_vec(b"hello", NO_MORE);
1935 assert_eq!(
1936 vec![
1937 InputEvent::Key(KeyEvent {
1938 modifiers: Modifiers::NONE,
1939 key: KeyCode::Char('h'),
1940 }),
1941 InputEvent::Key(KeyEvent {
1942 modifiers: Modifiers::NONE,
1943 key: KeyCode::Char('e'),
1944 }),
1945 InputEvent::Key(KeyEvent {
1946 modifiers: Modifiers::NONE,
1947 key: KeyCode::Char('l'),
1948 }),
1949 InputEvent::Key(KeyEvent {
1950 modifiers: Modifiers::NONE,
1951 key: KeyCode::Char('l'),
1952 }),
1953 InputEvent::Key(KeyEvent {
1954 modifiers: Modifiers::NONE,
1955 key: KeyCode::Char('o'),
1956 }),
1957 ],
1958 inputs
1959 );
1960 }
1961
1962 #[test]
1963 fn control_characters() {
1964 let mut p = InputParser::new();
1965 let inputs = p.parse_as_vec(b"\x03\x1bJ\x7f", NO_MORE);
1966 assert_eq!(
1967 vec![
1968 InputEvent::Key(KeyEvent {
1969 modifiers: Modifiers::CTRL,
1970 key: KeyCode::Char('c'),
1971 }),
1972 InputEvent::Key(KeyEvent {
1973 modifiers: Modifiers::ALT,
1974 key: KeyCode::Char('J'),
1975 }),
1976 InputEvent::Key(KeyEvent {
1977 modifiers: Modifiers::NONE,
1978 key: KeyCode::Backspace,
1979 }),
1980 ],
1981 inputs
1982 );
1983 }
1984
1985 #[test]
1986 fn arrow_keys() {
1987 let mut p = InputParser::new();
1988 let inputs = p.parse_as_vec(b"\x1bOA\x1bOB\x1bOC\x1bOD", NO_MORE);
1989 assert_eq!(
1990 vec![
1991 InputEvent::Key(KeyEvent {
1992 modifiers: Modifiers::NONE,
1993 key: KeyCode::ApplicationUpArrow,
1994 }),
1995 InputEvent::Key(KeyEvent {
1996 modifiers: Modifiers::NONE,
1997 key: KeyCode::ApplicationDownArrow,
1998 }),
1999 InputEvent::Key(KeyEvent {
2000 modifiers: Modifiers::NONE,
2001 key: KeyCode::ApplicationRightArrow,
2002 }),
2003 InputEvent::Key(KeyEvent {
2004 modifiers: Modifiers::NONE,
2005 key: KeyCode::ApplicationLeftArrow,
2006 }),
2007 ],
2008 inputs
2009 );
2010 }
2011
2012 fn parse_with_raw_bytes(bytes: &[u8], maybe_more: bool) -> Vec<(InputEvent, Vec<u8>)> {
2016 let mut p = InputParser::new();
2017 let mut collected: Vec<(InputEvent, usize)> = Vec::new();
2018 p.parse_with_consumed(bytes, |ev, n| collected.push((ev, n)), maybe_more);
2019 let mut buffer: Vec<u8> = bytes.to_vec();
2020 collected
2021 .into_iter()
2022 .map(|(ev, n)| {
2023 let take = n.min(buffer.len());
2024 let raw: Vec<u8> = buffer.drain(..take).collect();
2025 (ev, raw)
2026 })
2027 .collect()
2028 }
2029
2030 #[test]
2031 fn typed_char_keeps_only_its_own_bytes_before_mouse_reports() {
2032 let events = parse_with_raw_bytes(b"a\x1b[<35;52;16M\x1b[<35;49;16M", MAYBE_MORE);
2035 assert_eq!(
2036 events.len(),
2037 3,
2038 "expected key + 2 mouse events, got {:?}",
2039 events
2040 );
2041 assert!(
2042 matches!(
2043 events[0].0,
2044 InputEvent::Key(KeyEvent {
2045 key: KeyCode::Char('a'),
2046 ..
2047 })
2048 ),
2049 "first event should be the typed key, got {:?}",
2050 events[0].0
2051 );
2052 assert_eq!(
2053 events[0].1, b"a",
2054 "the keystroke must not carry the trailing mouse bytes"
2055 );
2056 assert!(matches!(events[1].0, InputEvent::Mouse(_)));
2057 assert_eq!(events[1].1, b"\x1b[<35;52;16M");
2058 assert!(matches!(events[2].0, InputEvent::Mouse(_)));
2059 assert_eq!(events[2].1, b"\x1b[<35;49;16M");
2060 }
2061
2062 #[test]
2063 fn typed_char_keeps_only_its_own_bytes_after_mouse_reports() {
2064 let events = parse_with_raw_bytes(b"\x1b[<35;52;16Ma", MAYBE_MORE);
2067 assert_eq!(events.len(), 2, "got {:?}", events);
2068 assert!(matches!(events[0].0, InputEvent::Mouse(_)));
2069 assert_eq!(events[0].1, b"\x1b[<35;52;16M");
2070 assert!(matches!(
2071 events[1].0,
2072 InputEvent::Key(KeyEvent {
2073 key: KeyCode::Char('a'),
2074 ..
2075 })
2076 ));
2077 assert_eq!(events[1].1, b"a");
2078 }
2079
2080 #[test]
2081 fn consecutive_chars_before_mouse_each_keep_one_byte() {
2082 let events = parse_with_raw_bytes(b"ab\x1b[<35;52;16M", MAYBE_MORE);
2084 assert_eq!(events.len(), 3, "got {:?}", events);
2085 assert_eq!(events[0].1, b"a");
2086 assert_eq!(events[1].1, b"b");
2087 assert_eq!(events[2].1, b"\x1b[<35;52;16M");
2088 }
2089
2090 #[test]
2091 fn single_event_keeps_all_its_bytes() {
2092 let events = parse_with_raw_bytes(b"\x1bOA", NO_MORE);
2095 assert_eq!(events.len(), 1, "got {:?}", events);
2096 assert!(matches!(
2097 events[0].0,
2098 InputEvent::Key(KeyEvent {
2099 key: KeyCode::ApplicationUpArrow,
2100 ..
2101 })
2102 ));
2103 assert_eq!(events[0].1, b"\x1bOA");
2104 }
2105
2106 #[test]
2107 fn lone_esc_batch_then_mouse_report_batch() {
2108 let mut p = InputParser::new();
2112 let mut events: Vec<(InputEvent, usize)> = Vec::new();
2113 let mut buffer: Vec<u8> = Vec::new();
2114
2115 buffer.extend_from_slice(b"\x1b");
2116 p.parse_with_consumed(b"\x1b", |ev, n| events.push((ev, n)), MAYBE_MORE);
2117 assert!(
2118 events.is_empty(),
2119 "a lone ESC with more data possibly coming must be held, got {:?}",
2120 events
2121 );
2122
2123 buffer.extend_from_slice(b"\x1b[<35;62;16M");
2124 p.parse_with_consumed(b"\x1b[<35;62;16M", |ev, n| events.push((ev, n)), MAYBE_MORE);
2125 assert_eq!(events.len(), 2, "got {:?}", events);
2126 assert!(matches!(
2127 events[0].0,
2128 InputEvent::Key(KeyEvent {
2129 key: KeyCode::Escape,
2130 ..
2131 })
2132 ));
2133 assert_eq!(events[0].1, 1, "the ESC consumed its single byte");
2134 assert!(matches!(events[1].0, InputEvent::Mouse(_)));
2135 assert_eq!(events[1].1, 12, "the mouse report consumed its 12 bytes");
2136
2137 let esc_bytes: Vec<u8> = buffer.drain(..events[0].1).collect();
2140 let mouse_bytes: Vec<u8> = buffer.drain(..events[1].1).collect();
2141 assert_eq!(esc_bytes, b"\x1b");
2142 assert_eq!(mouse_bytes, b"\x1b[<35;62;16M");
2143 assert!(buffer.is_empty());
2144 }
2145
2146 #[test]
2147 fn paste_start_alone_is_consumed_silently_and_not_buffered() {
2148 let mut p = InputParser::new();
2149 let mut events: Vec<(InputEvent, usize)> = Vec::new();
2150 p.parse_with_consumed(b"\x1b[200~", |ev, n| events.push((ev, n)), MAYBE_MORE);
2151 assert!(
2152 events.is_empty(),
2153 "a lone paste-start marker must produce no events, got {:?}",
2154 events
2155 );
2156 assert_eq!(
2157 p.buffered_len(),
2158 0,
2159 "the paste-start bytes are consumed out of the parser buffer without any event reporting them"
2160 );
2161 }
2162
2163 #[test]
2164 fn paste_start_with_partial_payload_buffers_only_the_payload() {
2165 let mut p = InputParser::new();
2166 let mut events: Vec<(InputEvent, usize)> = Vec::new();
2167 p.parse_with_consumed(b"\x1b[200~hel", |ev, n| events.push((ev, n)), MAYBE_MORE);
2168 assert!(events.is_empty(), "got {:?}", events);
2169 assert_eq!(
2170 p.buffered_len(),
2171 3,
2172 "only the pending paste payload remains buffered; the 6 marker bytes were consumed silently"
2173 );
2174 }
2175
2176 #[test]
2177 fn parked_esc_before_partial_utf8_is_consumed_out_of_the_buffer() {
2178 let mut p = InputParser::new();
2179 let mut events: Vec<(InputEvent, usize)> = Vec::new();
2180 p.parse_with_consumed(b"\x1b\xc3", |ev, n| events.push((ev, n)), MAYBE_MORE);
2181 assert!(events.is_empty(), "got {:?}", events);
2182 assert_eq!(
2183 p.buffered_len(),
2184 1,
2185 "the parked ESC is held in parser state, not in the buffer; only the partial UTF-8 byte remains"
2186 );
2187 }
2188
2189 #[test]
2190 fn newline_then_carriage_return_are_two_enter_events_with_their_own_bytes() {
2191 let events = parse_with_raw_bytes(b"\n\r", MAYBE_MORE);
2196 assert_eq!(events.len(), 2, "got {:?}", events);
2197 for (event, raw) in &events {
2198 assert!(
2199 matches!(
2200 event,
2201 InputEvent::Key(KeyEvent {
2202 key: KeyCode::Enter,
2203 ..
2204 })
2205 ),
2206 "expected an Enter key event, got {:?}",
2207 event
2208 );
2209 assert_eq!(raw.len(), 1, "each Enter is paired with a single byte");
2210 }
2211 assert_eq!(events[0].1, b"\n");
2212 assert_eq!(events[1].1, b"\r");
2213 }
2214
2215 #[test]
2216 fn partial() {
2217 let mut p = InputParser::new();
2218 let mut inputs = Vec::new();
2219 p.parse(b"\x1b[11", |evt| inputs.push(evt), true);
2221 p.parse(b"~", |evt| inputs.push(evt), true);
2222 assert_eq!(
2224 vec![InputEvent::Key(KeyEvent {
2225 modifiers: Modifiers::NONE,
2226 key: KeyCode::Function(1),
2227 })],
2228 inputs
2229 );
2230 }
2231
2232 #[test]
2233 fn partial_ambig() {
2234 let mut p = InputParser::new();
2235
2236 assert_eq!(
2237 vec![InputEvent::Key(KeyEvent {
2238 key: KeyCode::Escape,
2239 modifiers: Modifiers::NONE,
2240 })],
2241 p.parse_as_vec(b"\x1b", false)
2242 );
2243
2244 let mut inputs = Vec::new();
2245 p.parse(b"\x1b[11", |evt| inputs.push(evt), MAYBE_MORE);
2247 p.parse(b"", |evt| inputs.push(evt), NO_MORE);
2248 assert_eq!(
2251 vec![
2252 InputEvent::Key(KeyEvent {
2253 modifiers: Modifiers::ALT,
2254 key: KeyCode::Char('['),
2255 }),
2256 InputEvent::Key(KeyEvent {
2257 modifiers: Modifiers::NONE,
2258 key: KeyCode::Char('1'),
2259 }),
2260 InputEvent::Key(KeyEvent {
2261 modifiers: Modifiers::NONE,
2262 key: KeyCode::Char('1'),
2263 }),
2264 ],
2265 inputs
2266 );
2267 }
2268
2269 #[test]
2270 fn partial_mouse() {
2271 let mut p = InputParser::new();
2272 let mut inputs = Vec::new();
2273 p.parse(b"\x1b[<0;0;0", |evt| inputs.push(evt), true);
2275 p.parse(b"M", |evt| inputs.push(evt), true);
2276 assert_eq!(
2278 vec![InputEvent::Mouse(MouseEvent {
2279 x: 0,
2280 y: 0,
2281 mouse_buttons: MouseButtons::LEFT,
2282 modifiers: Modifiers::NONE,
2283 })],
2284 inputs
2285 );
2286 }
2287
2288 #[test]
2289 fn partial_mouse_ambig() {
2290 let mut p = InputParser::new();
2291 let mut inputs = Vec::new();
2292 p.parse(b"\x1b[<", |evt| inputs.push(evt), MAYBE_MORE);
2294 p.parse(b"0;0;0", |evt| inputs.push(evt), NO_MORE);
2295 assert_eq!(
2298 vec![
2299 InputEvent::Key(KeyEvent {
2300 modifiers: Modifiers::ALT,
2301 key: KeyCode::Char('['),
2302 }),
2303 InputEvent::Key(KeyEvent {
2304 modifiers: Modifiers::NONE,
2305 key: KeyCode::Char('<'),
2306 }),
2307 InputEvent::Key(KeyEvent {
2308 modifiers: Modifiers::NONE,
2309 key: KeyCode::Char('0'),
2310 }),
2311 InputEvent::Key(KeyEvent {
2312 modifiers: Modifiers::NONE,
2313 key: KeyCode::Char(';'),
2314 }),
2315 InputEvent::Key(KeyEvent {
2316 modifiers: Modifiers::NONE,
2317 key: KeyCode::Char('0'),
2318 }),
2319 InputEvent::Key(KeyEvent {
2320 modifiers: Modifiers::NONE,
2321 key: KeyCode::Char(';'),
2322 }),
2323 InputEvent::Key(KeyEvent {
2324 modifiers: Modifiers::NONE,
2325 key: KeyCode::Char('0'),
2326 }),
2327 ],
2328 inputs
2329 );
2330 }
2331
2332 #[test]
2333 fn alt_left_bracket() {
2334 let mut p = InputParser::new();
2337
2338 let mut inputs = Vec::new();
2339 p.parse(b"\x1b[", |evt| inputs.push(evt), false);
2340
2341 assert_eq!(
2342 vec![InputEvent::Key(KeyEvent {
2343 modifiers: Modifiers::ALT,
2344 key: KeyCode::Char('['),
2345 }),],
2346 inputs
2347 );
2348 }
2349
2350 #[test]
2351 fn modify_other_keys_parse() {
2352 let mut p = InputParser::new();
2353 let inputs = p.parse_as_vec(
2354 b"\x1b[27;5;13~\x1b[27;5;9~\x1b[27;6;8~\x1b[27;2;127~\x1b[27;6;27~",
2355 NO_MORE,
2356 );
2357 assert_eq!(
2358 vec![
2359 InputEvent::Key(KeyEvent {
2360 key: KeyCode::Enter,
2361 modifiers: Modifiers::CTRL,
2362 }),
2363 InputEvent::Key(KeyEvent {
2364 key: KeyCode::Tab,
2365 modifiers: Modifiers::CTRL,
2366 }),
2367 InputEvent::Key(KeyEvent {
2368 key: KeyCode::Backspace,
2369 modifiers: Modifiers::CTRL | Modifiers::SHIFT,
2370 }),
2371 InputEvent::Key(KeyEvent {
2372 key: KeyCode::Backspace,
2373 modifiers: Modifiers::SHIFT,
2374 }),
2375 InputEvent::Key(KeyEvent {
2376 key: KeyCode::Escape,
2377 modifiers: Modifiers::CTRL | Modifiers::SHIFT,
2378 }),
2379 ],
2380 inputs
2381 );
2382 }
2383
2384 #[test]
2385 fn modify_other_keys_encode() {
2386 let mode = KeyCodeEncodeModes {
2387 encoding: KeyboardEncoding::Xterm,
2388 newline_mode: false,
2389 application_cursor_keys: false,
2390 modify_other_keys: None,
2391 };
2392 let mode_1 = KeyCodeEncodeModes {
2393 encoding: KeyboardEncoding::Xterm,
2394 newline_mode: false,
2395 application_cursor_keys: false,
2396 modify_other_keys: Some(1),
2397 };
2398 let mode_2 = KeyCodeEncodeModes {
2399 encoding: KeyboardEncoding::Xterm,
2400 newline_mode: false,
2401 application_cursor_keys: false,
2402 modify_other_keys: Some(2),
2403 };
2404
2405 assert_eq!(
2406 KeyCode::Enter.encode(Modifiers::CTRL, mode, true).unwrap(),
2407 "\r".to_string()
2408 );
2409 assert_eq!(
2410 KeyCode::Enter
2411 .encode(Modifiers::CTRL, mode_1, true)
2412 .unwrap(),
2413 "\x1b[27;5;13~".to_string()
2414 );
2415 assert_eq!(
2416 KeyCode::Enter
2417 .encode(Modifiers::CTRL | Modifiers::SHIFT, mode_1, true)
2418 .unwrap(),
2419 "\x1b[27;6;13~".to_string()
2420 );
2421
2422 assert_eq!(
2426 KeyCode::Tab.encode(Modifiers::CTRL, mode, true).unwrap(),
2427 "\x1b[9;5u".to_string()
2428 );
2429 assert_eq!(
2430 KeyCode::Tab.encode(Modifiers::CTRL, mode_1, true).unwrap(),
2431 "\x1b[27;5;9~".to_string()
2432 );
2433 assert_eq!(
2434 KeyCode::Tab
2435 .encode(Modifiers::CTRL | Modifiers::SHIFT, mode_1, true)
2436 .unwrap(),
2437 "\x1b[27;6;9~".to_string()
2438 );
2439
2440 assert_eq!(
2441 KeyCode::Char('c')
2442 .encode(Modifiers::CTRL, mode, true)
2443 .unwrap(),
2444 "\x03".to_string()
2445 );
2446 assert_eq!(
2447 KeyCode::Char('c')
2448 .encode(Modifiers::CTRL, mode_1, true)
2449 .unwrap(),
2450 "\x03".to_string()
2451 );
2452 assert_eq!(
2453 KeyCode::Char('c')
2454 .encode(Modifiers::CTRL, mode_2, true)
2455 .unwrap(),
2456 "\x1b[27;5;99~".to_string()
2457 );
2458
2459 assert_eq!(
2460 KeyCode::Char('1')
2461 .encode(Modifiers::CTRL, mode, true)
2462 .unwrap(),
2463 "1".to_string()
2464 );
2465 assert_eq!(
2466 KeyCode::Char('1')
2467 .encode(Modifiers::CTRL, mode_2, true)
2468 .unwrap(),
2469 "\x1b[27;5;49~".to_string()
2470 );
2471
2472 assert_eq!(
2473 KeyCode::Char(',')
2474 .encode(Modifiers::CTRL, mode, true)
2475 .unwrap(),
2476 ",".to_string()
2477 );
2478 assert_eq!(
2479 KeyCode::Char(',')
2480 .encode(Modifiers::CTRL, mode_2, true)
2481 .unwrap(),
2482 "\x1b[27;5;44~".to_string()
2483 );
2484 }
2485
2486 #[test]
2487 fn encode_issue_892() {
2488 let mode = KeyCodeEncodeModes {
2489 encoding: KeyboardEncoding::Xterm,
2490 newline_mode: false,
2491 application_cursor_keys: false,
2492 modify_other_keys: None,
2493 };
2494
2495 assert_eq!(
2496 KeyCode::LeftArrow
2497 .encode(Modifiers::NONE, mode, true)
2498 .unwrap(),
2499 "\x1b[D".to_string()
2500 );
2501 assert_eq!(
2502 KeyCode::LeftArrow
2503 .encode(Modifiers::ALT, mode, true)
2504 .unwrap(),
2505 "\x1b[1;3D".to_string()
2506 );
2507 assert_eq!(
2508 KeyCode::Home.encode(Modifiers::NONE, mode, true).unwrap(),
2509 "\x1b[H".to_string()
2510 );
2511 assert_eq!(
2512 KeyCode::Home.encode(Modifiers::ALT, mode, true).unwrap(),
2513 "\x1b[1;3H".to_string()
2514 );
2515 assert_eq!(
2516 KeyCode::End.encode(Modifiers::NONE, mode, true).unwrap(),
2517 "\x1b[F".to_string()
2518 );
2519 assert_eq!(
2520 KeyCode::End.encode(Modifiers::ALT, mode, true).unwrap(),
2521 "\x1b[1;3F".to_string()
2522 );
2523 assert_eq!(
2524 KeyCode::Tab.encode(Modifiers::ALT, mode, true).unwrap(),
2525 "\x1b\t".to_string()
2526 );
2527 assert_eq!(
2528 KeyCode::PageUp.encode(Modifiers::ALT, mode, true).unwrap(),
2529 "\x1b[5;3~".to_string()
2530 );
2531 assert_eq!(
2532 KeyCode::Function(1)
2533 .encode(Modifiers::NONE, mode, true)
2534 .unwrap(),
2535 "\x1bOP".to_string()
2536 );
2537 }
2538
2539 #[test]
2540 fn partial_bracketed_paste() {
2541 let mut p = InputParser::new();
2542
2543 let input = b"\x1b[200~1234";
2544 let input2 = b"5678\x1b[201~";
2545
2546 let mut inputs = vec![];
2547
2548 p.parse(input, |e| inputs.push(e), false);
2549 p.parse(input2, |e| inputs.push(e), false);
2550
2551 assert_eq!(vec![InputEvent::Paste("12345678".to_owned())], inputs)
2552 }
2553
2554 #[test]
2555 fn mouse_horizontal_scroll() {
2556 let mut p = InputParser::new();
2557
2558 let input = b"\x1b[<66;42;12M\x1b[<67;42;12M";
2559 let res = p.parse_as_vec(input, MAYBE_MORE);
2560
2561 assert_eq!(
2562 vec![
2563 InputEvent::Mouse(MouseEvent {
2564 x: 42,
2565 y: 12,
2566 mouse_buttons: MouseButtons::HORZ_WHEEL | MouseButtons::WHEEL_POSITIVE,
2567 modifiers: Modifiers::NONE,
2568 }),
2569 InputEvent::Mouse(MouseEvent {
2570 x: 42,
2571 y: 12,
2572 mouse_buttons: MouseButtons::HORZ_WHEEL,
2573 modifiers: Modifiers::NONE,
2574 })
2575 ],
2576 res
2577 );
2578 }
2579
2580 #[test]
2581 fn encode_issue_3478_xterm() {
2582 let mode = KeyCodeEncodeModes {
2583 encoding: KeyboardEncoding::Xterm,
2584 newline_mode: false,
2585 application_cursor_keys: false,
2586 modify_other_keys: None,
2587 };
2588
2589 assert_eq!(
2590 KeyCode::Numpad0
2591 .encode(Modifiers::NONE, mode, true)
2592 .unwrap(),
2593 "\u{1b}[2~".to_string()
2594 );
2595 assert_eq!(
2596 KeyCode::Numpad0
2597 .encode(Modifiers::SHIFT, mode, true)
2598 .unwrap(),
2599 "\u{1b}[2;2~".to_string()
2600 );
2601
2602 assert_eq!(
2603 KeyCode::Numpad1
2604 .encode(Modifiers::NONE, mode, true)
2605 .unwrap(),
2606 "\u{1b}[F".to_string()
2607 );
2608 assert_eq!(
2609 KeyCode::Numpad1
2610 .encode(Modifiers::NONE | Modifiers::SHIFT, mode, true)
2611 .unwrap(),
2612 "\u{1b}[1;2F".to_string()
2613 );
2614 }
2615
2616 #[test]
2617 fn encode_tab_with_modifiers() {
2618 let mode = KeyCodeEncodeModes {
2619 encoding: KeyboardEncoding::Xterm,
2620 newline_mode: false,
2621 application_cursor_keys: false,
2622 modify_other_keys: None,
2623 };
2624
2625 let mods_to_result = [
2626 (Modifiers::SHIFT, "\u{1b}[Z"),
2627 (Modifiers::SHIFT | Modifiers::LEFT_SHIFT, "\u{1b}[Z"),
2628 (Modifiers::SHIFT | Modifiers::RIGHT_SHIFT, "\u{1b}[Z"),
2629 (Modifiers::CTRL, "\u{1b}[9;5u"),
2630 (Modifiers::CTRL | Modifiers::LEFT_CTRL, "\u{1b}[9;5u"),
2631 (Modifiers::CTRL | Modifiers::RIGHT_CTRL, "\u{1b}[9;5u"),
2632 (
2633 Modifiers::SHIFT | Modifiers::CTRL | Modifiers::LEFT_CTRL | Modifiers::LEFT_SHIFT,
2634 "\u{1b}[1;5Z",
2635 ),
2636 ];
2637 for (mods, result) in mods_to_result {
2638 assert_eq!(
2639 KeyCode::Tab.encode(mods, mode, true).unwrap(),
2640 result,
2641 "{:?}",
2642 mods
2643 );
2644 }
2645 }
2646
2647 #[test]
2648 fn mouse_button1_press() {
2649 let mut p = InputParser::new();
2650 let res = p.parse_as_vec(b"\x1b[<0;42;12M", true);
2651 assert_eq!(
2652 res,
2653 vec![InputEvent::Mouse(MouseEvent {
2654 x: 42,
2655 y: 12,
2656 mouse_buttons: MouseButtons::LEFT,
2657 modifiers: Modifiers::NONE,
2658 })]
2659 );
2660 }
2661
2662 #[test]
2663 fn mouse_button1_release() {
2664 let mut p = InputParser::new();
2665 let res = p.parse_as_vec(b"\x1b[<0;42;12m", true);
2666 assert_eq!(
2667 res,
2668 vec![InputEvent::Mouse(MouseEvent {
2669 x: 42,
2670 y: 12,
2671 mouse_buttons: MouseButtons::NONE,
2672 modifiers: Modifiers::NONE,
2673 })]
2674 );
2675 }
2676
2677 #[test]
2678 fn mouse_button3_with_shift() {
2679 let mut p = InputParser::new();
2680 let res = p.parse_as_vec(b"\x1b[<6;10;20M", true);
2682 assert_eq!(
2683 res,
2684 vec![InputEvent::Mouse(MouseEvent {
2685 x: 10,
2686 y: 20,
2687 mouse_buttons: MouseButtons::RIGHT,
2688 modifiers: Modifiers::SHIFT,
2689 })]
2690 );
2691 }
2692
2693 #[test]
2694 fn mouse_drag() {
2695 let mut p = InputParser::new();
2696 let res = p.parse_as_vec(b"\x1b[<32;5;5M", true);
2698 assert_eq!(
2699 res,
2700 vec![InputEvent::Mouse(MouseEvent {
2701 x: 5,
2702 y: 5,
2703 mouse_buttons: MouseButtons::LEFT,
2704 modifiers: Modifiers::NONE,
2705 })]
2706 );
2707 }
2708
2709 #[test]
2710 fn mouse_vertical_scroll_up() {
2711 let mut p = InputParser::new();
2712 let res = p.parse_as_vec(b"\x1b[<64;1;1M", true);
2714 assert_eq!(
2715 res,
2716 vec![InputEvent::Mouse(MouseEvent {
2717 x: 1,
2718 y: 1,
2719 mouse_buttons: MouseButtons::VERT_WHEEL | MouseButtons::WHEEL_POSITIVE,
2720 modifiers: Modifiers::NONE,
2721 })]
2722 );
2723 }
2724
2725 #[test]
2726 fn mouse_vertical_scroll_down() {
2727 let mut p = InputParser::new();
2728 let res = p.parse_as_vec(b"\x1b[<65;1;1M", true);
2730 assert_eq!(
2731 res,
2732 vec![InputEvent::Mouse(MouseEvent {
2733 x: 1,
2734 y: 1,
2735 mouse_buttons: MouseButtons::VERT_WHEEL,
2736 modifiers: Modifiers::NONE,
2737 })]
2738 );
2739 }
2740
2741 #[test]
2742 fn mouse_motion_no_buttons() {
2743 let mut p = InputParser::new();
2744 let res = p.parse_as_vec(b"\x1b[<35;10;10M", true);
2746 assert_eq!(
2747 res,
2748 vec![InputEvent::Mouse(MouseEvent {
2749 x: 10,
2750 y: 10,
2751 mouse_buttons: MouseButtons::NONE,
2752 modifiers: Modifiers::NONE,
2753 })]
2754 );
2755 }
2756
2757 #[test]
2758 fn mouse_with_ctrl_alt() {
2759 let mut p = InputParser::new();
2760 let res = p.parse_as_vec(b"\x1b[<24;1;1M", true);
2762 assert_eq!(
2763 res,
2764 vec![InputEvent::Mouse(MouseEvent {
2765 x: 1,
2766 y: 1,
2767 mouse_buttons: MouseButtons::LEFT,
2768 modifiers: Modifiers::ALT | Modifiers::CTRL,
2769 })]
2770 );
2771 }
2772
2773 #[test]
2774 fn mouse_large_coordinates() {
2775 let mut p = InputParser::new();
2776 let res = p.parse_as_vec(b"\x1b[<0;999;999M", true);
2777 assert_eq!(
2778 res,
2779 vec![InputEvent::Mouse(MouseEvent {
2780 x: 999,
2781 y: 999,
2782 mouse_buttons: MouseButtons::LEFT,
2783 modifiers: Modifiers::NONE,
2784 })]
2785 );
2786 }
2787
2788 #[test]
2789 fn mouse_followed_by_key() {
2790 let mut p = InputParser::new();
2791 let res = p.parse_as_vec(b"\x1b[<0;1;1Mhello", false);
2792 assert_eq!(res.len(), 6); assert!(matches!(res[0], InputEvent::Mouse(_)));
2794 assert!(matches!(res[1], InputEvent::Key(_)));
2795 }
2796
2797 #[test]
2798 fn two_mouse_events_back_to_back() {
2799 let mut p = InputParser::new();
2800 let res = p.parse_as_vec(b"\x1b[<0;1;1M\x1b[<0;2;2M", true);
2801 assert_eq!(res.len(), 2);
2802 }
2803
2804 #[test]
2812 fn esc_then_sgr_mouse_emits_esc_and_mouse() {
2813 let mut p = InputParser::new();
2814 let res = p.parse_as_vec(b"\x1b\x1b[<35;42;12M", MAYBE_MORE);
2815 assert_eq!(
2816 res,
2817 vec![
2818 InputEvent::Key(KeyEvent {
2819 key: KeyCode::Escape,
2820 modifiers: Modifiers::NONE,
2821 }),
2822 InputEvent::Mouse(MouseEvent {
2823 x: 42,
2824 y: 12,
2825 mouse_buttons: MouseButtons::NONE,
2826 modifiers: Modifiers::NONE,
2827 }),
2828 ]
2829 );
2830 }
2831
2832 #[test]
2836 fn esc_then_sgr_mouse_across_parse_calls() {
2837 let mut p = InputParser::new();
2838
2839 let mut res = p.parse_as_vec(b"\x1b", MAYBE_MORE);
2844 assert!(
2845 res.is_empty(),
2846 "lone ESC should not emit yet under MAYBE_MORE"
2847 );
2848
2849 res = p.parse_as_vec(b"\x1b[<35;42;12M", MAYBE_MORE);
2855 assert_eq!(
2856 res,
2857 vec![
2858 InputEvent::Key(KeyEvent {
2859 key: KeyCode::Escape,
2860 modifiers: Modifiers::NONE,
2861 }),
2862 InputEvent::Mouse(MouseEvent {
2863 x: 42,
2864 y: 12,
2865 mouse_buttons: MouseButtons::NONE,
2866 modifiers: Modifiers::NONE,
2867 }),
2868 ]
2869 );
2870 }
2871
2872 #[test]
2876 fn alt_esc_still_recognized() {
2877 let mut p = InputParser::new();
2878 let res = p.parse_as_vec(b"\x1b\x1b", NO_MORE);
2879 assert_eq!(
2880 res,
2881 vec![InputEvent::Key(KeyEvent {
2882 key: KeyCode::Escape,
2883 modifiers: Modifiers::ALT,
2884 })]
2885 );
2886 }
2887
2888 #[test]
2893 fn esc_then_osc_emits_esc_and_osc() {
2894 let mut p = InputParser::new();
2895 let res = p.parse_as_vec(b"\x1b\x1b]11;rgb:ffff/ffff/ffff\x1b\\", MAYBE_MORE);
2896 assert_eq!(
2897 res,
2898 vec![
2899 InputEvent::Key(KeyEvent {
2900 key: KeyCode::Escape,
2901 modifiers: Modifiers::NONE,
2902 }),
2903 InputEvent::OperatingSystemCommand(b"11;rgb:ffff/ffff/ffff".to_vec()),
2904 ]
2905 );
2906 }
2907
2908 #[test]
2911 fn esc_then_csi_report_emits_esc_and_report() {
2912 let mut p = InputParser::new();
2913 let res = p.parse_as_vec(b"\x1b\x1b[?2026;0$y", MAYBE_MORE);
2916 assert!(
2917 !res.is_empty(),
2918 "expected at least one event from Esc + CSI report"
2919 );
2920 assert!(
2921 matches!(
2922 res[0],
2923 InputEvent::Key(KeyEvent {
2924 key: KeyCode::Escape,
2925 modifiers: Modifiers::NONE,
2926 })
2927 ),
2928 "first event must be a bare Esc keystroke, got {:?}",
2929 res[0]
2930 );
2931 for ev in &res {
2936 if let InputEvent::Key(KeyEvent { key, modifiers }) = ev {
2937 assert!(
2938 !(matches!(key, KeyCode::Char('[')) && modifiers.contains(Modifiers::ALT)),
2939 "must not emit Alt+`[`; got {:?}",
2940 ev
2941 );
2942 }
2943 }
2944 }
2945
2946 #[test]
2947 fn invalid_sgr_mouse_falls_through() {
2948 let mut p = InputParser::new();
2949 let res = p.parse_as_vec(b"\x1b[<0;1M", false);
2951 assert!(res.iter().all(|e| matches!(e, InputEvent::Key(_))));
2953 }
2954
2955 #[test]
2956 fn osc_bel_terminated() {
2957 let mut p = InputParser::new();
2959 let inputs = p.parse_as_vec(b"\x1b]99;i=test:p=title;Hello\x07", NO_MORE);
2960 assert_eq!(
2961 vec![InputEvent::OperatingSystemCommand(
2962 b"99;i=test:p=title;Hello".to_vec()
2963 )],
2964 inputs
2965 );
2966 }
2967
2968 #[test]
2969 fn osc_st_terminated() {
2970 let mut p = InputParser::new();
2972 let inputs = p.parse_as_vec(b"\x1b]99;i=test:p=title;Hello\x1b\\", NO_MORE);
2973 assert_eq!(
2974 vec![InputEvent::OperatingSystemCommand(
2975 b"99;i=test:p=title;Hello".to_vec()
2976 )],
2977 inputs
2978 );
2979 }
2980
2981 #[test]
2982 fn osc_partial_across_reads() {
2983 let mut p = InputParser::new();
2985 let mut inputs = Vec::new();
2986 p.parse(
2987 b"\x1b]99;i=test:p=title;Hel",
2988 |evt| inputs.push(evt),
2989 MAYBE_MORE,
2990 );
2991 assert!(inputs.is_empty(), "no events yet - sequence incomplete");
2992 p.parse(b"lo\x1b\\", |evt| inputs.push(evt), MAYBE_MORE);
2993 assert_eq!(
2994 vec![InputEvent::OperatingSystemCommand(
2995 b"99;i=test:p=title;Hello".to_vec()
2996 )],
2997 inputs
2998 );
2999 }
3000
3001 #[test]
3002 fn osc_followed_by_keypress() {
3003 let mut p = InputParser::new();
3005 let inputs = p.parse_as_vec(b"\x1b]99;i=test;clicked\x07x", NO_MORE);
3006 assert_eq!(
3007 vec![
3008 InputEvent::OperatingSystemCommand(b"99;i=test;clicked".to_vec()),
3009 InputEvent::Key(KeyEvent {
3010 modifiers: Modifiers::NONE,
3011 key: KeyCode::Char('x'),
3012 }),
3013 ],
3014 inputs
3015 );
3016 }
3017
3018 #[test]
3019 fn keypress_followed_by_osc() {
3020 let mut p = InputParser::new();
3022 let inputs = p.parse_as_vec(b"x\x1b]99;i=test;clicked\x07", NO_MORE);
3023 assert_eq!(
3024 vec![
3025 InputEvent::Key(KeyEvent {
3026 modifiers: Modifiers::NONE,
3027 key: KeyCode::Char('x'),
3028 }),
3029 InputEvent::OperatingSystemCommand(b"99;i=test;clicked".to_vec()),
3030 ],
3031 inputs
3032 );
3033 }
3034
3035 #[test]
3036 fn osc_incomplete_degrades_to_keys() {
3037 let mut p = InputParser::new();
3040 let mut inputs = Vec::new();
3041 p.parse(b"\x1b]99;no-terminator", |evt| inputs.push(evt), MAYBE_MORE);
3042 assert!(inputs.is_empty(), "buffered while maybe_more=true");
3043 p.parse(b"", |evt| inputs.push(evt), NO_MORE);
3044 assert!(!inputs.is_empty(), "must emit something on finalization");
3045 }
3046
3047 #[test]
3048 fn osc_non_99_code() {
3049 let mut p = InputParser::new();
3051 let inputs = p.parse_as_vec(b"\x1b]11;rgb:0000/0000/0000\x1b\\", NO_MORE);
3052 assert_eq!(
3053 vec![InputEvent::OperatingSystemCommand(
3054 b"11;rgb:0000/0000/0000".to_vec()
3055 )],
3056 inputs
3057 );
3058 }
3059
3060 #[test]
3061 fn osc_empty_payload() {
3062 let mut p = InputParser::new();
3064 let inputs = p.parse_as_vec(b"\x1b]\x07", NO_MORE);
3065 assert_eq!(
3066 vec![InputEvent::OperatingSystemCommand(b"".to_vec())],
3067 inputs
3068 );
3069 }
3070
3071 #[test]
3072 fn csi_not_captured_as_osc() {
3073 let mut p = InputParser::new();
3076 let inputs = p.parse_as_vec(b"\x1b[A", NO_MORE);
3077 assert_eq!(
3078 vec![InputEvent::Key(KeyEvent {
3079 modifiers: Modifiers::NONE,
3080 key: KeyCode::UpArrow,
3081 })],
3082 inputs
3083 );
3084 }
3085
3086 fn csi_reply(intermediates: &[u8], params: &[u8], final_byte: u8, raw: &[u8]) -> InputEvent {
3091 InputEvent::DeviceControlReply {
3092 intermediates: intermediates.to_vec(),
3093 params: params.to_vec(),
3094 final_byte,
3095 raw: raw.to_vec(),
3096 }
3097 }
3098
3099 #[test]
3100 fn csi_report_recognises_each_whitelisted_final_byte() {
3101 let bytes = b"\x1b[4;600;800t";
3103 let (evt, consumed) = parse_csi_report(bytes).expect("t accepted");
3104 assert_eq!(consumed, bytes.len());
3105 assert_eq!(evt, csi_reply(b"", b"4;600;800", b't', bytes));
3106
3107 let bytes = b"\x1b[?2026;1$y";
3109 let (evt, consumed) = parse_csi_report(bytes).expect("y accepted");
3110 assert_eq!(consumed, bytes.len());
3111 assert_eq!(evt, csi_reply(b"$", b"?2026;1", b'y', bytes));
3112
3113 let bytes = b"\x1b[?62;1;6c";
3115 let (evt, consumed) = parse_csi_report(bytes).expect("c accepted");
3116 assert_eq!(consumed, bytes.len());
3117 assert_eq!(evt, csi_reply(b"", b"?62;1;6", b'c', bytes));
3118
3119 let bytes = b"\x1b[?997;1n";
3121 let (evt, consumed) = parse_csi_report(bytes).expect("n accepted");
3122 assert_eq!(consumed, bytes.len());
3123 assert_eq!(evt, csi_reply(b"", b"?997;1", b'n', bytes));
3124 }
3125
3126 #[test]
3127 fn csi_report_preserves_intermediates() {
3128 let bytes = b"\x1b[?2026;2$y";
3131 let (evt, _len) = parse_csi_report(bytes).expect("DECRPM accepted");
3132 let InputEvent::DeviceControlReply {
3133 intermediates,
3134 params,
3135 final_byte,
3136 raw,
3137 } = evt
3138 else {
3139 panic!("expected DeviceControlReply, got {:?}", evt);
3140 };
3141 assert_eq!(intermediates, b"$");
3142 assert_eq!(params, b"?2026;2");
3143 assert_eq!(final_byte, b'y');
3144 assert_eq!(raw, bytes);
3145 }
3146
3147 #[test]
3148 fn csi_report_rejects_non_whitelisted_final_bytes() {
3149 assert!(parse_csi_report(b"\x1b[A").is_none());
3151 assert!(parse_csi_report(b"\x1b[24;80R").is_none());
3154 assert!(parse_csi_report(b"\x1b[0m").is_none());
3157 }
3158
3159 #[test]
3160 fn csi_report_returns_none_on_truncated_input() {
3161 assert!(parse_csi_report(b"\x1b[4;600;800").is_none());
3165 assert!(parse_csi_report(b"\x1b[").is_none());
3167 assert!(parse_csi_report(b"").is_none());
3169 }
3170
3171 #[test]
3172 fn csi_report_raw_preserves_input_byte_for_byte() {
3173 let bytes = b"\x1b[4;16;8t";
3177 let (evt, consumed) = parse_csi_report(bytes).expect("accepted");
3178 assert_eq!(consumed, bytes.len());
3179 let InputEvent::DeviceControlReply { raw, .. } = evt else {
3180 panic!("wrong variant");
3181 };
3182 assert_eq!(&raw[..], bytes, "raw must be byte-identical to input");
3183 }
3184
3185 #[test]
3186 fn focus_reports_decode_as_focus_events() {
3187 let mut p = InputParser::new();
3188 assert_eq!(
3189 p.parse_as_vec(b"\x1b[I", MAYBE_MORE),
3190 vec![InputEvent::FocusGained],
3191 );
3192 assert_eq!(
3193 p.parse_as_vec(b"\x1b[O", MAYBE_MORE),
3194 vec![InputEvent::FocusLost],
3195 );
3196 }
3197
3198 #[test]
3199 fn focus_report_split_across_reads_still_decodes_as_one_event() {
3200 let mut p = InputParser::new();
3201 assert_eq!(p.parse_as_vec(b"\x1b[", MAYBE_MORE), vec![]);
3202 assert_eq!(
3203 p.parse_as_vec(b"I", MAYBE_MORE),
3204 vec![InputEvent::FocusGained],
3205 );
3206 }
3207
3208 #[test]
3209 fn focus_reports_never_degrade_into_literal_characters() {
3210 let mut p = InputParser::new();
3211 let events = p.parse_as_vec(b"\x1b[O\x1b[I", MAYBE_MORE);
3212 assert_eq!(
3213 events,
3214 vec![InputEvent::FocusLost, InputEvent::FocusGained],
3215 "a focus report must not decode as Alt+[ plus a literal I/O keystroke"
3216 );
3217 }
3218
3219 #[test]
3220 fn alt_bracket_is_still_recognized_for_other_following_bytes() {
3221 let mut p = InputParser::new();
3222 assert_eq!(
3223 p.parse_as_vec(b"\x1b[x", MAYBE_MORE),
3224 vec![
3225 InputEvent::Key(KeyEvent {
3226 key: KeyCode::Char('['),
3227 modifiers: Modifiers::ALT,
3228 }),
3229 InputEvent::Key(KeyEvent {
3230 key: KeyCode::Char('x'),
3231 modifiers: Modifiers::NONE,
3232 }),
3233 ],
3234 );
3235 }
3236}