1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2pub enum Key {
3 Char(char),
4 ArrowUp,
5 ArrowDown,
6 ArrowLeft,
7 ArrowRight,
8 F(u8),
9 Enter,
10 Escape,
11 Tab,
12 BackTab,
13 Backspace,
14 Delete,
15 Home,
16 End,
17 PageUp,
18 PageDown,
19}
20
21use crossterm::event::KeyCode;
22
23impl TryFrom<KeyCode> for Key {
24 type Error = ();
25
26 fn try_from(code: KeyCode) -> Result<Self, Self::Error> {
27 Ok(match code {
28 KeyCode::Char(c) => Key::Char(c),
29
30 KeyCode::Up => Key::ArrowUp,
31 KeyCode::Down => Key::ArrowDown,
32 KeyCode::Left => Key::ArrowLeft,
33 KeyCode::Right => Key::ArrowRight,
34
35 KeyCode::Enter => Key::Enter,
36 KeyCode::Esc => Key::Escape,
37 KeyCode::Tab => Key::Tab,
38 KeyCode::BackTab => Key::BackTab,
39 KeyCode::Backspace => Key::Backspace,
40 KeyCode::Delete => Key::Delete,
41 KeyCode::Home => Key::Home,
42 KeyCode::End => Key::End,
43 KeyCode::PageUp => Key::PageUp,
44 KeyCode::PageDown => Key::PageDown,
45
46 KeyCode::F(n) => Key::F(n),
47
48 _ => return Err(()),
49 })
50 }
51}
52use std::fmt;
53
54impl fmt::Display for Key {
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 match self {
57 Key::Char(c) => write!(f, "{}", c.to_ascii_lowercase()),
58 Key::ArrowUp => write!(f, "ArrowUp"),
59 Key::ArrowDown => write!(f, "ArrowDown"),
60 Key::ArrowLeft => write!(f, "ArrowLeft"),
61 Key::ArrowRight => write!(f, "ArrowRight"),
62 Key::F(n) => write!(f, "F{}", n),
63 Key::Enter => write!(f, "Enter"),
64 Key::Escape => write!(f, "Escape"),
65 Key::Tab => write!(f, "Tab"),
66 Key::BackTab => write!(f, "BackTab"),
67 Key::Backspace => write!(f, "Backspace"),
68 Key::Delete => write!(f, "Delete"),
69 Key::Home => write!(f, "Home"),
70 Key::End => write!(f, "End"),
71 Key::PageUp => write!(f, "PageUp"),
72 Key::PageDown => write!(f, "PageDown"),
73 }
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[test]
83 fn try_from_char() {
84 assert_eq!(Key::try_from(KeyCode::Char('a')), Ok(Key::Char('a')));
85 }
86
87 #[test]
88 fn try_from_up() {
89 assert_eq!(Key::try_from(KeyCode::Up), Ok(Key::ArrowUp));
90 }
91
92 #[test]
93 fn try_from_down() {
94 assert_eq!(Key::try_from(KeyCode::Down), Ok(Key::ArrowDown));
95 }
96
97 #[test]
98 fn try_from_left() {
99 assert_eq!(Key::try_from(KeyCode::Left), Ok(Key::ArrowLeft));
100 }
101
102 #[test]
103 fn try_from_right() {
104 assert_eq!(Key::try_from(KeyCode::Right), Ok(Key::ArrowRight));
105 }
106
107 #[test]
108 fn try_from_enter() {
109 assert_eq!(Key::try_from(KeyCode::Enter), Ok(Key::Enter));
110 }
111
112 #[test]
113 fn try_from_escape() {
114 assert_eq!(Key::try_from(KeyCode::Esc), Ok(Key::Escape));
115 }
116
117 #[test]
118 fn try_from_tab() {
119 assert_eq!(Key::try_from(KeyCode::Tab), Ok(Key::Tab));
120 }
121
122 #[test]
123 fn try_from_backtab() {
124 assert_eq!(Key::try_from(KeyCode::BackTab), Ok(Key::BackTab));
125 }
126
127 #[test]
128 fn try_from_backspace() {
129 assert_eq!(Key::try_from(KeyCode::Backspace), Ok(Key::Backspace));
130 }
131
132 #[test]
133 fn try_from_delete() {
134 assert_eq!(Key::try_from(KeyCode::Delete), Ok(Key::Delete));
135 }
136
137 #[test]
138 fn try_from_home() {
139 assert_eq!(Key::try_from(KeyCode::Home), Ok(Key::Home));
140 }
141
142 #[test]
143 fn try_from_end() {
144 assert_eq!(Key::try_from(KeyCode::End), Ok(Key::End));
145 }
146
147 #[test]
148 fn try_from_page_up() {
149 assert_eq!(Key::try_from(KeyCode::PageUp), Ok(Key::PageUp));
150 }
151
152 #[test]
153 fn try_from_page_down() {
154 assert_eq!(Key::try_from(KeyCode::PageDown), Ok(Key::PageDown));
155 }
156
157 #[test]
158 fn try_from_f_key() {
159 assert_eq!(Key::try_from(KeyCode::F(1)), Ok(Key::F(1)));
160 }
161
162 #[test]
163 fn try_from_f_key_12() {
164 assert_eq!(Key::try_from(KeyCode::F(12)), Ok(Key::F(12)));
165 }
166
167 #[test]
168 fn try_from_null_is_err() {
169 assert!(Key::try_from(KeyCode::Null).is_err());
170 }
171
172 #[test]
174 fn display_char_uppercase_lowercased() {
175 assert_eq!(Key::Char('A').to_string(), "a");
176 }
177
178 #[test]
179 fn display_char_already_lower() {
180 assert_eq!(Key::Char('z').to_string(), "z");
181 }
182
183 #[test]
184 fn display_char_digit() {
185 assert_eq!(Key::Char('5').to_string(), "5");
186 }
187
188 #[test]
189 fn display_arrow_up() {
190 assert_eq!(Key::ArrowUp.to_string(), "ArrowUp");
191 }
192
193 #[test]
194 fn display_arrow_down() {
195 assert_eq!(Key::ArrowDown.to_string(), "ArrowDown");
196 }
197
198 #[test]
199 fn display_arrow_left() {
200 assert_eq!(Key::ArrowLeft.to_string(), "ArrowLeft");
201 }
202
203 #[test]
204 fn display_arrow_right() {
205 assert_eq!(Key::ArrowRight.to_string(), "ArrowRight");
206 }
207
208 #[test]
209 fn display_enter() {
210 assert_eq!(Key::Enter.to_string(), "Enter");
211 }
212
213 #[test]
214 fn display_escape() {
215 assert_eq!(Key::Escape.to_string(), "Escape");
216 }
217
218 #[test]
219 fn display_tab() {
220 assert_eq!(Key::Tab.to_string(), "Tab");
221 }
222
223 #[test]
224 fn display_backtab() {
225 assert_eq!(Key::BackTab.to_string(), "BackTab");
226 }
227
228 #[test]
229 fn display_backspace() {
230 assert_eq!(Key::Backspace.to_string(), "Backspace");
231 }
232
233 #[test]
234 fn display_delete() {
235 assert_eq!(Key::Delete.to_string(), "Delete");
236 }
237
238 #[test]
239 fn display_home() {
240 assert_eq!(Key::Home.to_string(), "Home");
241 }
242
243 #[test]
244 fn display_end() {
245 assert_eq!(Key::End.to_string(), "End");
246 }
247
248 #[test]
249 fn display_page_up() {
250 assert_eq!(Key::PageUp.to_string(), "PageUp");
251 }
252
253 #[test]
254 fn display_page_down() {
255 assert_eq!(Key::PageDown.to_string(), "PageDown");
256 }
257
258 #[test]
259 fn display_f_key() {
260 assert_eq!(Key::F(12).to_string(), "F12");
261 }
262
263 #[test]
265 fn key_clone_eq() {
266 assert_eq!(Key::Enter.clone(), Key::Enter);
267 }
268
269 #[test]
270 fn key_ne() {
271 assert_ne!(Key::Enter, Key::Escape);
272 }
273
274 #[test]
275 fn key_hash() {
276 use std::collections::HashSet;
277 let mut s = HashSet::new();
278 s.insert(Key::Char('a'));
279 assert!(s.contains(&Key::Char('a')));
280 assert!(!s.contains(&Key::Char('b')));
281 }
282}