Skip to main content

zellij_utils/vendored/termwiz/
input.rs

1//! This module provides an InputParser struct to help with parsing
2//! input received from a terminal.
3use 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        /// if set then the wheel movement was in the positive
116        /// direction, else the negative direction
117        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    /// Detected that the user has resized the terminal
130    Resized {
131        cols: usize,
132        rows: usize,
133    },
134    /// For terminals that support Bracketed Paste mode,
135    /// pastes are collected and reported as this variant.
136    Paste(String),
137    /// The program has woken the input thread.
138    Wake,
139    /// An Operating System Command sequence was received.
140    /// Contains the raw payload between \x1b] and the terminator.
141    OperatingSystemCommand(Vec<u8>),
142    /// A CSI-based device control / status report reply emitted by the
143    /// host terminal (not a keyboard event). This variant is only produced
144    /// for a deliberately narrow whitelist of final bytes — `t` (pixel
145    /// dimensions reply), `y` (DECRPM reply), `c` (Primary-DA reply), and
146    /// `n` (DSR reply). The raw field contains the exact byte sequence of
147    /// the original report (including the leading ESC) so it can be
148    /// forwarded verbatim without re-serialization.
149    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    /// Which key was pressed
178    pub key: KeyCode,
179    /// Which modifiers are down
180    pub modifiers: Modifiers,
181}
182
183#[derive(Debug, Clone, Copy, PartialEq, Eq)]
184pub enum KeyboardEncoding {
185    Xterm,
186    /// <http://www.leonerd.org.uk/hacks/fixterms/>
187    CsiU,
188    /// <https://github.com/microsoft/terminal/blob/main/doc/specs/%234999%20-%20Improved%20keyboard%20handling%20in%20Conpty.md>
189    Win32,
190    /// <https://sw.kovidgoyal.net/kitty/keyboard-protocol/>
191    Kitty(KittyKeyboardFlags),
192}
193
194/// Specifies terminal modes/configuration that can influence how a KeyCode
195/// is encoded when being sent to and application via the pty.
196#[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/// Which key is pressed.  Not all of these are probable to appear
205/// on most systems.  A lot of this list is @wez trawling docs and
206/// making an entry for things that might be possible in this first pass.
207#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
208pub enum KeyCode {
209    /// The decoded unicode character
210    Char(char),
211
212    Hyper,
213    Super,
214    Meta,
215
216    /// Ctrl-break on windows
217    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    /// F1-F24 are possible
273    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    /// if SHIFT is held and we have KeyCode::Char('c') we want to normalize
311    /// that keycode to KeyCode::Char('C'); that is what this function does.
312    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    /// Return true if the key represents a modifier key.
324    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    /// Returns the byte sequence that represents this KeyCode and Modifier combination.
345    pub fn encode(
346        &self,
347        mods: Modifiers,
348        modes: KeyCodeEncodeModes,
349        is_down: bool,
350    ) -> Result<String> {
351        if !is_down {
352            // We only want down events
353            return Ok(String::new());
354        }
355        // We are encoding the key as an xterm-compatible sequence, which does not support
356        // positional modifiers.
357        let mods = mods.remove_positional_mods();
358
359        use KeyCode::*;
360
361        let key = self.normalize_shift_to_upper_case(mods);
362        // Normalize the modifier state for Char's that are uppercase; remove
363        // the SHIFT modifier so that reduce ambiguity below
364        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        // Normalize Backspace and Delete
375        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        // TODO: also respect self.application_keypad
384
385        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            // When alt is pressed, send escape first to indicate to the peer that
409            // ALT is pressed.  We do this only for ascii alnum characters because
410            // eg: on macOS generates altgr style glyphs and keeps the ALT key
411            // in the modifier set.  This confuses eg: zsh which then just displays
412            // <fffffffff> as the input, so we want to avoid that.
413            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                // Backspace sends the default VERASE which is confusingly
423                // the DEL ascii codepoint rather than BS.
424                // We only send BS when CTRL is held.
425                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                    // Use SS3 in application mode
512                    SS3
513                } else {
514                    // otherwise use regular CSI
515                    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                    // F1-F4 are encoded using SS3 if there are no modifiers
550                    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                    // Special case for F1-F4 with modifiers
563                    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                    // Higher numbered F-keys using CSI instead of SS3.
573                    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                        // If no modifiers are held, don't send the modifier
603                        // sequence, as the modifier encoding is a CSI-u extension.
604                        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            // Modifier keys pressed on their own don't expand to anything
651            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
665/// characters that when masked for CTRL could be an ascii control character
666/// or could be a key that a user legitimately wants to process in their
667/// terminal application
668fn 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    // <https://invisible-island.net/xterm/modified-keys.html>
688    match (c, modes.modify_other_keys) {
689        ('c' | 'd' | '\x1b' | '\x7f' | '\x08', Some(1)) => {
690            // Exclude well-known keys from modifyOtherKeys mode 1
691        },
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
786/// Try to parse an SGR mouse sequence from the buffer.
787/// Returns Some((InputEvent, bytes_consumed)) on success.
788/// Returns None if the buffer does not contain a complete SGR mouse sequence.
789fn parse_sgr_mouse(buf: &[u8]) -> Option<(InputEvent, usize)> {
790    // Must start with \x1b[<
791    if buf.len() < 6 || !buf.starts_with(b"\x1b[<") {
792        return None;
793    }
794    let rest = &buf[3..]; // skip \x1b[<
795
796    // Find the terminating M or m
797    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    // Parse three semicolon-separated integers
802    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; // \x1b[< + params + M/m
812
813    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
824/// Attempt to parse an OSC (Operating System Command) sequence from the buffer.
825/// Returns `Some((InputEvent::OperatingSystemCommand(payload), len))` if a complete
826/// OSC sequence is found, where `payload` is the bytes between `\x1b]` and the
827/// terminator, and `len` is the total number of bytes consumed.
828/// Returns `None` if the buffer does not start with `\x1b]` or the sequence is incomplete.
829/// Attempt to parse a CSI-based host-terminal report (device-attribute
830/// responses, DSR replies, DECRPM, pixel-dims reply, etc.) from the start
831/// of `buf`.
832///
833/// Only a narrow whitelist of final bytes is recognised: `t`, `y`, `c`,
834/// `n`. Any other final byte returns `None` so the bytes fall through to
835/// the regular CSI key-mapping machinery.
836///
837/// Returns `Some((event, len))` on a full match, `None` if the bytes do
838/// not look like a whitelisted CSI report (caller should try the next
839/// parser) and reserves returning None with the buffer starting with
840/// `ESC [` for two distinct cases — not currently disambiguated here:
841/// - truly malformed / unsupported sequence, or
842/// - incomplete input; caller handles incompleteness via `maybe_more`.
843/// Return `Some(len)` if `buf` starts with a structurally complete CSI
844/// sequence (`\x1b[ <params>* <intermediates>* <final>` per ECMA-48 §5.4),
845/// regardless of whether the final byte is one we have a use for. Used by
846/// `process_bytes` to advance past CSI sequences the keymap doesn't
847/// recognise — most importantly Kitty keyboard-protocol events
848/// `\x1b[<keycode>;<mods>u`. Without this, the keymap returns
849/// `Found::NeedData` (it sees the bytes as a possible prefix of a longer
850/// registered key) and the parser wedges holding bytes that will never
851/// extend into anything.
852///
853/// Returns `None` if the buffer doesn't start with `\x1b[`, contains a
854/// non-CSI byte, or hasn't yet received its final byte.
855fn 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            // Parameters (digits, ;, :, ?, <, =, >) and intermediates (space..'/').
865            0x30..=0x3F | 0x20..=0x2F => i += 1,
866            // Any byte in the final-byte range terminates a CSI sequence.
867            0x40..=0x7E => return Some(i + 1),
868            // Anything else means this isn't a well-formed CSI.
869            _ => 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    // Scan forward looking for a final byte in the whitelist, or bail if
880    // we hit something that clearly is not a CSI report (a non-printable
881    // byte other than the known final bytes).
882    let mut i = 2;
883    let mut intermediates: Vec<u8> = Vec::new();
884    let mut params: Vec<u8> = Vec::new();
885    // Parameters (0x30..=0x3F) come first, then intermediates (0x20..=0x2F),
886    // then a final byte (0x40..=0x7E). We only scan up to a reasonable
887    // length to avoid pathological buffers.
888    let max_scan = buf.len().min(256);
889    while i < max_scan {
890        let b = buf[i];
891        match b {
892            // Parameters: digits, `;`, `:`, `?`, `<`, `=`, `>`
893            0x30..=0x3F => {
894                params.push(b);
895                i += 1;
896            },
897            // Intermediates: space, `!`, `"`, ... `/`
898            0x20..=0x2F => {
899                intermediates.push(b);
900                i += 1;
901            },
902            // Final byte (0x40..=0x7E): must be one of the whitelisted bytes.
903            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                // Final byte outside the whitelist — not ours.
917                return None;
918            },
919            _ => {
920                // Something unexpected inside the CSI — give up.
921                return None;
922            },
923        }
924    }
925    None
926}
927
928fn parse_osc(buf: &[u8]) -> Option<(InputEvent, usize)> {
929    // OSC sequences start with ESC ] (0x1b 0x5d)
930    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                // BEL terminator
938                let payload = buf.get(2..i).unwrap_or_default().to_vec();
939                return Some((InputEvent::OperatingSystemCommand(payload), i + 1));
940            },
941            Some(&0x1b) => {
942                // Possible ST terminator (ESC \)
943                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                // Bare ESC inside OSC — malformed, but don't consume further
948                return None;
949            },
950            Some(_) => {
951                i += 1;
952            },
953            None => {
954                // Should not happen since i < buf.len(), but handle gracefully
955                return None;
956            },
957        }
958    }
959    None // incomplete — no terminator found yet
960}
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            // Ctrl-[A..=Z] are sent as 1..=26
1268            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            // ALT A-Z is often sent with a leading ESC
1278            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                // `CSI u` encodings for the ascii range;
1291                // see http://www.leonerd.org.uk/hacks/fixterms/
1292                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                    // xterm modifyOtherKeys sequences
1303                    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        // Common arrow keys
1322        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            // Arrow keys in normal mode encoded using CSI
1331            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            // rxvt-specific modified arrows.
1357            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            // Arrow keys in application cursor mode encoded using SS3
1378            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        // Function keys 1-4 with no modifiers encoded using SS3
1399        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        // Function keys 1-4 with modifiers
1416        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        // Function keys with modifiers encoded using CSI.
1435        // http://aperiodic.net/phil/archives/Geekery/term-function-keys.html
1436        for (range, offset) in &[
1437            // F1-F5 encoded as 11-15
1438            (1..=5, 10),
1439            // F6-F10 encoded as 17-21
1440            (6..=10, 11),
1441            // F11-F14 encoded as 23-26
1442            (11..=14, 12),
1443            // F15-F16 encoded as 28-29
1444            (15..=16, 13),
1445            // F17-F20 encoded as 31-34
1446            (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            // rxvt
1470            (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    /// Returns the first char from a str and the length of that char
1573    /// in *bytes*.
1574    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    /// This is a horrible function to pull off the first unicode character
1581    /// from the sequence of bytes and return it and the remaining slice.
1582    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        // `self.buf` is already advanced past this event, so `self.buf.len()` is
1608        // the remainder `parse_with_consumed` diffs into a per-event byte count.
1609        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                // The prior ESC was not part of an ALT sequence, so emit
1627                // it before we start collecting for paste.
1628                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                // Treat this as ALT-key
1639                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                // The prior ESC was not part of an ALT sequence, so emit
1652                // both it and the current event
1653                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    /// If a parked ESC is currently held in `EscapeMaybeAlt`, emit it as a
1667    /// real `Esc` keystroke and return to `Normal`. Called from
1668    /// `process_bytes` before dispatching any structured sequence (SGR
1669    /// mouse, OSC, whitelisted CSI host-reply) that the upcoming bytes
1670    /// match — those sequences are autonomous host events and cannot be
1671    /// ALT-combined with the parked ESC, so the ESC must be flushed
1672    /// before the sequence is emitted.
1673    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                    // Structured terminal sequences — SGR mouse, OSC, whitelisted
1705                    // CSI host-replies — are autonomous host events and cannot be
1706                    // ALT-combined with a leading Esc keystroke. Run these checks
1707                    // in *both* Normal and EscapeMaybeAlt: if we're sitting on a
1708                    // parked ESC (EscapeMaybeAlt) and the upcoming bytes match one
1709                    // of these patterns, the ESC must be a real Esc keystroke, so
1710                    // flush it before dispatching the sequence. Otherwise a parked
1711                    // ESC immediately followed by `\x1b[<...M` (xterm flushes Esc
1712                    // alone, then a mouse motion in the next read) would dispatch
1713                    // as a spurious ALT+`[` because the keymap registers `\x1b[`
1714                    // as Alt+`[`.
1715                    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                        // OSC sequence check — must come before the incomplete-SGR-mouse early return
1724                        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                        // Incomplete OSC — buffer and wait for more data
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 maybe_more && self.buf.as_slice().starts_with(b"\x1b[<") {
1738                            self.flush_parked_esc_if_held(&mut callback);
1739                            return;
1740                        }
1741
1742                        // CSI-based host-terminal report (pixel-dims reply,
1743                        // DECRPM, DSR, Primary-DA). Must come before the
1744                        // regular CSI key-mapping machinery, which would
1745                        // otherwise match "\x1b[" as an escape prefix and
1746                        // pass the bytes through as keyboard input.
1747                        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                        // Incomplete CSI ?... report (DECRPM, DSR 997, etc.) —
1755                        // wait for more data so the report-classification path
1756                        // can match the full sequence rather than letting the
1757                        // keymap dispatch the leading bytes as separate keys.
1758                        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                        // If we got an unambiguous ESC and we have more data to
1769                        // follow, then this is likely the Meta version of the
1770                        // following keypress.  Buffer up the escape key and
1771                        // consume it from the input.  dispatch_callback() will
1772                        // emit either the ESC or the ALT modified following key.
1773                        (
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                            // Advance before dispatching so `self.buf.len()` inside
1788                            // `dispatch_callback` already reflects this key's consumption.
1789                            self.buf.advance(len);
1790                            self.dispatch_callback(&mut callback, event.clone());
1791                        },
1792                        (Found::Ambiguous(_, _), true) | (Found::NeedData, true) => {
1793                            // The keymap is signalling "this buffer
1794                            // could still grow into a registered key,
1795                            // give me more bytes." That verdict is
1796                            // wrong when the buffer already holds a
1797                            // structurally complete CSI sequence whose
1798                            // final byte isn't in the keymap — most
1799                            // importantly Kitty keyboard-protocol
1800                            // events `\x1b[<keycode>;<mods>u`, which
1801                            // never grow into anything the keymap
1802                            // knows. Returning here would wedge
1803                            // `self.buf` indefinitely, swallowing every
1804                            // host reply that arrives behind it (the
1805                            // OSC + DA1 bytes for a forwarded
1806                            // `OSC 11;?` query among them) and stalling
1807                            // host-color forwards until session exit.
1808                            //
1809                            // Both `Ambiguous(_, true)` and
1810                            // `NeedData(true)` reach this point in
1811                            // practice: for `\x1b[<digits>;<digits>u`
1812                            // the trie reports `Ambiguous(1, Escape)`
1813                            // (it has ESC alone as a match and ESC[…]
1814                            // as longer prefixes), so the fix must
1815                            // cover both verdicts.
1816                            //
1817                            // Skip past the unrecognised CSI without
1818                            // emitting an event; callers that need
1819                            // keyboard dispatch (kitty_parser, the
1820                            // separate `input_parser` instance fed the
1821                            // residue from `StdinAnsiParser`) see the
1822                            // same bytes via `strip_replies`, which
1823                            // already treats unwhitelisted-final CSIs
1824                            // as `Malformed` and pushes them through.
1825                            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                            // No pre-defined key, so pull out a unicode character
1833                            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                                // We need more data to recognize the input, so
1844                                // yield the remainder of the slice
1845                                return;
1846                            }
1847                        },
1848                    }
1849                },
1850            }
1851        }
1852    }
1853
1854    /// Push a sequence of bytes into the parser.
1855    /// Each time input is recognized, the provided `callback` will be passed
1856    /// the decoded `InputEvent`.
1857    /// If not enough data are available to fully decode a sequence, the
1858    /// remaining data will be buffered until the next call.
1859    /// The `maybe_more` flag controls how ambiguous partial sequences are
1860    /// handled. The intent is that `maybe_more` should be set to true if
1861    /// you believe that you will be able to provide more data momentarily.
1862    /// This will cause the parser to defer judgement on partial prefix
1863    /// matches. You should attempt to read and pass the new data in
1864    /// immediately afterwards. If you have attempted a read and no data is
1865    /// immediately available, you should follow up with a call to parse
1866    /// with an empty slice and `maybe_more=false` to allow the partial
1867    /// data to be recognized and processed.
1868    pub fn parse<F: FnMut(InputEvent)>(&mut self, bytes: &[u8], callback: F, maybe_more: bool) {
1869        // rebind (not `mut callback: F`) to keep the upstream signature intact
1870        let mut callback = callback;
1871        self.parse_with_consumed(bytes, |event, _consumed| callback(event), maybe_more);
1872    }
1873
1874    /// Like [`InputParser::parse`], but the callback also receives the number
1875    /// of input bytes consumed to produce each event. This allows a caller
1876    /// that forwards raw bytes alongside decoded events to attribute to each
1877    /// event exactly the bytes that produced it when a single chunk of input
1878    /// decodes into multiple events.
1879    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        // `process_bytes` reports the bytes still buffered after each event; the
1887        // drop between successive remainders is what that event consumed.
1888        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    /// Number of bytes still held unprocessed in the parser's internal
1900    /// buffer. A caller that mirrors this ring separately (e.g. to forward
1901    /// raw bytes alongside decoded events) can reconcile its own buffer to
1902    /// exactly the same length so the two never drift apart.
1903    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    /// Parse `bytes` and pair each event with the raw bytes it consumed,
2013    /// draining from a copy of the input the same way the client's stdin
2014    /// loop attributes raw bytes to events.
2015    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        // A keystroke and two mouse reports arrive in one read: the key must be
2033        // paired with only its own byte and each report with its own bytes.
2034        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        // A mouse report precedes the keystroke in the read; the key must still
2065        // be paired with only its own byte.
2066        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        // Consecutive keystrokes in one read are each paired with their own byte.
2083        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        // A read that decodes into a single event pairs it with all of the
2093        // read's bytes, including a multi-byte sequence (`\x1bOA`).
2094        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        // A lone ESC arrives in one batch and a complete mouse report in the
2109        // next. The ESC is held until the following batch disambiguates it;
2110        // both events are then emitted, each paired with its own bytes.
2111        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        // Draining the accumulated bytes per event, the way the client's
2138        // stdin loop does, pairs each event with its own raw bytes.
2139        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        // In the legacy encoding a terminal sends `\r` for the Enter key and
2192        // `\n` for a control-j style newline; the keymap decodes both to
2193        // Enter. Arriving together they are two Enter events, each paired
2194        // with its own byte.
2195        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        // Fragment this F-key sequence across two different pushes
2220        p.parse(b"\x1b[11", |evt| inputs.push(evt), true);
2221        p.parse(b"~", |evt| inputs.push(evt), true);
2222        // make sure we recognize it as just the F-key
2223        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        // An incomplete F-key sequence fragmented across two different pushes
2246        p.parse(b"\x1b[11", |evt| inputs.push(evt), MAYBE_MORE);
2247        p.parse(b"", |evt| inputs.push(evt), NO_MORE);
2248        // since we finish with maybe_more false (NO_MORE), the results should be the longest matching
2249        // parts of said f-key sequence
2250        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        // Fragment this mouse sequence across two different pushes
2274        p.parse(b"\x1b[<0;0;0", |evt| inputs.push(evt), true);
2275        p.parse(b"M", |evt| inputs.push(evt), true);
2276        // make sure we recognize it as just the mouse event
2277        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        // Fragment this mouse sequence across two different pushes
2293        p.parse(b"\x1b[<", |evt| inputs.push(evt), MAYBE_MORE);
2294        p.parse(b"0;0;0", |evt| inputs.push(evt), NO_MORE);
2295        // since we finish with maybe_more false (NO_MORE), the results should be the longest matching
2296        // parts of said mouse sequence
2297        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        // tests that `Alt` + `[` is recognized as a single
2335        // event rather than two events (one `Esc` the second `Char('[')`)
2336        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        // This case is not conformant with xterm!
2423        // xterm just returns tab for CTRL-Tab when modify_other_keys
2424        // is not set.
2425        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        // button 2 (right) = 2, SHIFT adds 4 to p0 -> 6
2681        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        // button1 drag = 32
2697        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        // button4 press = 64
2713        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        // button5 press = 65
2729        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        // motion with no buttons = 35
2745        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        // button1 press = 0, ALT=8, CTRL=16 -> 0+8+16=24
2761        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); // 1 mouse + 5 chars
2793        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    /// Regression for the xterm Esc-during-mouse-drag bug:
2805    /// xterm flushes a real Esc keypress as a single `\x1b` byte. If a mouse
2806    /// motion arrives in the next stdin read, upstream `StdinAnsiParser` may
2807    /// concatenate them into `\x1b\x1b[<...M`. Termwiz must parse this as
2808    /// two events (Esc then Mouse), not as Alt+`[` (which would happen if
2809    /// the keymap's `\x1b[`=Alt+`[` registration short-circuits the SGR
2810    /// mouse parser while in `EscapeMaybeAlt` state).
2811    #[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    /// Same regression but for the cross-`parse()` case where the parked
2833    /// ESC is in `EscapeMaybeAlt` state from a prior call. The SGR mouse
2834    /// sequence arrives in a subsequent call.
2835    #[test]
2836    fn esc_then_sgr_mouse_across_parse_calls() {
2837        let mut p = InputParser::new();
2838
2839        // First call: lone ESC byte. Termwiz parks no state because the
2840        // first arm only fires when there are bytes after the ESC; with
2841        // `MAYBE_MORE` it leaves the ESC pending in its internal buf and
2842        // emits nothing yet.
2843        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        // Second call: the mouse sequence arrives. The buffered ESC plus
2850        // these bytes form `\x1b\x1b[<...M` (the inner buf already has the
2851        // ESC; this call's bytes start with another ESC because that's
2852        // what xterm sends for the mouse sequence). Result must still be
2853        // Esc + Mouse, not Alt+`[`.
2854        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    /// Real Alt+Esc keystroke (`\x1b\x1b` with no further bytes) must
2873    /// still be recognised as Alt+Esc — the fix above must not regress
2874    /// this convention.
2875    #[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    /// Esc keystroke followed by an OSC host reply (e.g. an OSC 11 color
2889    /// query response that arrives concatenated after a stray Esc byte
2890    /// the user pressed) must emit Esc and the OSC, not Alt-modify the
2891    /// OSC bytes.
2892    #[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    /// Esc followed by a CSI host-reply (whitelisted final byte). Must
2909    /// emit Esc and the report, never Alt+`[`.
2910    #[test]
2911    fn esc_then_csi_report_emits_esc_and_report() {
2912        let mut p = InputParser::new();
2913        // \x1b[?2026;0$y is a DECRPM reply for synchronised output mode.
2914        // Wrapped behind a stray Esc keystroke prefix.
2915        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        // The CSI report dispatches as DeviceControlReply via the
2932        // `parse_csi_report` whitelist. Anything but Alt+`[` is acceptable
2933        // for the second event; what we are guarding against is the
2934        // spurious Alt+`[` dispatch.
2935        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        // Invalid: missing terminator, not enough params
2950        let res = p.parse_as_vec(b"\x1b[<0;1M", false);
2951        // Should NOT parse as mouse - falls through to keymap
2952        assert!(res.iter().all(|e| matches!(e, InputEvent::Key(_))));
2953    }
2954
2955    #[test]
2956    fn osc_bel_terminated() {
2957        // Complete OSC sequence with BEL terminator
2958        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        // Complete OSC sequence with ST terminator (ESC \)
2971        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        // OSC sequence split across two reads — must buffer first part
2984        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        // OSC sequence then regular key in same buffer
3004        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        // Regular key then OSC sequence in same buffer
3021        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        // Incomplete OSC that never gets a terminator — when finalized with
3038        // maybe_more=false, must degrade to individual key events (not hang)
3039        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        // Non-99 OSC codes are also captured as OperatingSystemCommand
3050        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        // Edge case: OSC with no payload between \x1b] and terminator
3063        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        // ESC [ (CSI) must NOT be captured as an OSC sequence.
3074        // This validates that only ESC ] triggers OSC parsing.
3075        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    // =====================================================================
3087    // parse_csi_report (CSI report whitelist for host-reply forwarding)
3088    // =====================================================================
3089
3090    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        // `t` — pixel-dimension reply form `\x1b[4;H;Wt`.
3102        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        // `y` — DECRPM, e.g. sync-output support. Intermediate `$`.
3108        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        // `c` — Primary-DA reply (barrier).
3114        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        // `n` — DSR reply (used for theme notifications).
3120        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        // DECRPM uses `$` as its intermediate byte — it must land in
3129        // `intermediates`, not `params`.
3130        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        // `A` = cursor-up (keyboard input, not a report).
3150        assert!(parse_csi_report(b"\x1b[A").is_none());
3151        // `R` = cursor-position report — not whitelisted; must pass
3152        // through to the keyboard path.
3153        assert!(parse_csi_report(b"\x1b[24;80R").is_none());
3154        // `m` = SGR; appears in render streams but should never reach
3155        // stdin as a report.
3156        assert!(parse_csi_report(b"\x1b[0m").is_none());
3157    }
3158
3159    #[test]
3160    fn csi_report_returns_none_on_truncated_input() {
3161        // No final byte within the supplied slice → caller should wait
3162        // for more bytes; `parse_csi_report` must not "commit" to a
3163        // partial parse.
3164        assert!(parse_csi_report(b"\x1b[4;600;800").is_none());
3165        // Only the lead-in; parameters haven't started.
3166        assert!(parse_csi_report(b"\x1b[").is_none());
3167        // Empty input — zero bytes to consume.
3168        assert!(parse_csi_report(b"").is_none());
3169    }
3170
3171    #[test]
3172    fn csi_report_raw_preserves_input_byte_for_byte() {
3173        // `raw` must include the leading ESC through the final byte
3174        // inclusive, without adding or dropping any byte — the
3175        // forwarding path writes it verbatim to the pane's pty.
3176        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}