1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2#[non_exhaustive]
3pub enum Key {
4 Char(char),
5 Ctrl(char),
6 Alt(char),
7 Tab,
8 BackTab,
9 Enter,
10 Esc,
11 Backspace,
12 Left,
13 Right,
14 Up,
15 Down,
16 Home,
17 End,
18 PageUp,
19 PageDown,
20 Delete,
21 Other,
22}
23
24#[cfg(feature = "crossterm")]
25impl From<crossterm::event::KeyEvent> for Key {
26 fn from(event: crossterm::event::KeyEvent) -> Self {
27 use crossterm::event::{KeyCode, KeyEventKind, KeyModifiers};
28 if event.kind == KeyEventKind::Release {
29 return Key::Other;
30 }
31 let modifiers = event.modifiers;
32 let control = modifiers.contains(KeyModifiers::CONTROL);
33 let alt = modifiers.contains(KeyModifiers::ALT);
34 let other =
35 modifiers.intersects(KeyModifiers::SUPER | KeyModifiers::HYPER | KeyModifiers::META);
36 match event.code {
37 KeyCode::Char(_) if other => Key::Other,
38 KeyCode::Char(c) if control && alt => Key::Char(c),
39 KeyCode::Char(c) if control => Key::Ctrl(c.to_ascii_lowercase()),
40 KeyCode::Char(c) if alt => Key::Alt(c),
41 KeyCode::Char(c) => Key::Char(c),
42 _ if other || alt => Key::Other,
43 KeyCode::Tab if event.modifiers.contains(KeyModifiers::SHIFT) => Key::BackTab,
44 KeyCode::Tab => Key::Tab,
45 KeyCode::BackTab => Key::BackTab,
46 KeyCode::Enter => Key::Enter,
47 KeyCode::Esc => Key::Esc,
48 KeyCode::Backspace => Key::Backspace,
49 KeyCode::Left => Key::Left,
50 KeyCode::Right => Key::Right,
51 KeyCode::Up => Key::Up,
52 KeyCode::Down => Key::Down,
53 KeyCode::Home => Key::Home,
54 KeyCode::End => Key::End,
55 KeyCode::PageUp => Key::PageUp,
56 KeyCode::PageDown => Key::PageDown,
57 KeyCode::Delete => Key::Delete,
58 _ => Key::Other,
59 }
60 }
61}