Skip to main content

tui_pages/input/
key_chord.rs

1use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
4#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
5pub struct KeyChord {
6    pub code: KeyCode,
7    pub modifiers: KeyModifiers,
8}
9
10impl KeyChord {
11    pub fn new(code: KeyCode, modifiers: KeyModifiers) -> Self {
12        Self { code, modifiers }
13    }
14
15    pub fn from_event(event: &KeyEvent) -> Self {
16        let mut modifiers = event.modifiers;
17        // SHIFT is encoded in the character itself (':' vs ';', 'A' vs 'a'),
18        // so a binding like `":"` should match an event of `Char(':') + SHIFT`.
19        // We keep SHIFT only when combined with another modifier (e.g. Ctrl+Shift+S).
20        if matches!(event.code, KeyCode::Char(_)) && modifiers == KeyModifiers::SHIFT {
21            modifiers = KeyModifiers::empty();
22        }
23        if event.code == KeyCode::BackTab {
24            modifiers -= KeyModifiers::SHIFT;
25        }
26        Self {
27            code: event.code,
28            modifiers,
29        }
30    }
31
32    pub fn display_string(&self) -> String {
33        let mut out = String::new();
34        if self.modifiers.contains(KeyModifiers::CONTROL) {
35            out.push_str("Ctrl+");
36        }
37        if self.modifiers.contains(KeyModifiers::ALT) {
38            out.push_str("Alt+");
39        }
40        if self.modifiers.contains(KeyModifiers::SHIFT) {
41            out.push_str("Shift+");
42        }
43
44        match self.code {
45            KeyCode::Char(c) => out.push(c),
46            KeyCode::Enter => out.push_str("Enter"),
47            KeyCode::Tab => out.push_str("Tab"),
48            KeyCode::BackTab => out.push_str("BackTab"),
49            KeyCode::Backspace => out.push_str("Backspace"),
50            KeyCode::Esc => out.push_str("Esc"),
51            KeyCode::Up => out.push_str("Up"),
52            KeyCode::Down => out.push_str("Down"),
53            KeyCode::Left => out.push_str("Left"),
54            KeyCode::Right => out.push_str("Right"),
55            other => out.push_str(&format!("{other:?}")),
56        }
57
58        out
59    }
60}