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