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}
143
144#[derive(Debug, Clone, PartialEq, Eq)]
145pub struct MouseEvent {
146    pub x: u16,
147    pub y: u16,
148    pub mouse_buttons: MouseButtons,
149    pub modifiers: Modifiers,
150}
151
152#[derive(Debug, Clone, PartialEq, Eq)]
153pub struct PixelMouseEvent {
154    pub x_pixels: u16,
155    pub y_pixels: u16,
156    pub mouse_buttons: MouseButtons,
157    pub modifiers: Modifiers,
158}
159
160#[derive(Debug, Clone, PartialEq, Eq)]
161pub struct KeyEvent {
162    /// Which key was pressed
163    pub key: KeyCode,
164    /// Which modifiers are down
165    pub modifiers: Modifiers,
166}
167
168#[derive(Debug, Clone, Copy, PartialEq, Eq)]
169pub enum KeyboardEncoding {
170    Xterm,
171    /// <http://www.leonerd.org.uk/hacks/fixterms/>
172    CsiU,
173    /// <https://github.com/microsoft/terminal/blob/main/doc/specs/%234999%20-%20Improved%20keyboard%20handling%20in%20Conpty.md>
174    Win32,
175    /// <https://sw.kovidgoyal.net/kitty/keyboard-protocol/>
176    Kitty(KittyKeyboardFlags),
177}
178
179/// Specifies terminal modes/configuration that can influence how a KeyCode
180/// is encoded when being sent to and application via the pty.
181#[derive(Debug, Clone, Copy)]
182pub struct KeyCodeEncodeModes {
183    pub encoding: KeyboardEncoding,
184    pub application_cursor_keys: bool,
185    pub newline_mode: bool,
186    pub modify_other_keys: Option<i64>,
187}
188
189/// Which key is pressed.  Not all of these are probable to appear
190/// on most systems.  A lot of this list is @wez trawling docs and
191/// making an entry for things that might be possible in this first pass.
192#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
193pub enum KeyCode {
194    /// The decoded unicode character
195    Char(char),
196
197    Hyper,
198    Super,
199    Meta,
200
201    /// Ctrl-break on windows
202    Cancel,
203    Backspace,
204    Tab,
205    Clear,
206    Enter,
207    Shift,
208    Escape,
209    LeftShift,
210    RightShift,
211    Control,
212    LeftControl,
213    RightControl,
214    Alt,
215    LeftAlt,
216    RightAlt,
217    Menu,
218    LeftMenu,
219    RightMenu,
220    Pause,
221    CapsLock,
222    PageUp,
223    PageDown,
224    End,
225    Home,
226    LeftArrow,
227    RightArrow,
228    UpArrow,
229    DownArrow,
230    Select,
231    Print,
232    Execute,
233    PrintScreen,
234    Insert,
235    Delete,
236    Help,
237    LeftWindows,
238    RightWindows,
239    Applications,
240    Sleep,
241    Numpad0,
242    Numpad1,
243    Numpad2,
244    Numpad3,
245    Numpad4,
246    Numpad5,
247    Numpad6,
248    Numpad7,
249    Numpad8,
250    Numpad9,
251    Multiply,
252    Add,
253    Separator,
254    Subtract,
255    Decimal,
256    Divide,
257    /// F1-F24 are possible
258    Function(u8),
259    NumLock,
260    ScrollLock,
261    Copy,
262    Cut,
263    Paste,
264    BrowserBack,
265    BrowserForward,
266    BrowserRefresh,
267    BrowserStop,
268    BrowserSearch,
269    BrowserFavorites,
270    BrowserHome,
271    VolumeMute,
272    VolumeDown,
273    VolumeUp,
274    MediaNextTrack,
275    MediaPrevTrack,
276    MediaStop,
277    MediaPlayPause,
278    ApplicationLeftArrow,
279    ApplicationRightArrow,
280    ApplicationUpArrow,
281    ApplicationDownArrow,
282    KeyPadHome,
283    KeyPadEnd,
284    KeyPadPageUp,
285    KeyPadPageDown,
286    KeyPadBegin,
287
288    #[doc(hidden)]
289    InternalPasteStart,
290    #[doc(hidden)]
291    InternalPasteEnd,
292}
293
294impl KeyCode {
295    /// if SHIFT is held and we have KeyCode::Char('c') we want to normalize
296    /// that keycode to KeyCode::Char('C'); that is what this function does.
297    pub fn normalize_shift_to_upper_case(self, modifiers: Modifiers) -> KeyCode {
298        if modifiers.contains(Modifiers::SHIFT) {
299            match self {
300                KeyCode::Char(c) if c.is_ascii_lowercase() => KeyCode::Char(c.to_ascii_uppercase()),
301                _ => self,
302            }
303        } else {
304            self
305        }
306    }
307
308    /// Return true if the key represents a modifier key.
309    pub fn is_modifier(self) -> bool {
310        matches!(
311            self,
312            Self::Hyper
313                | Self::Super
314                | Self::Meta
315                | Self::Shift
316                | Self::LeftShift
317                | Self::RightShift
318                | Self::Control
319                | Self::LeftControl
320                | Self::RightControl
321                | Self::Alt
322                | Self::LeftAlt
323                | Self::RightAlt
324                | Self::LeftWindows
325                | Self::RightWindows
326        )
327    }
328
329    /// Returns the byte sequence that represents this KeyCode and Modifier combination.
330    pub fn encode(
331        &self,
332        mods: Modifiers,
333        modes: KeyCodeEncodeModes,
334        is_down: bool,
335    ) -> Result<String> {
336        if !is_down {
337            // We only want down events
338            return Ok(String::new());
339        }
340        // We are encoding the key as an xterm-compatible sequence, which does not support
341        // positional modifiers.
342        let mods = mods.remove_positional_mods();
343
344        use KeyCode::*;
345
346        let key = self.normalize_shift_to_upper_case(mods);
347        // Normalize the modifier state for Char's that are uppercase; remove
348        // the SHIFT modifier so that reduce ambiguity below
349        let mods = match key {
350            Char(c)
351                if (c.is_ascii_punctuation() || c.is_ascii_uppercase())
352                    && mods.contains(Modifiers::SHIFT) =>
353            {
354                mods & !Modifiers::SHIFT
355            },
356            _ => mods,
357        };
358
359        // Normalize Backspace and Delete
360        let key = match key {
361            Char('\x7f') => Delete,
362            Char('\x08') => Backspace,
363            c => c,
364        };
365
366        let mut buf = String::new();
367
368        // TODO: also respect self.application_keypad
369
370        match key {
371            Char(c)
372                if is_ambiguous_ascii_ctrl(c)
373                    && mods.contains(Modifiers::CTRL)
374                    && modes.encoding == KeyboardEncoding::CsiU =>
375            {
376                csi_u_encode(&mut buf, c, mods, &modes)?;
377            },
378            Char(c) if c.is_ascii_uppercase() && mods.contains(Modifiers::CTRL) => {
379                csi_u_encode(&mut buf, c, mods, &modes)?;
380            },
381
382            Char(c) if mods.contains(Modifiers::CTRL) && modes.modify_other_keys == Some(2) => {
383                csi_u_encode(&mut buf, c, mods, &modes)?;
384            },
385            Char(c) if mods.contains(Modifiers::CTRL) && ctrl_mapping(c).is_some() => {
386                let c = ctrl_mapping(c).unwrap();
387                if mods.contains(Modifiers::ALT) {
388                    buf.push(0x1b as char);
389                }
390                buf.push(c);
391            },
392
393            // When alt is pressed, send escape first to indicate to the peer that
394            // ALT is pressed.  We do this only for ascii alnum characters because
395            // eg: on macOS generates altgr style glyphs and keeps the ALT key
396            // in the modifier set.  This confuses eg: zsh which then just displays
397            // <fffffffff> as the input, so we want to avoid that.
398            Char(c)
399                if (c.is_ascii_alphanumeric() || c.is_ascii_punctuation())
400                    && mods.contains(Modifiers::ALT) =>
401            {
402                buf.push(0x1b as char);
403                buf.push(c);
404            },
405
406            Backspace => {
407                // Backspace sends the default VERASE which is confusingly
408                // the DEL ascii codepoint rather than BS.
409                // We only send BS when CTRL is held.
410                if mods.contains(Modifiers::CTRL) {
411                    csi_u_encode(&mut buf, '\x08', mods, &modes)?;
412                } else if mods.contains(Modifiers::SHIFT) {
413                    csi_u_encode(&mut buf, '\x7f', mods, &modes)?;
414                } else {
415                    if mods.contains(Modifiers::ALT) {
416                        buf.push(0x1b as char);
417                    }
418                    buf.push('\x7f');
419                }
420            },
421
422            Enter | Escape => {
423                let c = match key {
424                    Enter => '\r',
425                    Escape => '\x1b',
426                    _ => unreachable!(),
427                };
428                if mods.contains(Modifiers::SHIFT) || mods.contains(Modifiers::CTRL) {
429                    csi_u_encode(&mut buf, c, mods, &modes)?;
430                } else {
431                    if mods.contains(Modifiers::ALT) {
432                        buf.push(0x1b as char);
433                    }
434                    buf.push(c);
435                    if modes.newline_mode && key == Enter {
436                        buf.push(0x0a as char);
437                    }
438                }
439            },
440
441            Tab if !mods.is_empty() && modes.modify_other_keys.is_some() => {
442                csi_u_encode(&mut buf, '\t', mods, &modes)?;
443            },
444
445            Tab => {
446                if mods.contains(Modifiers::ALT) {
447                    buf.push(0x1b as char);
448                }
449                let mods = mods & !Modifiers::ALT;
450                if mods == Modifiers::CTRL {
451                    buf.push_str("\x1b[9;5u");
452                } else if mods == Modifiers::CTRL | Modifiers::SHIFT {
453                    buf.push_str("\x1b[1;5Z");
454                } else if mods == Modifiers::SHIFT {
455                    buf.push_str("\x1b[Z");
456                } else {
457                    buf.push('\t');
458                }
459            },
460
461            Char(c) => {
462                if mods.is_empty() {
463                    buf.push(c);
464                } else {
465                    csi_u_encode(&mut buf, c, mods, &modes)?;
466                }
467            },
468
469            Home
470            | KeyPadHome
471            | End
472            | KeyPadEnd
473            | UpArrow
474            | DownArrow
475            | RightArrow
476            | LeftArrow
477            | ApplicationUpArrow
478            | ApplicationDownArrow
479            | ApplicationRightArrow
480            | ApplicationLeftArrow => {
481                let (force_app, c) = match key {
482                    UpArrow => (false, 'A'),
483                    DownArrow => (false, 'B'),
484                    RightArrow => (false, 'C'),
485                    LeftArrow => (false, 'D'),
486                    KeyPadHome | Home => (false, 'H'),
487                    End | KeyPadEnd => (false, 'F'),
488                    ApplicationUpArrow => (true, 'A'),
489                    ApplicationDownArrow => (true, 'B'),
490                    ApplicationRightArrow => (true, 'C'),
491                    ApplicationLeftArrow => (true, 'D'),
492                    _ => unreachable!(),
493                };
494
495                let csi_or_ss3 = if force_app || modes.application_cursor_keys {
496                    // Use SS3 in application mode
497                    SS3
498                } else {
499                    // otherwise use regular CSI
500                    CSI
501                };
502
503                if mods.contains(Modifiers::ALT)
504                    || mods.contains(Modifiers::SHIFT)
505                    || mods.contains(Modifiers::CTRL)
506                {
507                    write!(buf, "{}1;{}{}", CSI, 1 + mods.encode_xterm(), c)?;
508                } else {
509                    write!(buf, "{}{}", csi_or_ss3, c)?;
510                }
511            },
512
513            PageUp | PageDown | KeyPadPageUp | KeyPadPageDown | Insert | Delete => {
514                let c = match key {
515                    Insert => 2,
516                    Delete => 3,
517                    KeyPadPageUp | PageUp => 5,
518                    KeyPadPageDown | PageDown => 6,
519                    _ => unreachable!(),
520                };
521
522                if mods.contains(Modifiers::ALT)
523                    || mods.contains(Modifiers::SHIFT)
524                    || mods.contains(Modifiers::CTRL)
525                {
526                    write!(buf, "\x1b[{};{}~", c, 1 + mods.encode_xterm())?;
527                } else {
528                    write!(buf, "\x1b[{}~", c)?;
529                }
530            },
531
532            Function(n) => {
533                if mods.is_empty() && n < 5 {
534                    // F1-F4 are encoded using SS3 if there are no modifiers
535                    write!(
536                        buf,
537                        "{}",
538                        match n {
539                            1 => "\x1bOP",
540                            2 => "\x1bOQ",
541                            3 => "\x1bOR",
542                            4 => "\x1bOS",
543                            _ => unreachable!("wat?"),
544                        }
545                    )?;
546                } else if n < 5 {
547                    // Special case for F1-F4 with modifiers
548                    let code = match n {
549                        1 => 'P',
550                        2 => 'Q',
551                        3 => 'R',
552                        4 => 'S',
553                        _ => unreachable!("wat?"),
554                    };
555                    write!(buf, "\x1b[1;{}{code}", 1 + mods.encode_xterm())?;
556                } else {
557                    // Higher numbered F-keys using CSI instead of SS3.
558                    let intro = match n {
559                        1 => "\x1b[11",
560                        2 => "\x1b[12",
561                        3 => "\x1b[13",
562                        4 => "\x1b[14",
563                        5 => "\x1b[15",
564                        6 => "\x1b[17",
565                        7 => "\x1b[18",
566                        8 => "\x1b[19",
567                        9 => "\x1b[20",
568                        10 => "\x1b[21",
569                        11 => "\x1b[23",
570                        12 => "\x1b[24",
571                        13 => "\x1b[25",
572                        14 => "\x1b[26",
573                        15 => "\x1b[28",
574                        16 => "\x1b[29",
575                        17 => "\x1b[31",
576                        18 => "\x1b[32",
577                        19 => "\x1b[33",
578                        20 => "\x1b[34",
579                        21 => "\x1b[42",
580                        22 => "\x1b[43",
581                        23 => "\x1b[44",
582                        24 => "\x1b[45",
583                        _ => return Err(format!("unhandled fkey number {}", n).into()),
584                    };
585                    let encoded_mods = mods.encode_xterm();
586                    if encoded_mods == 0 {
587                        // If no modifiers are held, don't send the modifier
588                        // sequence, as the modifier encoding is a CSI-u extension.
589                        write!(buf, "{}~", intro)?;
590                    } else {
591                        write!(buf, "{};{}~", intro, 1 + encoded_mods)?;
592                    }
593                }
594            },
595
596            Numpad0 | Numpad3 | Numpad9 | Decimal => {
597                let intro = match key {
598                    Numpad0 => "\x1b[2",
599                    Numpad3 => "\x1b[6",
600                    Numpad9 => "\x1b[6",
601                    Decimal => "\x1b[3",
602                    _ => unreachable!(),
603                };
604
605                let encoded_mods = mods.encode_xterm();
606                if encoded_mods == 0 {
607                    write!(buf, "{}~", intro)?;
608                } else {
609                    write!(buf, "{};{}~", intro, 1 + encoded_mods)?;
610                }
611            },
612
613            Numpad1 | Numpad2 | Numpad4 | Numpad5 | KeyPadBegin | Numpad6 | Numpad7 | Numpad8 => {
614                let c = match key {
615                    Numpad1 => "F",
616                    Numpad2 => "B",
617                    Numpad4 => "D",
618                    KeyPadBegin | Numpad5 => "E",
619                    Numpad6 => "C",
620                    Numpad7 => "H",
621                    Numpad8 => "A",
622                    _ => unreachable!(),
623                };
624
625                let encoded_mods = mods.encode_xterm();
626                if encoded_mods == 0 {
627                    write!(buf, "{}{}", CSI, c)?;
628                } else {
629                    write!(buf, "{}1;{}{}", CSI, 1 + encoded_mods, c)?;
630                }
631            },
632
633            Multiply | Add | Separator | Subtract | Divide => {},
634
635            // Modifier keys pressed on their own don't expand to anything
636            Control | LeftControl | RightControl | Alt | LeftAlt | RightAlt | Menu | LeftMenu
637            | RightMenu | Super | Hyper | Shift | LeftShift | RightShift | Meta | LeftWindows
638            | RightWindows | NumLock | ScrollLock | Cancel | Clear | Pause | CapsLock | Select
639            | Print | PrintScreen | Execute | Help | Applications | Sleep | Copy | Cut | Paste
640            | BrowserBack | BrowserForward | BrowserRefresh | BrowserStop | BrowserSearch
641            | BrowserFavorites | BrowserHome | VolumeMute | VolumeDown | VolumeUp
642            | MediaNextTrack | MediaPrevTrack | MediaStop | MediaPlayPause | InternalPasteStart
643            | InternalPasteEnd => {},
644        };
645
646        Ok(buf)
647    }
648}
649
650/// characters that when masked for CTRL could be an ascii control character
651/// or could be a key that a user legitimately wants to process in their
652/// terminal application
653fn is_ambiguous_ascii_ctrl(c: char) -> bool {
654    matches!(c, 'i' | 'I' | 'm' | 'M' | '[' | '{' | '@')
655}
656
657fn is_ascii(c: char) -> bool {
658    (c as u32) < 0x80
659}
660
661fn csi_u_encode(
662    buf: &mut String,
663    c: char,
664    mods: Modifiers,
665    modes: &KeyCodeEncodeModes,
666) -> Result<()> {
667    if modes.encoding == KeyboardEncoding::CsiU && is_ascii(c) {
668        write!(buf, "\x1b[{};{}u", c as u32, 1 + mods.encode_xterm())?;
669        return Ok(());
670    }
671
672    // <https://invisible-island.net/xterm/modified-keys.html>
673    match (c, modes.modify_other_keys) {
674        ('c' | 'd' | '\x1b' | '\x7f' | '\x08', Some(1)) => {
675            // Exclude well-known keys from modifyOtherKeys mode 1
676        },
677        (c, Some(_)) => {
678            write!(buf, "\x1b[27;{};{}~", 1 + mods.encode_xterm(), c as u32)?;
679            return Ok(());
680        },
681        _ => {},
682    }
683
684    let c = if mods.contains(Modifiers::CTRL) && ctrl_mapping(c).is_some() {
685        ctrl_mapping(c).unwrap()
686    } else {
687        c
688    };
689    if mods.contains(Modifiers::ALT) {
690        buf.push(0x1b as char);
691    }
692    write!(buf, "{}", c)?;
693    Ok(())
694}
695
696#[derive(Debug, Clone, Copy, PartialEq, Eq)]
697enum MouseButton {
698    Button1Press,
699    Button1Release,
700    Button1Drag,
701    Button2Press,
702    Button2Release,
703    Button2Drag,
704    Button3Press,
705    Button3Release,
706    Button3Drag,
707    Button4Press,
708    Button4Release,
709    Button5Press,
710    Button5Release,
711    Button6Press,
712    Button6Release,
713    Button7Press,
714    Button7Release,
715    None,
716}
717
718fn decode_mouse_button(control: u8, p0: i64) -> Option<MouseButton> {
719    match (control, p0 & 0b110_0011) {
720        (b'M', 0) => Some(MouseButton::Button1Press),
721        (b'm', 0) => Some(MouseButton::Button1Release),
722        (b'M', 1) => Some(MouseButton::Button2Press),
723        (b'm', 1) => Some(MouseButton::Button2Release),
724        (b'M', 2) => Some(MouseButton::Button3Press),
725        (b'm', 2) => Some(MouseButton::Button3Release),
726        (b'M', 64) => Some(MouseButton::Button4Press),
727        (b'm', 64) => Some(MouseButton::Button4Release),
728        (b'M', 65) => Some(MouseButton::Button5Press),
729        (b'm', 65) => Some(MouseButton::Button5Release),
730        (b'M', 66) => Some(MouseButton::Button6Press),
731        (b'm', 66) => Some(MouseButton::Button6Release),
732        (b'M', 67) => Some(MouseButton::Button7Press),
733        (b'm', 67) => Some(MouseButton::Button7Release),
734        (b'M', 32) => Some(MouseButton::Button1Drag),
735        (b'M', 33) => Some(MouseButton::Button2Drag),
736        (b'M', 34) => Some(MouseButton::Button3Drag),
737        (b'M', 35) | (b'm', 35) | (b'M', 3) | (b'm', 3) => Some(MouseButton::None),
738        _ => ::core::option::Option::None,
739    }
740}
741
742impl From<MouseButton> for MouseButtons {
743    fn from(button: MouseButton) -> MouseButtons {
744        match button {
745            MouseButton::Button1Press | MouseButton::Button1Drag => MouseButtons::LEFT,
746            MouseButton::Button2Press | MouseButton::Button2Drag => MouseButtons::MIDDLE,
747            MouseButton::Button3Press | MouseButton::Button3Drag => MouseButtons::RIGHT,
748            MouseButton::Button4Press => MouseButtons::VERT_WHEEL | MouseButtons::WHEEL_POSITIVE,
749            MouseButton::Button5Press => MouseButtons::VERT_WHEEL,
750            MouseButton::Button6Press => MouseButtons::HORZ_WHEEL | MouseButtons::WHEEL_POSITIVE,
751            MouseButton::Button7Press => MouseButtons::HORZ_WHEEL,
752            _ => MouseButtons::NONE,
753        }
754    }
755}
756
757fn decode_mouse_modifiers(p0: i64) -> Modifiers {
758    let mut modifiers = Modifiers::NONE;
759    if p0 & 4 != 0 {
760        modifiers |= Modifiers::SHIFT;
761    }
762    if p0 & 8 != 0 {
763        modifiers |= Modifiers::ALT;
764    }
765    if p0 & 16 != 0 {
766        modifiers |= Modifiers::CTRL;
767    }
768    modifiers
769}
770
771/// Try to parse an SGR mouse sequence from the buffer.
772/// Returns Some((InputEvent, bytes_consumed)) on success.
773/// Returns None if the buffer does not contain a complete SGR mouse sequence.
774fn parse_sgr_mouse(buf: &[u8]) -> Option<(InputEvent, usize)> {
775    // Must start with \x1b[<
776    if buf.len() < 6 || !buf.starts_with(b"\x1b[<") {
777        return None;
778    }
779    let rest = &buf[3..]; // skip \x1b[<
780
781    // Find the terminating M or m
782    let term_pos = rest.iter().position(|&b| b == b'M' || b == b'm')?;
783    let control = rest[term_pos];
784    let params_str = std::str::from_utf8(&rest[..term_pos]).ok()?;
785
786    // Parse three semicolon-separated integers
787    let mut parts = params_str.splitn(3, ';');
788    let p0: i64 = parts.next()?.parse().ok()?;
789    let p1: i64 = parts.next()?.parse().ok()?;
790    let p2: i64 = parts.next()?.parse().ok()?;
791
792    let button = decode_mouse_button(control, p0)?;
793    let modifiers = decode_mouse_modifiers(p0);
794    let mouse_buttons: MouseButtons = button.into();
795
796    let consumed = 3 + term_pos + 1; // \x1b[< + params + M/m
797
798    Some((
799        InputEvent::Mouse(MouseEvent {
800            x: p1 as u16,
801            y: p2 as u16,
802            mouse_buttons,
803            modifiers,
804        }),
805        consumed,
806    ))
807}
808
809/// Attempt to parse an OSC (Operating System Command) sequence from the buffer.
810/// Returns `Some((InputEvent::OperatingSystemCommand(payload), len))` if a complete
811/// OSC sequence is found, where `payload` is the bytes between `\x1b]` and the
812/// terminator, and `len` is the total number of bytes consumed.
813/// Returns `None` if the buffer does not start with `\x1b]` or the sequence is incomplete.
814fn parse_osc(buf: &[u8]) -> Option<(InputEvent, usize)> {
815    // OSC sequences start with ESC ] (0x1b 0x5d)
816    if buf.get(0) != Some(&0x1b) || buf.get(1) != Some(&b']') {
817        return None;
818    }
819    let mut i = 2;
820    while i < buf.len() {
821        match buf.get(i) {
822            Some(&0x07) => {
823                // BEL terminator
824                let payload = buf.get(2..i).unwrap_or_default().to_vec();
825                return Some((InputEvent::OperatingSystemCommand(payload), i + 1));
826            },
827            Some(&0x1b) => {
828                // Possible ST terminator (ESC \)
829                if buf.get(i + 1) == Some(&b'\\') {
830                    let payload = buf.get(2..i).unwrap_or_default().to_vec();
831                    return Some((InputEvent::OperatingSystemCommand(payload), i + 2));
832                }
833                // Bare ESC inside OSC — malformed, but don't consume further
834                return None;
835            },
836            Some(_) => {
837                i += 1;
838            },
839            None => {
840                // Should not happen since i < buf.len(), but handle gracefully
841                return None;
842            },
843        }
844    }
845    None // incomplete — no terminator found yet
846}
847
848#[derive(Debug, Clone, Copy, PartialEq, Eq)]
849enum InputState {
850    Normal,
851    EscapeMaybeAlt,
852    Pasting(usize),
853}
854
855#[derive(Debug)]
856pub struct InputParser {
857    key_map: KeyMap<InputEvent>,
858    buf: ReadBuffer,
859    state: InputState,
860}
861
862#[cfg(windows)]
863mod windows {
864    use super::*;
865    use std;
866    use winapi::um::wincon::{
867        INPUT_RECORD, KEY_EVENT, KEY_EVENT_RECORD, MOUSE_EVENT, MOUSE_EVENT_RECORD,
868        WINDOW_BUFFER_SIZE_EVENT, WINDOW_BUFFER_SIZE_RECORD,
869    };
870    use winapi::um::winuser;
871
872    fn modifiers_from_ctrl_key_state(state: u32) -> Modifiers {
873        use winapi::um::wincon::*;
874
875        let mut mods = Modifiers::NONE;
876
877        if (state & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) != 0 {
878            mods |= Modifiers::ALT;
879        }
880
881        if (state & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0 {
882            mods |= Modifiers::CTRL;
883        }
884
885        if (state & SHIFT_PRESSED) != 0 {
886            mods |= Modifiers::SHIFT;
887        }
888
889        mods
890    }
891
892    impl InputParser {
893        fn decode_key_record<F: FnMut(InputEvent)>(
894            &mut self,
895            event: &KEY_EVENT_RECORD,
896            callback: &mut F,
897        ) {
898            if event.bKeyDown == 0 {
899                return;
900            }
901
902            let key_code = match std::char::from_u32(*unsafe { event.uChar.UnicodeChar() } as u32) {
903                Some(unicode) if unicode > '\x00' => {
904                    let mut buf = [0u8; 4];
905                    self.buf
906                        .extend_with(unicode.encode_utf8(&mut buf).as_bytes());
907                    self.process_bytes(callback, true);
908                    return;
909                },
910                _ => match event.wVirtualKeyCode as i32 {
911                    winuser::VK_CANCEL => KeyCode::Cancel,
912                    winuser::VK_BACK => KeyCode::Backspace,
913                    winuser::VK_TAB => KeyCode::Tab,
914                    winuser::VK_CLEAR => KeyCode::Clear,
915                    winuser::VK_RETURN => KeyCode::Enter,
916                    winuser::VK_SHIFT => KeyCode::Shift,
917                    winuser::VK_CONTROL => KeyCode::Control,
918                    winuser::VK_MENU => KeyCode::Menu,
919                    winuser::VK_PAUSE => KeyCode::Pause,
920                    winuser::VK_CAPITAL => KeyCode::CapsLock,
921                    winuser::VK_ESCAPE => KeyCode::Escape,
922                    winuser::VK_PRIOR => KeyCode::PageUp,
923                    winuser::VK_NEXT => KeyCode::PageDown,
924                    winuser::VK_END => KeyCode::End,
925                    winuser::VK_HOME => KeyCode::Home,
926                    winuser::VK_LEFT => KeyCode::LeftArrow,
927                    winuser::VK_RIGHT => KeyCode::RightArrow,
928                    winuser::VK_UP => KeyCode::UpArrow,
929                    winuser::VK_DOWN => KeyCode::DownArrow,
930                    winuser::VK_SELECT => KeyCode::Select,
931                    winuser::VK_PRINT => KeyCode::Print,
932                    winuser::VK_EXECUTE => KeyCode::Execute,
933                    winuser::VK_SNAPSHOT => KeyCode::PrintScreen,
934                    winuser::VK_INSERT => KeyCode::Insert,
935                    winuser::VK_DELETE => KeyCode::Delete,
936                    winuser::VK_HELP => KeyCode::Help,
937                    winuser::VK_LWIN => KeyCode::LeftWindows,
938                    winuser::VK_RWIN => KeyCode::RightWindows,
939                    winuser::VK_APPS => KeyCode::Applications,
940                    winuser::VK_SLEEP => KeyCode::Sleep,
941                    winuser::VK_NUMPAD0 => KeyCode::Numpad0,
942                    winuser::VK_NUMPAD1 => KeyCode::Numpad1,
943                    winuser::VK_NUMPAD2 => KeyCode::Numpad2,
944                    winuser::VK_NUMPAD3 => KeyCode::Numpad3,
945                    winuser::VK_NUMPAD4 => KeyCode::Numpad4,
946                    winuser::VK_NUMPAD5 => KeyCode::Numpad5,
947                    winuser::VK_NUMPAD6 => KeyCode::Numpad6,
948                    winuser::VK_NUMPAD7 => KeyCode::Numpad7,
949                    winuser::VK_NUMPAD8 => KeyCode::Numpad8,
950                    winuser::VK_NUMPAD9 => KeyCode::Numpad9,
951                    winuser::VK_MULTIPLY => KeyCode::Multiply,
952                    winuser::VK_ADD => KeyCode::Add,
953                    winuser::VK_SEPARATOR => KeyCode::Separator,
954                    winuser::VK_SUBTRACT => KeyCode::Subtract,
955                    winuser::VK_DECIMAL => KeyCode::Decimal,
956                    winuser::VK_DIVIDE => KeyCode::Divide,
957                    winuser::VK_F1 => KeyCode::Function(1),
958                    winuser::VK_F2 => KeyCode::Function(2),
959                    winuser::VK_F3 => KeyCode::Function(3),
960                    winuser::VK_F4 => KeyCode::Function(4),
961                    winuser::VK_F5 => KeyCode::Function(5),
962                    winuser::VK_F6 => KeyCode::Function(6),
963                    winuser::VK_F7 => KeyCode::Function(7),
964                    winuser::VK_F8 => KeyCode::Function(8),
965                    winuser::VK_F9 => KeyCode::Function(9),
966                    winuser::VK_F10 => KeyCode::Function(10),
967                    winuser::VK_F11 => KeyCode::Function(11),
968                    winuser::VK_F12 => KeyCode::Function(12),
969                    winuser::VK_F13 => KeyCode::Function(13),
970                    winuser::VK_F14 => KeyCode::Function(14),
971                    winuser::VK_F15 => KeyCode::Function(15),
972                    winuser::VK_F16 => KeyCode::Function(16),
973                    winuser::VK_F17 => KeyCode::Function(17),
974                    winuser::VK_F18 => KeyCode::Function(18),
975                    winuser::VK_F19 => KeyCode::Function(19),
976                    winuser::VK_F20 => KeyCode::Function(20),
977                    winuser::VK_F21 => KeyCode::Function(21),
978                    winuser::VK_F22 => KeyCode::Function(22),
979                    winuser::VK_F23 => KeyCode::Function(23),
980                    winuser::VK_F24 => KeyCode::Function(24),
981                    winuser::VK_NUMLOCK => KeyCode::NumLock,
982                    winuser::VK_SCROLL => KeyCode::ScrollLock,
983                    winuser::VK_LSHIFT => KeyCode::LeftShift,
984                    winuser::VK_RSHIFT => KeyCode::RightShift,
985                    winuser::VK_LCONTROL => KeyCode::LeftControl,
986                    winuser::VK_RCONTROL => KeyCode::RightControl,
987                    winuser::VK_LMENU => KeyCode::LeftMenu,
988                    winuser::VK_RMENU => KeyCode::RightMenu,
989                    winuser::VK_BROWSER_BACK => KeyCode::BrowserBack,
990                    winuser::VK_BROWSER_FORWARD => KeyCode::BrowserForward,
991                    winuser::VK_BROWSER_REFRESH => KeyCode::BrowserRefresh,
992                    winuser::VK_BROWSER_STOP => KeyCode::BrowserStop,
993                    winuser::VK_BROWSER_SEARCH => KeyCode::BrowserSearch,
994                    winuser::VK_BROWSER_FAVORITES => KeyCode::BrowserFavorites,
995                    winuser::VK_BROWSER_HOME => KeyCode::BrowserHome,
996                    winuser::VK_VOLUME_MUTE => KeyCode::VolumeMute,
997                    winuser::VK_VOLUME_DOWN => KeyCode::VolumeDown,
998                    winuser::VK_VOLUME_UP => KeyCode::VolumeUp,
999                    winuser::VK_MEDIA_NEXT_TRACK => KeyCode::MediaNextTrack,
1000                    winuser::VK_MEDIA_PREV_TRACK => KeyCode::MediaPrevTrack,
1001                    winuser::VK_MEDIA_STOP => KeyCode::MediaStop,
1002                    winuser::VK_MEDIA_PLAY_PAUSE => KeyCode::MediaPlayPause,
1003                    _ => return,
1004                },
1005            };
1006            let mut modifiers = modifiers_from_ctrl_key_state(event.dwControlKeyState);
1007
1008            let key_code = key_code.normalize_shift_to_upper_case(modifiers);
1009            if let KeyCode::Char(c) = key_code {
1010                if c.is_ascii_uppercase() {
1011                    modifiers.remove(Modifiers::SHIFT);
1012                }
1013            }
1014
1015            let input_event = InputEvent::Key(KeyEvent {
1016                key: key_code,
1017                modifiers,
1018            });
1019            for _ in 0..event.wRepeatCount {
1020                callback(input_event.clone());
1021            }
1022        }
1023
1024        fn decode_mouse_record<F: FnMut(InputEvent)>(
1025            &self,
1026            event: &MOUSE_EVENT_RECORD,
1027            callback: &mut F,
1028        ) {
1029            use winapi::um::wincon::*;
1030            let mut buttons = MouseButtons::NONE;
1031
1032            if (event.dwButtonState & FROM_LEFT_1ST_BUTTON_PRESSED) != 0 {
1033                buttons |= MouseButtons::LEFT;
1034            }
1035            if (event.dwButtonState & RIGHTMOST_BUTTON_PRESSED) != 0 {
1036                buttons |= MouseButtons::RIGHT;
1037            }
1038            if (event.dwButtonState & FROM_LEFT_2ND_BUTTON_PRESSED) != 0 {
1039                buttons |= MouseButtons::MIDDLE;
1040            }
1041
1042            let modifiers = modifiers_from_ctrl_key_state(event.dwControlKeyState);
1043
1044            if (event.dwEventFlags & MOUSE_WHEELED) != 0 {
1045                buttons |= MouseButtons::VERT_WHEEL;
1046                if (event.dwButtonState >> 8) != 0 {
1047                    buttons |= MouseButtons::WHEEL_POSITIVE;
1048                }
1049            } else if (event.dwEventFlags & MOUSE_HWHEELED) != 0 {
1050                buttons |= MouseButtons::HORZ_WHEEL;
1051                if (event.dwButtonState >> 8) != 0 {
1052                    buttons |= MouseButtons::WHEEL_POSITIVE;
1053                }
1054            }
1055
1056            let mouse = InputEvent::Mouse(MouseEvent {
1057                x: event.dwMousePosition.X as u16,
1058                y: event.dwMousePosition.Y as u16,
1059                mouse_buttons: buttons,
1060                modifiers,
1061            });
1062
1063            if (event.dwEventFlags & DOUBLE_CLICK) != 0 {
1064                callback(mouse.clone());
1065            }
1066            callback(mouse);
1067        }
1068
1069        fn decode_resize_record<F: FnMut(InputEvent)>(
1070            &self,
1071            event: &WINDOW_BUFFER_SIZE_RECORD,
1072            callback: &mut F,
1073        ) {
1074            callback(InputEvent::Resized {
1075                rows: event.dwSize.Y as usize,
1076                cols: event.dwSize.X as usize,
1077            });
1078        }
1079
1080        pub fn decode_input_records<F: FnMut(InputEvent)>(
1081            &mut self,
1082            records: &[INPUT_RECORD],
1083            callback: &mut F,
1084        ) {
1085            for record in records {
1086                match record.EventType {
1087                    KEY_EVENT => {
1088                        self.decode_key_record(unsafe { record.Event.KeyEvent() }, callback)
1089                    },
1090                    MOUSE_EVENT => {
1091                        self.decode_mouse_record(unsafe { record.Event.MouseEvent() }, callback)
1092                    },
1093                    WINDOW_BUFFER_SIZE_EVENT => self.decode_resize_record(
1094                        unsafe { record.Event.WindowBufferSizeEvent() },
1095                        callback,
1096                    ),
1097                    _ => {},
1098                }
1099            }
1100            self.process_bytes(callback, false);
1101        }
1102    }
1103}
1104
1105impl Default for InputParser {
1106    fn default() -> Self {
1107        Self::new()
1108    }
1109}
1110
1111impl InputParser {
1112    pub fn new() -> Self {
1113        Self {
1114            key_map: Self::build_basic_key_map(),
1115            buf: ReadBuffer::new(),
1116            state: InputState::Normal,
1117        }
1118    }
1119
1120    fn build_basic_key_map() -> KeyMap<InputEvent> {
1121        let mut map = KeyMap::new();
1122
1123        let modifier_combos = &[
1124            ("", Modifiers::NONE),
1125            (";1", Modifiers::NONE),
1126            (";2", Modifiers::SHIFT),
1127            (";3", Modifiers::ALT),
1128            (";4", Modifiers::ALT | Modifiers::SHIFT),
1129            (";5", Modifiers::CTRL),
1130            (";6", Modifiers::CTRL | Modifiers::SHIFT),
1131            (";7", Modifiers::CTRL | Modifiers::ALT),
1132            (";8", Modifiers::CTRL | Modifiers::ALT | Modifiers::SHIFT),
1133        ];
1134        let meta = Modifiers::ALT;
1135        let meta_modifier_combos = &[
1136            (";9", meta),
1137            (";10", meta | Modifiers::SHIFT),
1138            (";11", meta | Modifiers::ALT),
1139            (";12", meta | Modifiers::ALT | Modifiers::SHIFT),
1140            (";13", meta | Modifiers::CTRL),
1141            (";14", meta | Modifiers::CTRL | Modifiers::SHIFT),
1142            (";15", meta | Modifiers::CTRL | Modifiers::ALT),
1143            (
1144                ";16",
1145                meta | Modifiers::CTRL | Modifiers::ALT | Modifiers::SHIFT,
1146            ),
1147        ];
1148
1149        let modifier_combos_including_meta =
1150            || modifier_combos.iter().chain(meta_modifier_combos.iter());
1151
1152        for alpha in b'A'..=b'Z' {
1153            // Ctrl-[A..=Z] are sent as 1..=26
1154            let ctrl = [alpha & 0x1f];
1155            map.insert(
1156                &ctrl,
1157                InputEvent::Key(KeyEvent {
1158                    key: KeyCode::Char((alpha as char).to_ascii_lowercase()),
1159                    modifiers: Modifiers::CTRL,
1160                }),
1161            );
1162
1163            // ALT A-Z is often sent with a leading ESC
1164            let alt = [0x1b, alpha];
1165            map.insert(
1166                &alt,
1167                InputEvent::Key(KeyEvent {
1168                    key: KeyCode::Char(alpha as char),
1169                    modifiers: Modifiers::ALT,
1170                }),
1171            );
1172        }
1173
1174        for c in 0..=0x7fu8 {
1175            for (suffix, modifiers) in modifier_combos {
1176                // `CSI u` encodings for the ascii range;
1177                // see http://www.leonerd.org.uk/hacks/fixterms/
1178                let key = format!("\x1b[{}{}u", c, suffix);
1179                map.insert(
1180                    key,
1181                    InputEvent::Key(KeyEvent {
1182                        key: KeyCode::Char(c as char),
1183                        modifiers: *modifiers,
1184                    }),
1185                );
1186
1187                if !suffix.is_empty() {
1188                    // xterm modifyOtherKeys sequences
1189                    let key = format!("\x1b[27{};{}~", suffix, c);
1190                    map.insert(
1191                        key,
1192                        InputEvent::Key(KeyEvent {
1193                            key: match c {
1194                                8 | 0x7f => KeyCode::Backspace,
1195                                0x1b => KeyCode::Escape,
1196                                9 => KeyCode::Tab,
1197                                10 | 13 => KeyCode::Enter,
1198                                _ => KeyCode::Char(c as char),
1199                            },
1200                            modifiers: *modifiers,
1201                        }),
1202                    );
1203                }
1204            }
1205        }
1206
1207        // Common arrow keys
1208        for (keycode, dir) in &[
1209            (KeyCode::UpArrow, b'A'),
1210            (KeyCode::DownArrow, b'B'),
1211            (KeyCode::RightArrow, b'C'),
1212            (KeyCode::LeftArrow, b'D'),
1213            (KeyCode::Home, b'H'),
1214            (KeyCode::End, b'F'),
1215        ] {
1216            // Arrow keys in normal mode encoded using CSI
1217            let arrow = [0x1b, b'[', *dir];
1218            map.insert(
1219                &arrow,
1220                InputEvent::Key(KeyEvent {
1221                    key: *keycode,
1222                    modifiers: Modifiers::NONE,
1223                }),
1224            );
1225            for (suffix, modifiers) in modifier_combos_including_meta() {
1226                let key = format!("\x1b[1{}{}", suffix, *dir as char);
1227                map.insert(
1228                    key,
1229                    InputEvent::Key(KeyEvent {
1230                        key: *keycode,
1231                        modifiers: *modifiers,
1232                    }),
1233                );
1234            }
1235        }
1236        for &(keycode, dir) in &[
1237            (KeyCode::UpArrow, b'a'),
1238            (KeyCode::DownArrow, b'b'),
1239            (KeyCode::RightArrow, b'c'),
1240            (KeyCode::LeftArrow, b'd'),
1241        ] {
1242            // rxvt-specific modified arrows.
1243            for &(seq, mods) in &[
1244                ([0x1b, b'[', dir], Modifiers::SHIFT),
1245                ([0x1b, b'O', dir], Modifiers::CTRL),
1246            ] {
1247                map.insert(
1248                    &seq,
1249                    InputEvent::Key(KeyEvent {
1250                        key: keycode,
1251                        modifiers: mods,
1252                    }),
1253                );
1254            }
1255        }
1256
1257        for (keycode, dir) in &[
1258            (KeyCode::ApplicationUpArrow, b'A'),
1259            (KeyCode::ApplicationDownArrow, b'B'),
1260            (KeyCode::ApplicationRightArrow, b'C'),
1261            (KeyCode::ApplicationLeftArrow, b'D'),
1262        ] {
1263            // Arrow keys in application cursor mode encoded using SS3
1264            let app = [0x1b, b'O', *dir];
1265            map.insert(
1266                &app,
1267                InputEvent::Key(KeyEvent {
1268                    key: *keycode,
1269                    modifiers: Modifiers::NONE,
1270                }),
1271            );
1272            for (suffix, modifiers) in modifier_combos {
1273                let key = format!("\x1bO1{}{}", suffix, *dir as char);
1274                map.insert(
1275                    key,
1276                    InputEvent::Key(KeyEvent {
1277                        key: *keycode,
1278                        modifiers: *modifiers,
1279                    }),
1280                );
1281            }
1282        }
1283
1284        // Function keys 1-4 with no modifiers encoded using SS3
1285        for (keycode, c) in &[
1286            (KeyCode::Function(1), b'P'),
1287            (KeyCode::Function(2), b'Q'),
1288            (KeyCode::Function(3), b'R'),
1289            (KeyCode::Function(4), b'S'),
1290        ] {
1291            let key = [0x1b, b'O', *c];
1292            map.insert(
1293                &key,
1294                InputEvent::Key(KeyEvent {
1295                    key: *keycode,
1296                    modifiers: Modifiers::NONE,
1297                }),
1298            );
1299        }
1300
1301        // Function keys 1-4 with modifiers
1302        for (keycode, c) in &[
1303            (KeyCode::Function(1), b'P'),
1304            (KeyCode::Function(2), b'Q'),
1305            (KeyCode::Function(3), b'R'),
1306            (KeyCode::Function(4), b'S'),
1307        ] {
1308            for (suffix, modifiers) in modifier_combos_including_meta() {
1309                let key = format!("\x1b[1{suffix}{code}", code = *c as char, suffix = suffix);
1310                map.insert(
1311                    key,
1312                    InputEvent::Key(KeyEvent {
1313                        key: *keycode,
1314                        modifiers: *modifiers,
1315                    }),
1316                );
1317            }
1318        }
1319
1320        // Function keys with modifiers encoded using CSI.
1321        // http://aperiodic.net/phil/archives/Geekery/term-function-keys.html
1322        for (range, offset) in &[
1323            // F1-F5 encoded as 11-15
1324            (1..=5, 10),
1325            // F6-F10 encoded as 17-21
1326            (6..=10, 11),
1327            // F11-F14 encoded as 23-26
1328            (11..=14, 12),
1329            // F15-F16 encoded as 28-29
1330            (15..=16, 13),
1331            // F17-F20 encoded as 31-34
1332            (17..=20, 14),
1333        ] {
1334            for n in range.clone() {
1335                for (suffix, modifiers) in modifier_combos_including_meta() {
1336                    let key = format!("\x1b[{code}{suffix}~", code = n + offset, suffix = suffix);
1337                    map.insert(
1338                        key,
1339                        InputEvent::Key(KeyEvent {
1340                            key: KeyCode::Function(n),
1341                            modifiers: *modifiers,
1342                        }),
1343                    );
1344                }
1345            }
1346        }
1347
1348        for (keycode, c) in &[
1349            (KeyCode::Insert, b'2'),
1350            (KeyCode::Delete, b'3'),
1351            (KeyCode::Home, b'1'),
1352            (KeyCode::End, b'4'),
1353            (KeyCode::PageUp, b'5'),
1354            (KeyCode::PageDown, b'6'),
1355            // rxvt
1356            (KeyCode::Home, b'7'),
1357            (KeyCode::End, b'8'),
1358        ] {
1359            for (suffix, modifiers) in &[
1360                (b'~', Modifiers::NONE),
1361                (b'$', Modifiers::SHIFT),
1362                (b'^', Modifiers::CTRL),
1363                (b'@', Modifiers::SHIFT | Modifiers::CTRL),
1364            ] {
1365                let key = [0x1b, b'[', *c, *suffix];
1366                map.insert(
1367                    key,
1368                    InputEvent::Key(KeyEvent {
1369                        key: *keycode,
1370                        modifiers: *modifiers,
1371                    }),
1372                );
1373            }
1374        }
1375
1376        map.insert(
1377            &[0x7f],
1378            InputEvent::Key(KeyEvent {
1379                key: KeyCode::Backspace,
1380                modifiers: Modifiers::NONE,
1381            }),
1382        );
1383
1384        map.insert(
1385            &[0x8],
1386            InputEvent::Key(KeyEvent {
1387                key: KeyCode::Backspace,
1388                modifiers: Modifiers::NONE,
1389            }),
1390        );
1391
1392        map.insert(
1393            &[0x1b],
1394            InputEvent::Key(KeyEvent {
1395                key: KeyCode::Escape,
1396                modifiers: Modifiers::NONE,
1397            }),
1398        );
1399
1400        map.insert(
1401            &[b'\t'],
1402            InputEvent::Key(KeyEvent {
1403                key: KeyCode::Tab,
1404                modifiers: Modifiers::NONE,
1405            }),
1406        );
1407        map.insert(
1408            b"\x1b[Z",
1409            InputEvent::Key(KeyEvent {
1410                key: KeyCode::Tab,
1411                modifiers: Modifiers::SHIFT,
1412            }),
1413        );
1414
1415        map.insert(
1416            &[b'\r'],
1417            InputEvent::Key(KeyEvent {
1418                key: KeyCode::Enter,
1419                modifiers: Modifiers::NONE,
1420            }),
1421        );
1422        map.insert(
1423            &[b'\n'],
1424            InputEvent::Key(KeyEvent {
1425                key: KeyCode::Enter,
1426                modifiers: Modifiers::NONE,
1427            }),
1428        );
1429
1430        map.insert(
1431            b"\x1b[200~",
1432            InputEvent::Key(KeyEvent {
1433                key: KeyCode::InternalPasteStart,
1434                modifiers: Modifiers::NONE,
1435            }),
1436        );
1437        map.insert(
1438            b"\x1b[201~",
1439            InputEvent::Key(KeyEvent {
1440                key: KeyCode::InternalPasteEnd,
1441                modifiers: Modifiers::NONE,
1442            }),
1443        );
1444        map.insert(
1445            b"\x1b[",
1446            InputEvent::Key(KeyEvent {
1447                key: KeyCode::Char('['),
1448                modifiers: Modifiers::ALT,
1449            }),
1450        );
1451
1452        map
1453    }
1454
1455    /// Returns the first char from a str and the length of that char
1456    /// in *bytes*.
1457    fn first_char_and_len(s: &str) -> (char, usize) {
1458        let mut iter = s.chars();
1459        let c = iter.next().unwrap();
1460        (c, c.len_utf8())
1461    }
1462
1463    /// This is a horrible function to pull off the first unicode character
1464    /// from the sequence of bytes and return it and the remaining slice.
1465    fn decode_one_char(bytes: &[u8]) -> Option<(char, usize)> {
1466        let bytes = &bytes[..bytes.len().min(4)];
1467        match std::str::from_utf8(bytes) {
1468            Ok(s) => {
1469                let (c, len) = Self::first_char_and_len(s);
1470                Some((c, len))
1471            },
1472            Err(err) => {
1473                let (valid, _after_valid) = bytes.split_at(err.valid_up_to());
1474                if !valid.is_empty() {
1475                    let s = unsafe { std::str::from_utf8_unchecked(valid) };
1476                    let (c, len) = Self::first_char_and_len(s);
1477                    Some((c, len))
1478                } else {
1479                    None
1480                }
1481            },
1482        }
1483    }
1484
1485    fn dispatch_callback<F: FnMut(InputEvent)>(&mut self, mut callback: F, event: InputEvent) {
1486        match (self.state, &event) {
1487            (
1488                InputState::Normal,
1489                InputEvent::Key(KeyEvent {
1490                    key: KeyCode::InternalPasteStart,
1491                    ..
1492                }),
1493            ) => {
1494                self.state = InputState::Pasting(0);
1495            },
1496            (
1497                InputState::EscapeMaybeAlt,
1498                InputEvent::Key(KeyEvent {
1499                    key: KeyCode::InternalPasteStart,
1500                    ..
1501                }),
1502            ) => {
1503                // The prior ESC was not part of an ALT sequence, so emit
1504                // it before we start collecting for paste.
1505                callback(InputEvent::Key(KeyEvent {
1506                    key: KeyCode::Escape,
1507                    modifiers: Modifiers::NONE,
1508                }));
1509                self.state = InputState::Pasting(0);
1510            },
1511            (InputState::EscapeMaybeAlt, InputEvent::Key(KeyEvent { key, modifiers })) => {
1512                // Treat this as ALT-key
1513                let key = *key;
1514                let modifiers = *modifiers;
1515                self.state = InputState::Normal;
1516                callback(InputEvent::Key(KeyEvent {
1517                    key,
1518                    modifiers: modifiers | Modifiers::ALT,
1519                }));
1520            },
1521            (InputState::EscapeMaybeAlt, _) => {
1522                // The prior ESC was not part of an ALT sequence, so emit
1523                // both it and the current event
1524                callback(InputEvent::Key(KeyEvent {
1525                    key: KeyCode::Escape,
1526                    modifiers: Modifiers::NONE,
1527                }));
1528                callback(event);
1529            },
1530            (_, _) => callback(event),
1531        }
1532    }
1533
1534    fn process_bytes<F: FnMut(InputEvent)>(&mut self, mut callback: F, maybe_more: bool) {
1535        while !self.buf.is_empty() {
1536            match self.state {
1537                InputState::Pasting(offset) => {
1538                    let end_paste = b"\x1b[201~";
1539                    if let Some(idx) = self.buf.find_subsequence(offset, end_paste) {
1540                        let pasted =
1541                            String::from_utf8_lossy(&self.buf.as_slice()[0..idx]).to_string();
1542                        self.buf.advance(pasted.len() + end_paste.len());
1543                        callback(InputEvent::Paste(pasted));
1544                        self.state = InputState::Normal;
1545                    } else {
1546                        self.state =
1547                            InputState::Pasting(self.buf.len().saturating_sub(end_paste.len()));
1548                        return;
1549                    }
1550                },
1551                InputState::EscapeMaybeAlt | InputState::Normal => {
1552                    if self.state == InputState::Normal
1553                        && self.buf.as_slice().get(0) == Some(&b'\x1b')
1554                    {
1555                        if let Some((event, len)) = parse_sgr_mouse(self.buf.as_slice()) {
1556                            self.buf.advance(len);
1557                            callback(event);
1558                            continue;
1559                        }
1560
1561                        // OSC sequence check — must come before the incomplete-SGR-mouse early return
1562                        if let Some((event, len)) = parse_osc(self.buf.as_slice()) {
1563                            self.buf.advance(len);
1564                            callback(event);
1565                            continue;
1566                        }
1567
1568                        // Incomplete OSC — buffer and wait for more data
1569                        if maybe_more && self.buf.as_slice().starts_with(b"\x1b]") {
1570                            return;
1571                        }
1572
1573                        if maybe_more && self.buf.as_slice().starts_with(b"\x1b[<") {
1574                            return;
1575                        }
1576                    }
1577
1578                    match (
1579                        self.key_map.lookup(self.buf.as_slice(), maybe_more),
1580                        maybe_more,
1581                    ) {
1582                        // If we got an unambiguous ESC and we have more data to
1583                        // follow, then this is likely the Meta version of the
1584                        // following keypress.  Buffer up the escape key and
1585                        // consume it from the input.  dispatch_callback() will
1586                        // emit either the ESC or the ALT modified following key.
1587                        (
1588                            Found::Exact(
1589                                len,
1590                                InputEvent::Key(KeyEvent {
1591                                    key: KeyCode::Escape,
1592                                    modifiers: Modifiers::NONE,
1593                                }),
1594                            ),
1595                            _,
1596                        ) if self.state == InputState::Normal && self.buf.len() > len => {
1597                            self.state = InputState::EscapeMaybeAlt;
1598                            self.buf.advance(len);
1599                        },
1600                        (Found::Exact(len, event), _) | (Found::Ambiguous(len, event), false) => {
1601                            self.dispatch_callback(&mut callback, event.clone());
1602                            self.buf.advance(len);
1603                        },
1604                        (Found::Ambiguous(_, _), true) | (Found::NeedData, true) => {
1605                            return;
1606                        },
1607                        (Found::None, _) | (Found::NeedData, false) => {
1608                            // No pre-defined key, so pull out a unicode character
1609                            if let Some((c, len)) = Self::decode_one_char(self.buf.as_slice()) {
1610                                self.buf.advance(len);
1611                                self.dispatch_callback(
1612                                    &mut callback,
1613                                    InputEvent::Key(KeyEvent {
1614                                        key: KeyCode::Char(c),
1615                                        modifiers: Modifiers::NONE,
1616                                    }),
1617                                );
1618                            } else {
1619                                // We need more data to recognize the input, so
1620                                // yield the remainder of the slice
1621                                return;
1622                            }
1623                        },
1624                    }
1625                },
1626            }
1627        }
1628    }
1629
1630    /// Push a sequence of bytes into the parser.
1631    /// Each time input is recognized, the provided `callback` will be passed
1632    /// the decoded `InputEvent`.
1633    /// If not enough data are available to fully decode a sequence, the
1634    /// remaining data will be buffered until the next call.
1635    /// The `maybe_more` flag controls how ambiguous partial sequences are
1636    /// handled. The intent is that `maybe_more` should be set to true if
1637    /// you believe that you will be able to provide more data momentarily.
1638    /// This will cause the parser to defer judgement on partial prefix
1639    /// matches. You should attempt to read and pass the new data in
1640    /// immediately afterwards. If you have attempted a read and no data is
1641    /// immediately available, you should follow up with a call to parse
1642    /// with an empty slice and `maybe_more=false` to allow the partial
1643    /// data to be recognized and processed.
1644    pub fn parse<F: FnMut(InputEvent)>(&mut self, bytes: &[u8], callback: F, maybe_more: bool) {
1645        self.buf.extend_with(bytes);
1646        self.process_bytes(callback, maybe_more);
1647    }
1648
1649    pub fn parse_as_vec(&mut self, bytes: &[u8], maybe_more: bool) -> Vec<InputEvent> {
1650        let mut result = Vec::new();
1651        self.parse(bytes, |event| result.push(event), maybe_more);
1652        result
1653    }
1654
1655    #[cfg(windows)]
1656    pub fn decode_input_records_as_vec(
1657        &mut self,
1658        records: &[winapi::um::wincon::INPUT_RECORD],
1659    ) -> Vec<InputEvent> {
1660        let mut result = Vec::new();
1661        self.decode_input_records(records, &mut |event| result.push(event));
1662        result
1663    }
1664}
1665
1666#[cfg(test)]
1667mod test {
1668    use super::*;
1669
1670    const NO_MORE: bool = false;
1671    const MAYBE_MORE: bool = true;
1672
1673    #[test]
1674    fn simple() {
1675        let mut p = InputParser::new();
1676        let inputs = p.parse_as_vec(b"hello", NO_MORE);
1677        assert_eq!(
1678            vec![
1679                InputEvent::Key(KeyEvent {
1680                    modifiers: Modifiers::NONE,
1681                    key: KeyCode::Char('h'),
1682                }),
1683                InputEvent::Key(KeyEvent {
1684                    modifiers: Modifiers::NONE,
1685                    key: KeyCode::Char('e'),
1686                }),
1687                InputEvent::Key(KeyEvent {
1688                    modifiers: Modifiers::NONE,
1689                    key: KeyCode::Char('l'),
1690                }),
1691                InputEvent::Key(KeyEvent {
1692                    modifiers: Modifiers::NONE,
1693                    key: KeyCode::Char('l'),
1694                }),
1695                InputEvent::Key(KeyEvent {
1696                    modifiers: Modifiers::NONE,
1697                    key: KeyCode::Char('o'),
1698                }),
1699            ],
1700            inputs
1701        );
1702    }
1703
1704    #[test]
1705    fn control_characters() {
1706        let mut p = InputParser::new();
1707        let inputs = p.parse_as_vec(b"\x03\x1bJ\x7f", NO_MORE);
1708        assert_eq!(
1709            vec![
1710                InputEvent::Key(KeyEvent {
1711                    modifiers: Modifiers::CTRL,
1712                    key: KeyCode::Char('c'),
1713                }),
1714                InputEvent::Key(KeyEvent {
1715                    modifiers: Modifiers::ALT,
1716                    key: KeyCode::Char('J'),
1717                }),
1718                InputEvent::Key(KeyEvent {
1719                    modifiers: Modifiers::NONE,
1720                    key: KeyCode::Backspace,
1721                }),
1722            ],
1723            inputs
1724        );
1725    }
1726
1727    #[test]
1728    fn arrow_keys() {
1729        let mut p = InputParser::new();
1730        let inputs = p.parse_as_vec(b"\x1bOA\x1bOB\x1bOC\x1bOD", NO_MORE);
1731        assert_eq!(
1732            vec![
1733                InputEvent::Key(KeyEvent {
1734                    modifiers: Modifiers::NONE,
1735                    key: KeyCode::ApplicationUpArrow,
1736                }),
1737                InputEvent::Key(KeyEvent {
1738                    modifiers: Modifiers::NONE,
1739                    key: KeyCode::ApplicationDownArrow,
1740                }),
1741                InputEvent::Key(KeyEvent {
1742                    modifiers: Modifiers::NONE,
1743                    key: KeyCode::ApplicationRightArrow,
1744                }),
1745                InputEvent::Key(KeyEvent {
1746                    modifiers: Modifiers::NONE,
1747                    key: KeyCode::ApplicationLeftArrow,
1748                }),
1749            ],
1750            inputs
1751        );
1752    }
1753
1754    #[test]
1755    fn partial() {
1756        let mut p = InputParser::new();
1757        let mut inputs = Vec::new();
1758        // Fragment this F-key sequence across two different pushes
1759        p.parse(b"\x1b[11", |evt| inputs.push(evt), true);
1760        p.parse(b"~", |evt| inputs.push(evt), true);
1761        // make sure we recognize it as just the F-key
1762        assert_eq!(
1763            vec![InputEvent::Key(KeyEvent {
1764                modifiers: Modifiers::NONE,
1765                key: KeyCode::Function(1),
1766            })],
1767            inputs
1768        );
1769    }
1770
1771    #[test]
1772    fn partial_ambig() {
1773        let mut p = InputParser::new();
1774
1775        assert_eq!(
1776            vec![InputEvent::Key(KeyEvent {
1777                key: KeyCode::Escape,
1778                modifiers: Modifiers::NONE,
1779            })],
1780            p.parse_as_vec(b"\x1b", false)
1781        );
1782
1783        let mut inputs = Vec::new();
1784        // An incomplete F-key sequence fragmented across two different pushes
1785        p.parse(b"\x1b[11", |evt| inputs.push(evt), MAYBE_MORE);
1786        p.parse(b"", |evt| inputs.push(evt), NO_MORE);
1787        // since we finish with maybe_more false (NO_MORE), the results should be the longest matching
1788        // parts of said f-key sequence
1789        assert_eq!(
1790            vec![
1791                InputEvent::Key(KeyEvent {
1792                    modifiers: Modifiers::ALT,
1793                    key: KeyCode::Char('['),
1794                }),
1795                InputEvent::Key(KeyEvent {
1796                    modifiers: Modifiers::NONE,
1797                    key: KeyCode::Char('1'),
1798                }),
1799                InputEvent::Key(KeyEvent {
1800                    modifiers: Modifiers::NONE,
1801                    key: KeyCode::Char('1'),
1802                }),
1803            ],
1804            inputs
1805        );
1806    }
1807
1808    #[test]
1809    fn partial_mouse() {
1810        let mut p = InputParser::new();
1811        let mut inputs = Vec::new();
1812        // Fragment this mouse sequence across two different pushes
1813        p.parse(b"\x1b[<0;0;0", |evt| inputs.push(evt), true);
1814        p.parse(b"M", |evt| inputs.push(evt), true);
1815        // make sure we recognize it as just the mouse event
1816        assert_eq!(
1817            vec![InputEvent::Mouse(MouseEvent {
1818                x: 0,
1819                y: 0,
1820                mouse_buttons: MouseButtons::LEFT,
1821                modifiers: Modifiers::NONE,
1822            })],
1823            inputs
1824        );
1825    }
1826
1827    #[test]
1828    fn partial_mouse_ambig() {
1829        let mut p = InputParser::new();
1830        let mut inputs = Vec::new();
1831        // Fragment this mouse sequence across two different pushes
1832        p.parse(b"\x1b[<", |evt| inputs.push(evt), MAYBE_MORE);
1833        p.parse(b"0;0;0", |evt| inputs.push(evt), NO_MORE);
1834        // since we finish with maybe_more false (NO_MORE), the results should be the longest matching
1835        // parts of said mouse sequence
1836        assert_eq!(
1837            vec![
1838                InputEvent::Key(KeyEvent {
1839                    modifiers: Modifiers::ALT,
1840                    key: KeyCode::Char('['),
1841                }),
1842                InputEvent::Key(KeyEvent {
1843                    modifiers: Modifiers::NONE,
1844                    key: KeyCode::Char('<'),
1845                }),
1846                InputEvent::Key(KeyEvent {
1847                    modifiers: Modifiers::NONE,
1848                    key: KeyCode::Char('0'),
1849                }),
1850                InputEvent::Key(KeyEvent {
1851                    modifiers: Modifiers::NONE,
1852                    key: KeyCode::Char(';'),
1853                }),
1854                InputEvent::Key(KeyEvent {
1855                    modifiers: Modifiers::NONE,
1856                    key: KeyCode::Char('0'),
1857                }),
1858                InputEvent::Key(KeyEvent {
1859                    modifiers: Modifiers::NONE,
1860                    key: KeyCode::Char(';'),
1861                }),
1862                InputEvent::Key(KeyEvent {
1863                    modifiers: Modifiers::NONE,
1864                    key: KeyCode::Char('0'),
1865                }),
1866            ],
1867            inputs
1868        );
1869    }
1870
1871    #[test]
1872    fn alt_left_bracket() {
1873        // tests that `Alt` + `[` is recognized as a single
1874        // event rather than two events (one `Esc` the second `Char('[')`)
1875        let mut p = InputParser::new();
1876
1877        let mut inputs = Vec::new();
1878        p.parse(b"\x1b[", |evt| inputs.push(evt), false);
1879
1880        assert_eq!(
1881            vec![InputEvent::Key(KeyEvent {
1882                modifiers: Modifiers::ALT,
1883                key: KeyCode::Char('['),
1884            }),],
1885            inputs
1886        );
1887    }
1888
1889    #[test]
1890    fn modify_other_keys_parse() {
1891        let mut p = InputParser::new();
1892        let inputs = p.parse_as_vec(
1893            b"\x1b[27;5;13~\x1b[27;5;9~\x1b[27;6;8~\x1b[27;2;127~\x1b[27;6;27~",
1894            NO_MORE,
1895        );
1896        assert_eq!(
1897            vec![
1898                InputEvent::Key(KeyEvent {
1899                    key: KeyCode::Enter,
1900                    modifiers: Modifiers::CTRL,
1901                }),
1902                InputEvent::Key(KeyEvent {
1903                    key: KeyCode::Tab,
1904                    modifiers: Modifiers::CTRL,
1905                }),
1906                InputEvent::Key(KeyEvent {
1907                    key: KeyCode::Backspace,
1908                    modifiers: Modifiers::CTRL | Modifiers::SHIFT,
1909                }),
1910                InputEvent::Key(KeyEvent {
1911                    key: KeyCode::Backspace,
1912                    modifiers: Modifiers::SHIFT,
1913                }),
1914                InputEvent::Key(KeyEvent {
1915                    key: KeyCode::Escape,
1916                    modifiers: Modifiers::CTRL | Modifiers::SHIFT,
1917                }),
1918            ],
1919            inputs
1920        );
1921    }
1922
1923    #[test]
1924    fn modify_other_keys_encode() {
1925        let mode = KeyCodeEncodeModes {
1926            encoding: KeyboardEncoding::Xterm,
1927            newline_mode: false,
1928            application_cursor_keys: false,
1929            modify_other_keys: None,
1930        };
1931        let mode_1 = KeyCodeEncodeModes {
1932            encoding: KeyboardEncoding::Xterm,
1933            newline_mode: false,
1934            application_cursor_keys: false,
1935            modify_other_keys: Some(1),
1936        };
1937        let mode_2 = KeyCodeEncodeModes {
1938            encoding: KeyboardEncoding::Xterm,
1939            newline_mode: false,
1940            application_cursor_keys: false,
1941            modify_other_keys: Some(2),
1942        };
1943
1944        assert_eq!(
1945            KeyCode::Enter.encode(Modifiers::CTRL, mode, true).unwrap(),
1946            "\r".to_string()
1947        );
1948        assert_eq!(
1949            KeyCode::Enter
1950                .encode(Modifiers::CTRL, mode_1, true)
1951                .unwrap(),
1952            "\x1b[27;5;13~".to_string()
1953        );
1954        assert_eq!(
1955            KeyCode::Enter
1956                .encode(Modifiers::CTRL | Modifiers::SHIFT, mode_1, true)
1957                .unwrap(),
1958            "\x1b[27;6;13~".to_string()
1959        );
1960
1961        // This case is not conformant with xterm!
1962        // xterm just returns tab for CTRL-Tab when modify_other_keys
1963        // is not set.
1964        assert_eq!(
1965            KeyCode::Tab.encode(Modifiers::CTRL, mode, true).unwrap(),
1966            "\x1b[9;5u".to_string()
1967        );
1968        assert_eq!(
1969            KeyCode::Tab.encode(Modifiers::CTRL, mode_1, true).unwrap(),
1970            "\x1b[27;5;9~".to_string()
1971        );
1972        assert_eq!(
1973            KeyCode::Tab
1974                .encode(Modifiers::CTRL | Modifiers::SHIFT, mode_1, true)
1975                .unwrap(),
1976            "\x1b[27;6;9~".to_string()
1977        );
1978
1979        assert_eq!(
1980            KeyCode::Char('c')
1981                .encode(Modifiers::CTRL, mode, true)
1982                .unwrap(),
1983            "\x03".to_string()
1984        );
1985        assert_eq!(
1986            KeyCode::Char('c')
1987                .encode(Modifiers::CTRL, mode_1, true)
1988                .unwrap(),
1989            "\x03".to_string()
1990        );
1991        assert_eq!(
1992            KeyCode::Char('c')
1993                .encode(Modifiers::CTRL, mode_2, true)
1994                .unwrap(),
1995            "\x1b[27;5;99~".to_string()
1996        );
1997
1998        assert_eq!(
1999            KeyCode::Char('1')
2000                .encode(Modifiers::CTRL, mode, true)
2001                .unwrap(),
2002            "1".to_string()
2003        );
2004        assert_eq!(
2005            KeyCode::Char('1')
2006                .encode(Modifiers::CTRL, mode_2, true)
2007                .unwrap(),
2008            "\x1b[27;5;49~".to_string()
2009        );
2010
2011        assert_eq!(
2012            KeyCode::Char(',')
2013                .encode(Modifiers::CTRL, mode, true)
2014                .unwrap(),
2015            ",".to_string()
2016        );
2017        assert_eq!(
2018            KeyCode::Char(',')
2019                .encode(Modifiers::CTRL, mode_2, true)
2020                .unwrap(),
2021            "\x1b[27;5;44~".to_string()
2022        );
2023    }
2024
2025    #[test]
2026    fn encode_issue_892() {
2027        let mode = KeyCodeEncodeModes {
2028            encoding: KeyboardEncoding::Xterm,
2029            newline_mode: false,
2030            application_cursor_keys: false,
2031            modify_other_keys: None,
2032        };
2033
2034        assert_eq!(
2035            KeyCode::LeftArrow
2036                .encode(Modifiers::NONE, mode, true)
2037                .unwrap(),
2038            "\x1b[D".to_string()
2039        );
2040        assert_eq!(
2041            KeyCode::LeftArrow
2042                .encode(Modifiers::ALT, mode, true)
2043                .unwrap(),
2044            "\x1b[1;3D".to_string()
2045        );
2046        assert_eq!(
2047            KeyCode::Home.encode(Modifiers::NONE, mode, true).unwrap(),
2048            "\x1b[H".to_string()
2049        );
2050        assert_eq!(
2051            KeyCode::Home.encode(Modifiers::ALT, mode, true).unwrap(),
2052            "\x1b[1;3H".to_string()
2053        );
2054        assert_eq!(
2055            KeyCode::End.encode(Modifiers::NONE, mode, true).unwrap(),
2056            "\x1b[F".to_string()
2057        );
2058        assert_eq!(
2059            KeyCode::End.encode(Modifiers::ALT, mode, true).unwrap(),
2060            "\x1b[1;3F".to_string()
2061        );
2062        assert_eq!(
2063            KeyCode::Tab.encode(Modifiers::ALT, mode, true).unwrap(),
2064            "\x1b\t".to_string()
2065        );
2066        assert_eq!(
2067            KeyCode::PageUp.encode(Modifiers::ALT, mode, true).unwrap(),
2068            "\x1b[5;3~".to_string()
2069        );
2070        assert_eq!(
2071            KeyCode::Function(1)
2072                .encode(Modifiers::NONE, mode, true)
2073                .unwrap(),
2074            "\x1bOP".to_string()
2075        );
2076    }
2077
2078    #[test]
2079    fn partial_bracketed_paste() {
2080        let mut p = InputParser::new();
2081
2082        let input = b"\x1b[200~1234";
2083        let input2 = b"5678\x1b[201~";
2084
2085        let mut inputs = vec![];
2086
2087        p.parse(input, |e| inputs.push(e), false);
2088        p.parse(input2, |e| inputs.push(e), false);
2089
2090        assert_eq!(vec![InputEvent::Paste("12345678".to_owned())], inputs)
2091    }
2092
2093    #[test]
2094    fn mouse_horizontal_scroll() {
2095        let mut p = InputParser::new();
2096
2097        let input = b"\x1b[<66;42;12M\x1b[<67;42;12M";
2098        let res = p.parse_as_vec(input, MAYBE_MORE);
2099
2100        assert_eq!(
2101            vec![
2102                InputEvent::Mouse(MouseEvent {
2103                    x: 42,
2104                    y: 12,
2105                    mouse_buttons: MouseButtons::HORZ_WHEEL | MouseButtons::WHEEL_POSITIVE,
2106                    modifiers: Modifiers::NONE,
2107                }),
2108                InputEvent::Mouse(MouseEvent {
2109                    x: 42,
2110                    y: 12,
2111                    mouse_buttons: MouseButtons::HORZ_WHEEL,
2112                    modifiers: Modifiers::NONE,
2113                })
2114            ],
2115            res
2116        );
2117    }
2118
2119    #[test]
2120    fn encode_issue_3478_xterm() {
2121        let mode = KeyCodeEncodeModes {
2122            encoding: KeyboardEncoding::Xterm,
2123            newline_mode: false,
2124            application_cursor_keys: false,
2125            modify_other_keys: None,
2126        };
2127
2128        assert_eq!(
2129            KeyCode::Numpad0
2130                .encode(Modifiers::NONE, mode, true)
2131                .unwrap(),
2132            "\u{1b}[2~".to_string()
2133        );
2134        assert_eq!(
2135            KeyCode::Numpad0
2136                .encode(Modifiers::SHIFT, mode, true)
2137                .unwrap(),
2138            "\u{1b}[2;2~".to_string()
2139        );
2140
2141        assert_eq!(
2142            KeyCode::Numpad1
2143                .encode(Modifiers::NONE, mode, true)
2144                .unwrap(),
2145            "\u{1b}[F".to_string()
2146        );
2147        assert_eq!(
2148            KeyCode::Numpad1
2149                .encode(Modifiers::NONE | Modifiers::SHIFT, mode, true)
2150                .unwrap(),
2151            "\u{1b}[1;2F".to_string()
2152        );
2153    }
2154
2155    #[test]
2156    fn encode_tab_with_modifiers() {
2157        let mode = KeyCodeEncodeModes {
2158            encoding: KeyboardEncoding::Xterm,
2159            newline_mode: false,
2160            application_cursor_keys: false,
2161            modify_other_keys: None,
2162        };
2163
2164        let mods_to_result = [
2165            (Modifiers::SHIFT, "\u{1b}[Z"),
2166            (Modifiers::SHIFT | Modifiers::LEFT_SHIFT, "\u{1b}[Z"),
2167            (Modifiers::SHIFT | Modifiers::RIGHT_SHIFT, "\u{1b}[Z"),
2168            (Modifiers::CTRL, "\u{1b}[9;5u"),
2169            (Modifiers::CTRL | Modifiers::LEFT_CTRL, "\u{1b}[9;5u"),
2170            (Modifiers::CTRL | Modifiers::RIGHT_CTRL, "\u{1b}[9;5u"),
2171            (
2172                Modifiers::SHIFT | Modifiers::CTRL | Modifiers::LEFT_CTRL | Modifiers::LEFT_SHIFT,
2173                "\u{1b}[1;5Z",
2174            ),
2175        ];
2176        for (mods, result) in mods_to_result {
2177            assert_eq!(
2178                KeyCode::Tab.encode(mods, mode, true).unwrap(),
2179                result,
2180                "{:?}",
2181                mods
2182            );
2183        }
2184    }
2185
2186    #[test]
2187    fn mouse_button1_press() {
2188        let mut p = InputParser::new();
2189        let res = p.parse_as_vec(b"\x1b[<0;42;12M", true);
2190        assert_eq!(
2191            res,
2192            vec![InputEvent::Mouse(MouseEvent {
2193                x: 42,
2194                y: 12,
2195                mouse_buttons: MouseButtons::LEFT,
2196                modifiers: Modifiers::NONE,
2197            })]
2198        );
2199    }
2200
2201    #[test]
2202    fn mouse_button1_release() {
2203        let mut p = InputParser::new();
2204        let res = p.parse_as_vec(b"\x1b[<0;42;12m", true);
2205        assert_eq!(
2206            res,
2207            vec![InputEvent::Mouse(MouseEvent {
2208                x: 42,
2209                y: 12,
2210                mouse_buttons: MouseButtons::NONE,
2211                modifiers: Modifiers::NONE,
2212            })]
2213        );
2214    }
2215
2216    #[test]
2217    fn mouse_button3_with_shift() {
2218        let mut p = InputParser::new();
2219        // button 2 (right) = 2, SHIFT adds 4 to p0 -> 6
2220        let res = p.parse_as_vec(b"\x1b[<6;10;20M", true);
2221        assert_eq!(
2222            res,
2223            vec![InputEvent::Mouse(MouseEvent {
2224                x: 10,
2225                y: 20,
2226                mouse_buttons: MouseButtons::RIGHT,
2227                modifiers: Modifiers::SHIFT,
2228            })]
2229        );
2230    }
2231
2232    #[test]
2233    fn mouse_drag() {
2234        let mut p = InputParser::new();
2235        // button1 drag = 32
2236        let res = p.parse_as_vec(b"\x1b[<32;5;5M", true);
2237        assert_eq!(
2238            res,
2239            vec![InputEvent::Mouse(MouseEvent {
2240                x: 5,
2241                y: 5,
2242                mouse_buttons: MouseButtons::LEFT,
2243                modifiers: Modifiers::NONE,
2244            })]
2245        );
2246    }
2247
2248    #[test]
2249    fn mouse_vertical_scroll_up() {
2250        let mut p = InputParser::new();
2251        // button4 press = 64
2252        let res = p.parse_as_vec(b"\x1b[<64;1;1M", true);
2253        assert_eq!(
2254            res,
2255            vec![InputEvent::Mouse(MouseEvent {
2256                x: 1,
2257                y: 1,
2258                mouse_buttons: MouseButtons::VERT_WHEEL | MouseButtons::WHEEL_POSITIVE,
2259                modifiers: Modifiers::NONE,
2260            })]
2261        );
2262    }
2263
2264    #[test]
2265    fn mouse_vertical_scroll_down() {
2266        let mut p = InputParser::new();
2267        // button5 press = 65
2268        let res = p.parse_as_vec(b"\x1b[<65;1;1M", true);
2269        assert_eq!(
2270            res,
2271            vec![InputEvent::Mouse(MouseEvent {
2272                x: 1,
2273                y: 1,
2274                mouse_buttons: MouseButtons::VERT_WHEEL,
2275                modifiers: Modifiers::NONE,
2276            })]
2277        );
2278    }
2279
2280    #[test]
2281    fn mouse_motion_no_buttons() {
2282        let mut p = InputParser::new();
2283        // motion with no buttons = 35
2284        let res = p.parse_as_vec(b"\x1b[<35;10;10M", true);
2285        assert_eq!(
2286            res,
2287            vec![InputEvent::Mouse(MouseEvent {
2288                x: 10,
2289                y: 10,
2290                mouse_buttons: MouseButtons::NONE,
2291                modifiers: Modifiers::NONE,
2292            })]
2293        );
2294    }
2295
2296    #[test]
2297    fn mouse_with_ctrl_alt() {
2298        let mut p = InputParser::new();
2299        // button1 press = 0, ALT=8, CTRL=16 -> 0+8+16=24
2300        let res = p.parse_as_vec(b"\x1b[<24;1;1M", true);
2301        assert_eq!(
2302            res,
2303            vec![InputEvent::Mouse(MouseEvent {
2304                x: 1,
2305                y: 1,
2306                mouse_buttons: MouseButtons::LEFT,
2307                modifiers: Modifiers::ALT | Modifiers::CTRL,
2308            })]
2309        );
2310    }
2311
2312    #[test]
2313    fn mouse_large_coordinates() {
2314        let mut p = InputParser::new();
2315        let res = p.parse_as_vec(b"\x1b[<0;999;999M", true);
2316        assert_eq!(
2317            res,
2318            vec![InputEvent::Mouse(MouseEvent {
2319                x: 999,
2320                y: 999,
2321                mouse_buttons: MouseButtons::LEFT,
2322                modifiers: Modifiers::NONE,
2323            })]
2324        );
2325    }
2326
2327    #[test]
2328    fn mouse_followed_by_key() {
2329        let mut p = InputParser::new();
2330        let res = p.parse_as_vec(b"\x1b[<0;1;1Mhello", false);
2331        assert_eq!(res.len(), 6); // 1 mouse + 5 chars
2332        assert!(matches!(res[0], InputEvent::Mouse(_)));
2333        assert!(matches!(res[1], InputEvent::Key(_)));
2334    }
2335
2336    #[test]
2337    fn two_mouse_events_back_to_back() {
2338        let mut p = InputParser::new();
2339        let res = p.parse_as_vec(b"\x1b[<0;1;1M\x1b[<0;2;2M", true);
2340        assert_eq!(res.len(), 2);
2341    }
2342
2343    #[test]
2344    fn invalid_sgr_mouse_falls_through() {
2345        let mut p = InputParser::new();
2346        // Invalid: missing terminator, not enough params
2347        let res = p.parse_as_vec(b"\x1b[<0;1M", false);
2348        // Should NOT parse as mouse - falls through to keymap
2349        assert!(res.iter().all(|e| matches!(e, InputEvent::Key(_))));
2350    }
2351
2352    #[test]
2353    fn osc_bel_terminated() {
2354        // Complete OSC sequence with BEL terminator
2355        let mut p = InputParser::new();
2356        let inputs = p.parse_as_vec(b"\x1b]99;i=test:p=title;Hello\x07", NO_MORE);
2357        assert_eq!(
2358            vec![InputEvent::OperatingSystemCommand(
2359                b"99;i=test:p=title;Hello".to_vec()
2360            )],
2361            inputs
2362        );
2363    }
2364
2365    #[test]
2366    fn osc_st_terminated() {
2367        // Complete OSC sequence with ST terminator (ESC \)
2368        let mut p = InputParser::new();
2369        let inputs = p.parse_as_vec(b"\x1b]99;i=test:p=title;Hello\x1b\\", NO_MORE);
2370        assert_eq!(
2371            vec![InputEvent::OperatingSystemCommand(
2372                b"99;i=test:p=title;Hello".to_vec()
2373            )],
2374            inputs
2375        );
2376    }
2377
2378    #[test]
2379    fn osc_partial_across_reads() {
2380        // OSC sequence split across two reads — must buffer first part
2381        let mut p = InputParser::new();
2382        let mut inputs = Vec::new();
2383        p.parse(
2384            b"\x1b]99;i=test:p=title;Hel",
2385            |evt| inputs.push(evt),
2386            MAYBE_MORE,
2387        );
2388        assert!(inputs.is_empty(), "no events yet - sequence incomplete");
2389        p.parse(b"lo\x1b\\", |evt| inputs.push(evt), MAYBE_MORE);
2390        assert_eq!(
2391            vec![InputEvent::OperatingSystemCommand(
2392                b"99;i=test:p=title;Hello".to_vec()
2393            )],
2394            inputs
2395        );
2396    }
2397
2398    #[test]
2399    fn osc_followed_by_keypress() {
2400        // OSC sequence then regular key in same buffer
2401        let mut p = InputParser::new();
2402        let inputs = p.parse_as_vec(b"\x1b]99;i=test;clicked\x07x", NO_MORE);
2403        assert_eq!(
2404            vec![
2405                InputEvent::OperatingSystemCommand(b"99;i=test;clicked".to_vec()),
2406                InputEvent::Key(KeyEvent {
2407                    modifiers: Modifiers::NONE,
2408                    key: KeyCode::Char('x'),
2409                }),
2410            ],
2411            inputs
2412        );
2413    }
2414
2415    #[test]
2416    fn keypress_followed_by_osc() {
2417        // Regular key then OSC sequence in same buffer
2418        let mut p = InputParser::new();
2419        let inputs = p.parse_as_vec(b"x\x1b]99;i=test;clicked\x07", NO_MORE);
2420        assert_eq!(
2421            vec![
2422                InputEvent::Key(KeyEvent {
2423                    modifiers: Modifiers::NONE,
2424                    key: KeyCode::Char('x'),
2425                }),
2426                InputEvent::OperatingSystemCommand(b"99;i=test;clicked".to_vec()),
2427            ],
2428            inputs
2429        );
2430    }
2431
2432    #[test]
2433    fn osc_incomplete_degrades_to_keys() {
2434        // Incomplete OSC that never gets a terminator — when finalized with
2435        // maybe_more=false, must degrade to individual key events (not hang)
2436        let mut p = InputParser::new();
2437        let mut inputs = Vec::new();
2438        p.parse(b"\x1b]99;no-terminator", |evt| inputs.push(evt), MAYBE_MORE);
2439        assert!(inputs.is_empty(), "buffered while maybe_more=true");
2440        p.parse(b"", |evt| inputs.push(evt), NO_MORE);
2441        assert!(!inputs.is_empty(), "must emit something on finalization");
2442    }
2443
2444    #[test]
2445    fn osc_non_99_code() {
2446        // Non-99 OSC codes are also captured as OperatingSystemCommand
2447        let mut p = InputParser::new();
2448        let inputs = p.parse_as_vec(b"\x1b]11;rgb:0000/0000/0000\x1b\\", NO_MORE);
2449        assert_eq!(
2450            vec![InputEvent::OperatingSystemCommand(
2451                b"11;rgb:0000/0000/0000".to_vec()
2452            )],
2453            inputs
2454        );
2455    }
2456
2457    #[test]
2458    fn osc_empty_payload() {
2459        // Edge case: OSC with no payload between \x1b] and terminator
2460        let mut p = InputParser::new();
2461        let inputs = p.parse_as_vec(b"\x1b]\x07", NO_MORE);
2462        assert_eq!(
2463            vec![InputEvent::OperatingSystemCommand(b"".to_vec())],
2464            inputs
2465        );
2466    }
2467
2468    #[test]
2469    fn csi_not_captured_as_osc() {
2470        // ESC [ (CSI) must NOT be captured as an OSC sequence.
2471        // This validates that only ESC ] triggers OSC parsing.
2472        let mut p = InputParser::new();
2473        let inputs = p.parse_as_vec(b"\x1b[A", NO_MORE);
2474        assert_eq!(
2475            vec![InputEvent::Key(KeyEvent {
2476                modifiers: Modifiers::NONE,
2477                key: KeyCode::UpArrow,
2478            })],
2479            inputs
2480        );
2481    }
2482}