1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum Key {
6 Up,
7 Down,
8 Left,
9 Right,
10 Home,
11 End,
12 Delete,
13 Backspace,
14 Enter,
15 Tab,
16 BackTab,
17 Esc,
18 Char(char),
19 Ctrl(char),
21}
22
23pub fn decode(bytes: &[u8]) -> Vec<Key> {
25 let mut keys = Vec::new();
26 let mut i = 0;
27 while i < bytes.len() {
28 let b = bytes[i];
29 match b {
30 0x1b => {
31 if i + 1 >= bytes.len() {
32 keys.push(Key::Esc);
33 i += 1;
34 continue;
35 }
36 match bytes[i + 1] {
37 b'[' | b'O' => {
38 let mut j = i + 2;
40 while j < bytes.len() && !(0x40..=0x7e).contains(&bytes[j]) {
41 j += 1;
42 }
43 let params = &bytes[i + 2..j.min(bytes.len())];
44 if let Some(&final_byte) = bytes.get(j) {
45 if let Some(key) = csi_key(params, final_byte) {
46 keys.push(key);
47 }
48 }
49 i = j + 1;
50 }
51 _ => i += 1,
53 }
54 }
55 0x0d | 0x0a => {
56 keys.push(Key::Enter);
57 i += 1;
58 }
59 0x09 => {
60 keys.push(Key::Tab);
61 i += 1;
62 }
63 0x7f | 0x08 => {
64 keys.push(Key::Backspace);
65 i += 1;
66 }
67 0x01..=0x1a => {
68 keys.push(Key::Ctrl((b - 1 + b'a') as char));
69 i += 1;
70 }
71 0x00 | 0x1c..=0x1f => i += 1,
72 _ => {
73 let len = match b {
75 0x00..=0x7f => 1,
76 0xc0..=0xdf => 2,
77 0xe0..=0xef => 3,
78 0xf0..=0xf7 => 4,
79 _ => 1,
80 };
81 let end = (i + len).min(bytes.len());
82 if let Some(c) = std::str::from_utf8(&bytes[i..end])
83 .ok()
84 .and_then(|s| s.chars().next())
85 {
86 keys.push(Key::Char(c));
87 }
88 i = end;
89 }
90 }
91 }
92 keys
93}
94
95fn csi_key(params: &[u8], final_byte: u8) -> Option<Key> {
96 match final_byte {
97 b'A' => Some(Key::Up),
98 b'B' => Some(Key::Down),
99 b'C' => Some(Key::Right),
100 b'D' => Some(Key::Left),
101 b'H' => Some(Key::Home),
102 b'F' => Some(Key::End),
103 b'Z' => Some(Key::BackTab),
104 b'~' => match params {
105 b"1" | b"7" => Some(Key::Home),
106 b"4" | b"8" => Some(Key::End),
107 b"3" => Some(Key::Delete),
108 _ => None,
109 },
110 _ => None,
111 }
112}
113
114#[cfg(test)]
115mod tests;