use crate::escape::csi::MouseReport;
use crate::escape::parser::Parser;
use crate::escape::{Action, CSI};
use crate::keymap::{Found, KeyMap};
use crate::readbuf::ReadBuffer;
use bitflags::bitflags;
#[cfg(feature = "use_serde")]
use serde::{Deserialize, Serialize};
use std;
#[cfg(windows)]
use winapi::um::wincon::{
INPUT_RECORD, KEY_EVENT, KEY_EVENT_RECORD, MOUSE_EVENT, MOUSE_EVENT_RECORD,
WINDOW_BUFFER_SIZE_EVENT, WINDOW_BUFFER_SIZE_RECORD,
};
bitflags! {
#[cfg_attr(feature="use_serde", derive(Serialize, Deserialize))]
#[derive(Default)]
pub struct Modifiers: u8 {
const NONE = 0;
const SHIFT = 1<<1;
const ALT = 1<<2;
const CTRL = 1<<3;
const SUPER = 1<<4;
#[doc(hidden)]
const LEADER = 1<<5;
}
}
bitflags! {
#[cfg_attr(feature="use_serde", derive(Serialize, Deserialize))]
#[derive(Default)]
pub struct MouseButtons: u8 {
const NONE = 0;
const LEFT = 1<<1;
const RIGHT = 1<<2;
const MIDDLE = 1<<3;
const VERT_WHEEL = 1<<4;
const HORZ_WHEEL = 1<<5;
const WHEEL_POSITIVE = 1<<6;
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum InputEvent {
Key(KeyEvent),
Mouse(MouseEvent),
Resized {
cols: usize,
rows: usize,
},
Paste(String),
Wake,
}
#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MouseEvent {
pub x: u16,
pub y: u16,
pub mouse_buttons: MouseButtons,
pub modifiers: Modifiers,
}
#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct KeyEvent {
pub key: KeyCode,
pub modifiers: Modifiers,
}
#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum KeyCode {
Char(char),
Hyper,
Super,
Meta,
Cancel,
Backspace,
Tab,
Clear,
Enter,
Shift,
Escape,
LeftShift,
RightShift,
Control,
LeftControl,
RightControl,
Alt,
LeftAlt,
RightAlt,
Menu,
LeftMenu,
RightMenu,
Pause,
CapsLock,
PageUp,
PageDown,
End,
Home,
LeftArrow,
RightArrow,
UpArrow,
DownArrow,
Select,
Print,
Execute,
PrintScreen,
Insert,
Delete,
Help,
LeftWindows,
RightWindows,
Applications,
Sleep,
Numpad0,
Numpad1,
Numpad2,
Numpad3,
Numpad4,
Numpad5,
Numpad6,
Numpad7,
Numpad8,
Numpad9,
Multiply,
Add,
Separator,
Subtract,
Decimal,
Divide,
Function(u8),
NumLock,
ScrollLock,
BrowserBack,
BrowserForward,
BrowserRefresh,
BrowserStop,
BrowserSearch,
BrowserFavorites,
BrowserHome,
VolumeMute,
VolumeDown,
VolumeUp,
MediaNextTrack,
MediaPrevTrack,
MediaStop,
MediaPlayPause,
ApplicationLeftArrow,
ApplicationRightArrow,
ApplicationUpArrow,
ApplicationDownArrow,
#[doc(hidden)]
InternalPasteStart,
#[doc(hidden)]
InternalPasteEnd,
}
impl KeyCode {
pub fn normalize_shift_to_upper_case(self, modifiers: Modifiers) -> KeyCode {
if modifiers.contains(Modifiers::SHIFT) {
match self {
KeyCode::Char(c) if c.is_ascii_lowercase() => KeyCode::Char(c.to_ascii_uppercase()),
_ => self,
}
} else {
self
}
}
pub fn is_modifier(self) -> bool {
match self {
Self::Hyper
| Self::Super
| Self::Meta
| Self::Shift
| Self::LeftShift
| Self::RightShift
| Self::Control
| Self::LeftControl
| Self::RightControl
| Self::Alt
| Self::LeftAlt
| Self::RightAlt
| Self::LeftWindows
| Self::RightWindows => true,
_ => false,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum InputState {
Normal,
EscapeMaybeAlt,
Pasting(usize),
}
#[derive(Debug)]
pub struct InputParser {
key_map: KeyMap<InputEvent>,
buf: ReadBuffer,
state: InputState,
}
#[cfg(windows)]
mod windows {
use super::*;
use std;
use winapi::um::winuser;
fn modifiers_from_ctrl_key_state(state: u32) -> Modifiers {
use winapi::um::wincon::*;
let mut mods = Modifiers::NONE;
if (state & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) != 0 {
mods |= Modifiers::ALT;
}
if (state & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0 {
mods |= Modifiers::CTRL;
}
if (state & SHIFT_PRESSED) != 0 {
mods |= Modifiers::SHIFT;
}
mods
}
impl InputParser {
fn decode_key_record<F: FnMut(InputEvent)>(
&mut self,
event: &KEY_EVENT_RECORD,
callback: &mut F,
) {
if event.bKeyDown == 0 {
return;
}
let key_code = match std::char::from_u32(*unsafe { event.uChar.UnicodeChar() } as u32) {
Some(unicode) if unicode > '\x00' => {
let mut buf = [0u8; 4];
self.buf
.extend_with(unicode.encode_utf8(&mut buf).as_bytes());
self.process_bytes(callback, true);
return;
}
_ => match event.wVirtualKeyCode as i32 {
winuser::VK_CANCEL => KeyCode::Cancel,
winuser::VK_BACK => KeyCode::Backspace,
winuser::VK_TAB => KeyCode::Tab,
winuser::VK_CLEAR => KeyCode::Clear,
winuser::VK_RETURN => KeyCode::Enter,
winuser::VK_SHIFT => KeyCode::Shift,
winuser::VK_CONTROL => KeyCode::Control,
winuser::VK_MENU => KeyCode::Menu,
winuser::VK_PAUSE => KeyCode::Pause,
winuser::VK_CAPITAL => KeyCode::CapsLock,
winuser::VK_ESCAPE => KeyCode::Escape,
winuser::VK_PRIOR => KeyCode::PageUp,
winuser::VK_NEXT => KeyCode::PageDown,
winuser::VK_END => KeyCode::End,
winuser::VK_HOME => KeyCode::Home,
winuser::VK_LEFT => KeyCode::LeftArrow,
winuser::VK_RIGHT => KeyCode::RightArrow,
winuser::VK_UP => KeyCode::UpArrow,
winuser::VK_DOWN => KeyCode::DownArrow,
winuser::VK_SELECT => KeyCode::Select,
winuser::VK_PRINT => KeyCode::Print,
winuser::VK_EXECUTE => KeyCode::Execute,
winuser::VK_SNAPSHOT => KeyCode::PrintScreen,
winuser::VK_INSERT => KeyCode::Insert,
winuser::VK_DELETE => KeyCode::Delete,
winuser::VK_HELP => KeyCode::Help,
winuser::VK_LWIN => KeyCode::LeftWindows,
winuser::VK_RWIN => KeyCode::RightWindows,
winuser::VK_APPS => KeyCode::Applications,
winuser::VK_SLEEP => KeyCode::Sleep,
winuser::VK_NUMPAD0 => KeyCode::Numpad0,
winuser::VK_NUMPAD1 => KeyCode::Numpad1,
winuser::VK_NUMPAD2 => KeyCode::Numpad2,
winuser::VK_NUMPAD3 => KeyCode::Numpad3,
winuser::VK_NUMPAD4 => KeyCode::Numpad4,
winuser::VK_NUMPAD5 => KeyCode::Numpad5,
winuser::VK_NUMPAD6 => KeyCode::Numpad6,
winuser::VK_NUMPAD7 => KeyCode::Numpad7,
winuser::VK_NUMPAD8 => KeyCode::Numpad8,
winuser::VK_NUMPAD9 => KeyCode::Numpad9,
winuser::VK_MULTIPLY => KeyCode::Multiply,
winuser::VK_ADD => KeyCode::Add,
winuser::VK_SEPARATOR => KeyCode::Separator,
winuser::VK_SUBTRACT => KeyCode::Subtract,
winuser::VK_DECIMAL => KeyCode::Decimal,
winuser::VK_DIVIDE => KeyCode::Divide,
winuser::VK_F1 => KeyCode::Function(1),
winuser::VK_F2 => KeyCode::Function(2),
winuser::VK_F3 => KeyCode::Function(3),
winuser::VK_F4 => KeyCode::Function(4),
winuser::VK_F5 => KeyCode::Function(5),
winuser::VK_F6 => KeyCode::Function(6),
winuser::VK_F7 => KeyCode::Function(7),
winuser::VK_F8 => KeyCode::Function(8),
winuser::VK_F9 => KeyCode::Function(9),
winuser::VK_F10 => KeyCode::Function(10),
winuser::VK_F11 => KeyCode::Function(11),
winuser::VK_F12 => KeyCode::Function(12),
winuser::VK_F13 => KeyCode::Function(13),
winuser::VK_F14 => KeyCode::Function(14),
winuser::VK_F15 => KeyCode::Function(15),
winuser::VK_F16 => KeyCode::Function(16),
winuser::VK_F17 => KeyCode::Function(17),
winuser::VK_F18 => KeyCode::Function(18),
winuser::VK_F19 => KeyCode::Function(19),
winuser::VK_F20 => KeyCode::Function(20),
winuser::VK_F21 => KeyCode::Function(21),
winuser::VK_F22 => KeyCode::Function(22),
winuser::VK_F23 => KeyCode::Function(23),
winuser::VK_F24 => KeyCode::Function(24),
winuser::VK_NUMLOCK => KeyCode::NumLock,
winuser::VK_SCROLL => KeyCode::ScrollLock,
winuser::VK_LSHIFT => KeyCode::LeftShift,
winuser::VK_RSHIFT => KeyCode::RightShift,
winuser::VK_LCONTROL => KeyCode::LeftControl,
winuser::VK_RCONTROL => KeyCode::RightControl,
winuser::VK_LMENU => KeyCode::LeftMenu,
winuser::VK_RMENU => KeyCode::RightMenu,
winuser::VK_BROWSER_BACK => KeyCode::BrowserBack,
winuser::VK_BROWSER_FORWARD => KeyCode::BrowserForward,
winuser::VK_BROWSER_REFRESH => KeyCode::BrowserRefresh,
winuser::VK_BROWSER_STOP => KeyCode::BrowserStop,
winuser::VK_BROWSER_SEARCH => KeyCode::BrowserSearch,
winuser::VK_BROWSER_FAVORITES => KeyCode::BrowserFavorites,
winuser::VK_BROWSER_HOME => KeyCode::BrowserHome,
winuser::VK_VOLUME_MUTE => KeyCode::VolumeMute,
winuser::VK_VOLUME_DOWN => KeyCode::VolumeDown,
winuser::VK_VOLUME_UP => KeyCode::VolumeUp,
winuser::VK_MEDIA_NEXT_TRACK => KeyCode::MediaNextTrack,
winuser::VK_MEDIA_PREV_TRACK => KeyCode::MediaPrevTrack,
winuser::VK_MEDIA_STOP => KeyCode::MediaStop,
winuser::VK_MEDIA_PLAY_PAUSE => KeyCode::MediaPlayPause,
_ => return,
},
};
let mut modifiers = modifiers_from_ctrl_key_state(event.dwControlKeyState);
let key_code = key_code.normalize_shift_to_upper_case(modifiers);
if let KeyCode::Char(c) = key_code {
if c.is_ascii_uppercase() {
modifiers.remove(Modifiers::SHIFT);
}
}
let input_event = InputEvent::Key(KeyEvent {
key: key_code,
modifiers,
});
for _ in 0..event.wRepeatCount {
callback(input_event.clone());
}
}
fn decode_mouse_record<F: FnMut(InputEvent)>(
&self,
event: &MOUSE_EVENT_RECORD,
callback: &mut F,
) {
use winapi::um::wincon::*;
let mut buttons = MouseButtons::NONE;
if (event.dwButtonState & FROM_LEFT_1ST_BUTTON_PRESSED) != 0 {
buttons |= MouseButtons::LEFT;
}
if (event.dwButtonState & RIGHTMOST_BUTTON_PRESSED) != 0 {
buttons |= MouseButtons::RIGHT;
}
if (event.dwButtonState & FROM_LEFT_2ND_BUTTON_PRESSED) != 0 {
buttons |= MouseButtons::MIDDLE;
}
let modifiers = modifiers_from_ctrl_key_state(event.dwControlKeyState);
if (event.dwEventFlags & MOUSE_WHEELED) != 0 {
buttons |= MouseButtons::VERT_WHEEL;
if (event.dwButtonState >> 8) != 0 {
buttons |= MouseButtons::WHEEL_POSITIVE;
}
} else if (event.dwEventFlags & MOUSE_HWHEELED) != 0 {
buttons |= MouseButtons::HORZ_WHEEL;
if (event.dwButtonState >> 8) != 0 {
buttons |= MouseButtons::WHEEL_POSITIVE;
}
}
let mouse = InputEvent::Mouse(MouseEvent {
x: event.dwMousePosition.X as u16,
y: event.dwMousePosition.Y as u16,
mouse_buttons: buttons,
modifiers,
});
if (event.dwEventFlags & DOUBLE_CLICK) != 0 {
callback(mouse.clone());
}
callback(mouse);
}
fn decode_resize_record<F: FnMut(InputEvent)>(
&self,
event: &WINDOW_BUFFER_SIZE_RECORD,
callback: &mut F,
) {
callback(InputEvent::Resized {
rows: event.dwSize.Y as usize,
cols: event.dwSize.X as usize,
});
}
pub fn decode_input_records<F: FnMut(InputEvent)>(
&mut self,
records: &[INPUT_RECORD],
callback: &mut F,
) {
for record in records {
match record.EventType {
KEY_EVENT => {
self.decode_key_record(unsafe { record.Event.KeyEvent() }, callback)
}
MOUSE_EVENT => {
self.decode_mouse_record(unsafe { record.Event.MouseEvent() }, callback)
}
WINDOW_BUFFER_SIZE_EVENT => self.decode_resize_record(
unsafe { record.Event.WindowBufferSizeEvent() },
callback,
),
_ => {}
}
}
self.process_bytes(callback, false);
}
}
}
impl Default for InputParser {
fn default() -> Self {
Self::new()
}
}
impl InputParser {
pub fn new() -> Self {
Self {
key_map: Self::build_basic_key_map(),
buf: ReadBuffer::new(),
state: InputState::Normal,
}
}
fn build_basic_key_map() -> KeyMap<InputEvent> {
let mut map = KeyMap::new();
let modifier_combos = &[
("", Modifiers::NONE),
(";1", Modifiers::NONE),
(";2", Modifiers::SHIFT),
(";3", Modifiers::ALT),
(";4", Modifiers::ALT | Modifiers::SHIFT),
(";5", Modifiers::CTRL),
(";6", Modifiers::CTRL | Modifiers::SHIFT),
(";7", Modifiers::CTRL | Modifiers::ALT),
(";8", Modifiers::CTRL | Modifiers::ALT | Modifiers::SHIFT),
];
let meta = Modifiers::ALT;
let meta_modifier_combos = &[
(";9", meta),
(";10", meta | Modifiers::SHIFT),
(";11", meta | Modifiers::ALT),
(";12", meta | Modifiers::ALT | Modifiers::SHIFT),
(";13", meta | Modifiers::CTRL),
(";14", meta | Modifiers::CTRL | Modifiers::SHIFT),
(";15", meta | Modifiers::CTRL | Modifiers::ALT),
(
";16",
meta | Modifiers::CTRL | Modifiers::ALT | Modifiers::SHIFT,
),
];
let modifier_combos_including_meta =
|| modifier_combos.iter().chain(meta_modifier_combos.iter());
for alpha in b'A'..=b'Z' {
let ctrl = [alpha & 0x1f];
map.insert(
&ctrl,
InputEvent::Key(KeyEvent {
key: KeyCode::Char(alpha as char),
modifiers: Modifiers::CTRL,
}),
);
let alt = [0x1b, alpha];
map.insert(
&alt,
InputEvent::Key(KeyEvent {
key: KeyCode::Char(alpha as char),
modifiers: Modifiers::ALT,
}),
);
}
for c in 0..=0x7fu8 {
for (suffix, modifiers) in modifier_combos {
let key = format!("\x1b[{}{}u", c, suffix);
map.insert(
key,
InputEvent::Key(KeyEvent {
key: KeyCode::Char(c as char),
modifiers: *modifiers,
}),
);
}
}
for (keycode, dir) in &[
(KeyCode::UpArrow, b'A'),
(KeyCode::DownArrow, b'B'),
(KeyCode::RightArrow, b'C'),
(KeyCode::LeftArrow, b'D'),
(KeyCode::Home, b'H'),
(KeyCode::End, b'F'),
] {
let arrow = [0x1b, b'[', *dir];
map.insert(
&arrow,
InputEvent::Key(KeyEvent {
key: *keycode,
modifiers: Modifiers::NONE,
}),
);
for (suffix, modifiers) in modifier_combos_including_meta() {
let key = format!("\x1b[1{}{}", suffix, *dir as char);
map.insert(
key,
InputEvent::Key(KeyEvent {
key: *keycode,
modifiers: *modifiers,
}),
);
}
}
for &(keycode, dir) in &[
(KeyCode::UpArrow, b'a'),
(KeyCode::DownArrow, b'b'),
(KeyCode::RightArrow, b'c'),
(KeyCode::LeftArrow, b'd'),
] {
for &(seq, mods) in &[
([0x1b, b'[', dir], Modifiers::SHIFT),
([0x1b, b'O', dir], Modifiers::CTRL),
] {
map.insert(
&seq,
InputEvent::Key(KeyEvent {
key: keycode,
modifiers: mods,
}),
);
}
}
for (keycode, dir) in &[
(KeyCode::ApplicationUpArrow, b'A'),
(KeyCode::ApplicationDownArrow, b'B'),
(KeyCode::ApplicationRightArrow, b'C'),
(KeyCode::ApplicationLeftArrow, b'D'),
] {
let app = [0x1b, b'O', *dir];
map.insert(
&app,
InputEvent::Key(KeyEvent {
key: *keycode,
modifiers: Modifiers::NONE,
}),
);
for (suffix, modifiers) in modifier_combos {
let key = format!("\x1bO1{}{}", suffix, *dir as char);
map.insert(
key,
InputEvent::Key(KeyEvent {
key: *keycode,
modifiers: *modifiers,
}),
);
}
}
for (keycode, c) in &[
(KeyCode::Function(1), b'P'),
(KeyCode::Function(2), b'Q'),
(KeyCode::Function(3), b'R'),
(KeyCode::Function(4), b'S'),
] {
let key = [0x1b, b'O', *c];
map.insert(
&key,
InputEvent::Key(KeyEvent {
key: *keycode,
modifiers: Modifiers::NONE,
}),
);
}
for (keycode, c) in &[
(KeyCode::Function(1), b'P'),
(KeyCode::Function(2), b'Q'),
(KeyCode::Function(3), b'R'),
(KeyCode::Function(4), b'S'),
] {
for (suffix, modifiers) in modifier_combos_including_meta() {
let key = format!("\x1b[1{suffix}{code}", code = *c as char, suffix = suffix);
map.insert(
key,
InputEvent::Key(KeyEvent {
key: *keycode,
modifiers: *modifiers,
}),
);
}
}
for (range, offset) in &[
(1..=5, 10),
(6..=10, 11),
(11..=14, 12),
(15..=16, 13),
(17..=20, 14),
] {
for n in range.clone() {
for (suffix, modifiers) in modifier_combos_including_meta() {
let key = format!("\x1b[{code}{suffix}~", code = n + offset, suffix = suffix);
map.insert(
key,
InputEvent::Key(KeyEvent {
key: KeyCode::Function(n),
modifiers: *modifiers,
}),
);
}
}
}
for (keycode, c) in &[
(KeyCode::Insert, b'2'),
(KeyCode::Delete, b'3'),
(KeyCode::Home, b'1'),
(KeyCode::End, b'4'),
(KeyCode::PageUp, b'5'),
(KeyCode::PageDown, b'6'),
(KeyCode::Home, b'7'),
(KeyCode::End, b'8'),
] {
for (suffix, modifiers) in &[
(b'~', Modifiers::NONE),
(b'$', Modifiers::SHIFT),
(b'^', Modifiers::CTRL),
(b'@', Modifiers::SHIFT | Modifiers::CTRL),
] {
let key = [0x1b, b'[', *c, *suffix];
map.insert(
key,
InputEvent::Key(KeyEvent {
key: *keycode,
modifiers: *modifiers,
}),
);
}
}
map.insert(
&[0x7f],
InputEvent::Key(KeyEvent {
key: KeyCode::Backspace,
modifiers: Modifiers::NONE,
}),
);
map.insert(
&[0x8],
InputEvent::Key(KeyEvent {
key: KeyCode::Backspace,
modifiers: Modifiers::NONE,
}),
);
map.insert(
&[0x1b],
InputEvent::Key(KeyEvent {
key: KeyCode::Escape,
modifiers: Modifiers::NONE,
}),
);
map.insert(
&[b'\t'],
InputEvent::Key(KeyEvent {
key: KeyCode::Tab,
modifiers: Modifiers::NONE,
}),
);
map.insert(
&[b'\r'],
InputEvent::Key(KeyEvent {
key: KeyCode::Enter,
modifiers: Modifiers::NONE,
}),
);
map.insert(
&[b'\n'],
InputEvent::Key(KeyEvent {
key: KeyCode::Enter,
modifiers: Modifiers::NONE,
}),
);
map.insert(
b"\x1b[200~",
InputEvent::Key(KeyEvent {
key: KeyCode::InternalPasteStart,
modifiers: Modifiers::NONE,
}),
);
map.insert(
b"\x1b[201~",
InputEvent::Key(KeyEvent {
key: KeyCode::InternalPasteEnd,
modifiers: Modifiers::NONE,
}),
);
map
}
fn first_char_and_len(s: &str) -> (char, usize) {
let mut iter = s.chars();
let c = iter.next().unwrap();
(c, c.len_utf8())
}
fn decode_one_char(bytes: &[u8]) -> Option<(char, usize)> {
let bytes = &bytes[..bytes.len().min(4)];
match std::str::from_utf8(bytes) {
Ok(s) => {
let (c, len) = Self::first_char_and_len(s);
Some((c, len))
}
Err(err) => {
let (valid, _after_valid) = bytes.split_at(err.valid_up_to());
if !valid.is_empty() {
let s = unsafe { std::str::from_utf8_unchecked(valid) };
let (c, len) = Self::first_char_and_len(s);
Some((c, len))
} else {
None
}
}
}
}
fn dispatch_callback<F: FnMut(InputEvent)>(&mut self, mut callback: F, event: InputEvent) {
match (self.state, event) {
(
InputState::Normal,
InputEvent::Key(KeyEvent {
key: KeyCode::InternalPasteStart,
..
}),
) => {
self.state = InputState::Pasting(0);
}
(
InputState::EscapeMaybeAlt,
InputEvent::Key(KeyEvent {
key: KeyCode::InternalPasteStart,
..
}),
) => {
callback(InputEvent::Key(KeyEvent {
key: KeyCode::Escape,
modifiers: Modifiers::NONE,
}));
self.state = InputState::Pasting(0);
}
(InputState::EscapeMaybeAlt, InputEvent::Key(KeyEvent { key, modifiers })) => {
self.state = InputState::Normal;
callback(InputEvent::Key(KeyEvent {
key,
modifiers: modifiers | Modifiers::ALT,
}));
}
(InputState::EscapeMaybeAlt, event) => {
callback(InputEvent::Key(KeyEvent {
key: KeyCode::Escape,
modifiers: Modifiers::NONE,
}));
callback(event);
}
(_, event) => callback(event),
}
}
fn process_bytes<F: FnMut(InputEvent)>(&mut self, mut callback: F, maybe_more: bool) {
while !self.buf.is_empty() {
match self.state {
InputState::Pasting(offset) => {
let end_paste = b"\x1b[201~";
if let Some(idx) = self.buf.find_subsequence(offset, end_paste) {
let pasted =
String::from_utf8_lossy(&self.buf.as_slice()[0..idx]).to_string();
self.buf.advance(pasted.len() + end_paste.len());
callback(InputEvent::Paste(pasted));
self.state = InputState::Normal;
} else {
self.state = InputState::Pasting(self.buf.len() - end_paste.len());
return;
}
}
InputState::EscapeMaybeAlt | InputState::Normal => {
if self.state == InputState::Normal && self.buf.as_slice()[0] == b'\x1b' {
let mut parser = Parser::new();
if let Some((Action::CSI(CSI::Mouse(mouse)), len)) =
parser.parse_first(self.buf.as_slice())
{
self.buf.advance(len);
match mouse {
MouseReport::SGR1006 {
x,
y,
button,
modifiers,
} => {
callback(InputEvent::Mouse(MouseEvent {
x,
y,
mouse_buttons: button.into(),
modifiers,
}));
}
}
continue;
}
}
match (self.key_map.lookup(self.buf.as_slice()), maybe_more) {
(
Found::Exact(
len,
InputEvent::Key(KeyEvent {
key: KeyCode::Escape,
modifiers: Modifiers::NONE,
}),
),
_,
) if self.state == InputState::Normal && self.buf.len() > len => {
self.state = InputState::EscapeMaybeAlt;
self.buf.advance(len);
}
(Found::Exact(len, event), _) | (Found::Ambiguous(len, event), false) => {
self.dispatch_callback(&mut callback, event.clone());
self.buf.advance(len);
}
(Found::Ambiguous(_, _), true) | (Found::NeedData, true) => {
return;
}
(Found::None, _) | (Found::NeedData, false) => {
if let Some((c, len)) = Self::decode_one_char(self.buf.as_slice()) {
self.buf.advance(len);
self.dispatch_callback(
&mut callback,
InputEvent::Key(KeyEvent {
key: KeyCode::Char(c),
modifiers: Modifiers::NONE,
}),
);
} else {
return;
}
}
}
}
}
}
}
pub fn parse<F: FnMut(InputEvent)>(&mut self, bytes: &[u8], callback: F, maybe_more: bool) {
self.buf.extend_with(bytes);
self.process_bytes(callback, maybe_more);
}
pub fn parse_as_vec(&mut self, bytes: &[u8]) -> Vec<InputEvent> {
let mut result = Vec::new();
self.parse(bytes, |event| result.push(event), false);
result
}
#[cfg(windows)]
pub fn decode_input_records_as_vec(&mut self, records: &[INPUT_RECORD]) -> Vec<InputEvent> {
let mut result = Vec::new();
self.decode_input_records(records, &mut |event| result.push(event));
result
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn simple() {
let mut p = InputParser::new();
let inputs = p.parse_as_vec(b"hello");
assert_eq!(
vec![
InputEvent::Key(KeyEvent {
modifiers: Modifiers::NONE,
key: KeyCode::Char('h'),
}),
InputEvent::Key(KeyEvent {
modifiers: Modifiers::NONE,
key: KeyCode::Char('e'),
}),
InputEvent::Key(KeyEvent {
modifiers: Modifiers::NONE,
key: KeyCode::Char('l'),
}),
InputEvent::Key(KeyEvent {
modifiers: Modifiers::NONE,
key: KeyCode::Char('l'),
}),
InputEvent::Key(KeyEvent {
modifiers: Modifiers::NONE,
key: KeyCode::Char('o'),
}),
],
inputs
);
}
#[test]
fn control_characters() {
let mut p = InputParser::new();
let inputs = p.parse_as_vec(b"\x03\x1bJ\x7f");
assert_eq!(
vec![
InputEvent::Key(KeyEvent {
modifiers: Modifiers::CTRL,
key: KeyCode::Char('C'),
}),
InputEvent::Key(KeyEvent {
modifiers: Modifiers::ALT,
key: KeyCode::Char('J'),
}),
InputEvent::Key(KeyEvent {
modifiers: Modifiers::NONE,
key: KeyCode::Backspace,
}),
],
inputs
);
}
#[test]
fn arrow_keys() {
let mut p = InputParser::new();
let inputs = p.parse_as_vec(b"\x1bOA\x1bOB\x1bOC\x1bOD");
assert_eq!(
vec![
InputEvent::Key(KeyEvent {
modifiers: Modifiers::NONE,
key: KeyCode::ApplicationUpArrow,
}),
InputEvent::Key(KeyEvent {
modifiers: Modifiers::NONE,
key: KeyCode::ApplicationDownArrow,
}),
InputEvent::Key(KeyEvent {
modifiers: Modifiers::NONE,
key: KeyCode::ApplicationRightArrow,
}),
InputEvent::Key(KeyEvent {
modifiers: Modifiers::NONE,
key: KeyCode::ApplicationLeftArrow,
}),
],
inputs
);
}
#[test]
fn partial() {
let mut p = InputParser::new();
let mut inputs = Vec::new();
p.parse(b"\x1b[11", |evt| inputs.push(evt), true);
p.parse(b"~", |evt| inputs.push(evt), true);
assert_eq!(
vec![InputEvent::Key(KeyEvent {
modifiers: Modifiers::NONE,
key: KeyCode::Function(1),
})],
inputs
);
}
#[test]
fn partial_ambig() {
let mut p = InputParser::new();
assert_eq!(
vec![InputEvent::Key(KeyEvent {
key: KeyCode::Escape,
modifiers: Modifiers::NONE,
})],
p.parse_as_vec(b"\x1b")
);
let mut inputs = Vec::new();
p.parse(b"\x1b[11", |evt| inputs.push(evt), true);
p.parse(b"", |evt| inputs.push(evt), false);
assert_eq!(
vec![
InputEvent::Key(KeyEvent {
key: KeyCode::Escape,
modifiers: Modifiers::NONE,
}),
InputEvent::Key(KeyEvent {
modifiers: Modifiers::NONE,
key: KeyCode::Char('['),
}),
InputEvent::Key(KeyEvent {
modifiers: Modifiers::NONE,
key: KeyCode::Char('1'),
}),
InputEvent::Key(KeyEvent {
modifiers: Modifiers::NONE,
key: KeyCode::Char('1'),
}),
],
inputs
);
}
}