1pub struct CodePoint {
7 pub code_point: u32,
8 pub control_pressed: bool,
9}
10
11impl From<CodePoint> for Option<String> {
12 fn from(item: CodePoint) -> Self {
13 if item.code_point > 128 {
15 return None;
16 }
17
18 let mut code_point = item.code_point;
19 if item.control_pressed {
21 if let Some(c) = std::char::from_u32(item.code_point) {
22 match c {
23 'a'..='z' => code_point = code_point - 96,
24 'A'..='Z' => code_point = code_point - 64,
25 _ => (),
26 };
27 }
28 }
29
30 String::from_utf8(vec![code_point as u8]).ok()
31 }
32}
33
34const HID_USAGE_KEY_ENTER: u32 = 0x28;
35const HID_USAGE_KEY_ESC: u32 = 0x29;
36const HID_USAGE_KEY_BACKSPACE: u32 = 0x2a;
37const HID_USAGE_KEY_TAB: u32 = 0x2b;
38const HID_USAGE_KEY_INSERT: u32 = 0x49;
39const HID_USAGE_KEY_HOME: u32 = 0x4a;
40const HID_USAGE_KEY_PAGEUP: u32 = 0x4b;
41const HID_USAGE_KEY_DELETE: u32 = 0x4c;
42const HID_USAGE_KEY_END: u32 = 0x4d;
43const HID_USAGE_KEY_PAGEDOWN: u32 = 0x4e;
44const HID_USAGE_KEY_RIGHT: u32 = 0x4f;
45const HID_USAGE_KEY_LEFT: u32 = 0x50;
46const HID_USAGE_KEY_DOWN: u32 = 0x51;
47const HID_USAGE_KEY_UP: u32 = 0x52;
48
49pub struct HidUsage {
51 pub hid_usage: u32,
52 pub app_cursor: bool,
53}
54
55impl From<HidUsage> for Option<String> {
56 fn from(item: HidUsage) -> Self {
57 let esc: char = 0x1b_u8.into();
58 macro_rules! escape_string {
59 ($x:expr) => {{
60 Some(format!("{}{}", esc, $x))
61 }};
62 }
63
64 let app_cursor = item.app_cursor;
65 match item.hid_usage {
66 HID_USAGE_KEY_BACKSPACE => Some(String::from("\x7f")),
67 HID_USAGE_KEY_ESC => escape_string!(""),
68 HID_USAGE_KEY_PAGEDOWN => escape_string!("[6~"),
69 HID_USAGE_KEY_PAGEUP => escape_string!("[5~"),
70 HID_USAGE_KEY_END if app_cursor => escape_string!("OF"),
71 HID_USAGE_KEY_END => escape_string!("[F"),
72 HID_USAGE_KEY_HOME if app_cursor => escape_string!("OH"),
73 HID_USAGE_KEY_HOME => escape_string!("[H"),
74 HID_USAGE_KEY_LEFT if app_cursor => escape_string!("OD"),
75 HID_USAGE_KEY_LEFT => escape_string!("[D"),
76 HID_USAGE_KEY_UP if app_cursor => escape_string!("OA"),
77 HID_USAGE_KEY_UP => escape_string!("[A"),
78 HID_USAGE_KEY_RIGHT if app_cursor => escape_string!("OC"),
79 HID_USAGE_KEY_RIGHT => escape_string!("[C"),
80 HID_USAGE_KEY_DOWN if app_cursor => escape_string!("OB"),
81 HID_USAGE_KEY_DOWN => escape_string!("[B"),
82 HID_USAGE_KEY_INSERT => escape_string!("[2~"),
83 HID_USAGE_KEY_DELETE => escape_string!("[3~"),
84 HID_USAGE_KEY_ENTER => Some(String::from("\n")),
85 HID_USAGE_KEY_TAB => Some(String::from("\t")),
86 _ => None,
87 }
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94
95 #[test]
96 fn convert_from_code_point_unsupported_values() {
97 assert!(
98 Option::<String>::from(CodePoint { code_point: 129, control_pressed: false }).is_none()
99 );
100 }
101
102 #[test]
103 fn convert_from_code_point_shifts_when_control_pressed_lowercase() {
104 let mut i = 0;
105 for c in (b'a'..=b'z').map(char::from) {
106 i = i + 1;
107 let result =
108 Option::<String>::from(CodePoint { code_point: c as u32, control_pressed: true })
109 .unwrap();
110 let expected = String::from_utf8(vec![i]).unwrap();
111 assert_eq!(result, expected);
112 }
113 }
114
115 #[test]
116 fn convert_from_code_point_shifts_when_control_pressed_uppercase() {
117 let mut i = 0;
118 for c in (b'A'..=b'Z').map(char::from) {
119 i = i + 1;
120 let result =
121 Option::<String>::from(CodePoint { code_point: c as u32, control_pressed: true })
122 .unwrap();
123
124 let expected = String::from_utf8(vec![i]).unwrap();
125 assert_eq!(result, expected);
126 }
127 }
128
129 #[test]
130 fn convert_from_hid_usage_left() {
131 let result =
132 Option::<String>::from(HidUsage { hid_usage: HID_USAGE_KEY_LEFT, app_cursor: false })
133 .unwrap();
134 let expected = String::from("\u{1b}[D");
135 assert_eq!(result, expected);
136 }
137
138 #[test]
139 fn convert_from_hid_usage_left_app_cursor() {
140 let result =
141 Option::<String>::from(HidUsage { hid_usage: HID_USAGE_KEY_LEFT, app_cursor: true })
142 .unwrap();
143 let expected = String::from("\u{1b}OD");
144 assert_eq!(result, expected);
145 }
146}