use super::types::{KeyCode, KeyModifiers, Mouse, MouseButton, Sequence}; pub(crate) fn parse_char(ch: char, esc_o: bool) -> Option { if esc_o { return match ch { 'P'..='S' => Some(Sequence::Key( KeyCode::F(ch as u8 - b'P' + 1), KeyModifiers::empty(), )), _ => None, }; } let code = match ch { '\r' | '\n' => KeyCode::Enter, '\t' => KeyCode::Tab, '\x7F' => KeyCode::BackTab, '\x1B' => KeyCode::Esc, '\0' => KeyCode::Null, _ => KeyCode::Char(ch), }; Some(Sequence::Key(code, KeyModifiers::empty())) } pub(crate) fn parse_esc_sequence(ch: char) -> Option { // EscO[P-S] is handled in the Performer, see parse_char & esc_o argument // No need to handle other cases here? It's just Alt+$char Some(Sequence::Key(KeyCode::Char(ch), KeyModifiers::ALT)) } pub(crate) fn parse_csi_sequence( parameters: &[u64], _ignored_count: usize, ch: char, ) -> Option { match ch { 'A' => Some(Sequence::Key( KeyCode::Up, parse_csi_arrow_key_modifiers(parameters.first().cloned()), )), 'B' => Some(Sequence::Key( KeyCode::Down, parse_csi_arrow_key_modifiers(parameters.first().cloned()), )), 'C' => Some(Sequence::Key( KeyCode::Right, parse_csi_arrow_key_modifiers(parameters.first().cloned()), )), 'D' => Some(Sequence::Key( KeyCode::Left, parse_csi_arrow_key_modifiers(parameters.first().cloned()), )), 'H' => Some(Sequence::Key(KeyCode::Home, KeyModifiers::empty())), 'F' => Some(Sequence::Key(KeyCode::End, KeyModifiers::empty())), 'Z' => Some(Sequence::Key(KeyCode::BackTab, KeyModifiers::empty())), 'R' => parse_csi_cursor_position(parameters), 'm' => parse_csi_xterm_mouse(parameters, ch), 'M' if parameters.first() == Some(&0x3C) => parse_csi_xterm_mouse(parameters, ch), 'M' => parse_csi_rxvt_mouse(parameters), '~' => parse_csi_tilde_key_code(parameters), _ => None, } } fn parse_csi_arrow_key_modifiers(parameter: Option) -> KeyModifiers { parse_key_modifiers(parameter.map(|x| x.saturating_sub(48))) } fn parse_key_modifiers(parameter: Option) -> KeyModifiers { if let Some(parameter) = parameter { match parameter { 2 => KeyModifiers::SHIFT, 3 => KeyModifiers::ALT, 4 => KeyModifiers::SHIFT | KeyModifiers::ALT, 5 => KeyModifiers::CONTROL, 6 => KeyModifiers::SHIFT | KeyModifiers::CONTROL, 7 => KeyModifiers::ALT | KeyModifiers::CONTROL, 8 => KeyModifiers::SHIFT | KeyModifiers::ALT | KeyModifiers::CONTROL, 9 => KeyModifiers::META, 10 => KeyModifiers::META | KeyModifiers::SHIFT, 11 => KeyModifiers::META | KeyModifiers::ALT, 12 => KeyModifiers::META | KeyModifiers::SHIFT | KeyModifiers::ALT, 13 => KeyModifiers::META | KeyModifiers::CONTROL, 14 => KeyModifiers::META | KeyModifiers::SHIFT | KeyModifiers::CONTROL, 15 => KeyModifiers::META | KeyModifiers::ALT | KeyModifiers::CONTROL, 16 => { KeyModifiers::META | KeyModifiers::SHIFT | KeyModifiers::ALT | KeyModifiers::CONTROL } _ => KeyModifiers::empty(), } } else { KeyModifiers::empty() } } fn parse_csi_tilde_key_code(parameters: &[u64]) -> Option { if parameters.is_empty() { return None; } let modifiers = parse_key_modifiers(parameters.get(1).cloned()); let code = match parameters[0] { 1 | 7 => KeyCode::Home, 2 => KeyCode::Insert, 3 => KeyCode::Delete, 4 | 8 => KeyCode::End, 5 => KeyCode::PageUp, 6 => KeyCode::PageDown, p @ 11..=15 => KeyCode::F(p as u8 - 10), p @ 17..=21 => KeyCode::F(p as u8 - 11), p @ 23..=24 => KeyCode::F(p as u8 - 12), _ => return None, }; Some(Sequence::Key(code, modifiers)) } fn parse_csi_cursor_position(parameters: &[u64]) -> Option { // ESC [ Cy ; Cx R if parameters.len() < 2 { return None; } let y = parameters[0] as u16; let x = parameters[1] as u16; Some(Sequence::CursorPosition(x, y)) } fn parse_csi_xterm_mouse(parameters: &[u64], ch: char) -> Option { // ESC [ < Cb ; Cx ; Cy (;) (M or m) if parameters.len() < 4 { return None; } let cb = parameters[1] as u8; let cx = parameters[2] as u16; let cy = parameters[3] as u16; let up = match ch { 'm' => true, 'M' => false, _ => return None, }; let mut modifiers = KeyModifiers::empty(); if cb & 0b0000_0100 == 0b0000_0100 { modifiers |= KeyModifiers::SHIFT; } if cb & 0b0000_1000 == 0b0000_1000 { modifiers |= KeyModifiers::ALT; } if cb & 0b0001_0000 == 0b0001_0000 { modifiers |= KeyModifiers::CONTROL; } let mouse = if cb & 0b0100_0000 == 0b0100_0000 { if cb & 0b0000_0001 == 0b0000_0001 { Mouse::ScrollDown(cx, cy) } else { Mouse::ScrollUp(cx, cy) } } else { let drag = cb & 0b0010_0000 == 0b0010_0000; match (cb & 0b0000_0011, up, drag) { (0, true, _) => Mouse::Up(MouseButton::Left, cx, cy), (0, false, false) => Mouse::Down(MouseButton::Left, cx, cy), (0, false, true) => Mouse::Drag(MouseButton::Left, cx, cy), (1, true, _) => Mouse::Up(MouseButton::Middle, cx, cy), (1, false, false) => Mouse::Down(MouseButton::Middle, cx, cy), (1, false, true) => Mouse::Drag(MouseButton::Middle, cx, cy), (2, true, _) => Mouse::Up(MouseButton::Right, cx, cy), (2, false, false) => Mouse::Down(MouseButton::Right, cx, cy), (2, false, true) => Mouse::Drag(MouseButton::Right, cx, cy), _ => return None, } }; Some(Sequence::Mouse(mouse, modifiers)) } fn parse_csi_rxvt_mouse(parameters: &[u64]) -> Option { // ESC [ Cb ; Cx ; Cy ; M if parameters.len() < 3 { return None; } let cb = parameters[0]; let cx = parameters[1] as u16; let cy = parameters[2] as u16; let mut modifiers = KeyModifiers::empty(); if cb & 0b0000_0100 == 0b0000_0100 { modifiers |= KeyModifiers::SHIFT; } if cb & 0b0000_1000 == 0b0000_1000 { modifiers |= KeyModifiers::ALT; } if cb & 0b0001_0000 == 0b0001_0000 { modifiers |= KeyModifiers::CONTROL; } let mouse = if cb & 0b0110_0000 == 0b0110_0000 { if cb & 0b0000_0001 == 0b0000_0001 { Mouse::ScrollDown(cx, cy) } else { Mouse::ScrollUp(cx, cy) } } else { let drag = cb & 0b0100_0000 == 0b0100_0000; match (cb & 0b0000_0011, drag) { (0b0000_0000, false) => Mouse::Down(MouseButton::Left, cx, cy), (0b0000_0010, false) => Mouse::Down(MouseButton::Right, cx, cy), (0b0000_0001, false) => Mouse::Down(MouseButton::Middle, cx, cy), (0b0000_0000, true) => Mouse::Drag(MouseButton::Left, cx, cy), (0b0000_0010, true) => Mouse::Drag(MouseButton::Right, cx, cy), (0b0000_0001, true) => Mouse::Drag(MouseButton::Middle, cx, cy), (0b0000_0011, false) => Mouse::Up(MouseButton::Any, cx, cy), _ => return None, } }; Some(Sequence::Mouse(mouse, modifiers)) }