ad_editor/
key.rs

1//! Keypresses and related user interactions.
2use tracing::trace;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
5pub enum Arrow {
6    Up,
7    Down,
8    Left,
9    Right,
10}
11
12impl Arrow {
13    pub fn flip(&self) -> Self {
14        match self {
15            Self::Up => Self::Down,
16            Self::Down => Self::Up,
17            Self::Left => Self::Right,
18            Self::Right => Self::Left,
19        }
20    }
21}
22
23// using 'showkey -a' to view keycodes is useful for adding to this
24#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
25pub enum Input {
26    Char(char),
27    Ctrl(char),
28    Alt(char),
29    CtrlAlt(char),
30    Tab,
31    BackTab,
32    AltReturn,
33    Return,
34    Backspace,
35    Arrow(Arrow),
36    Del,
37    Home,
38    End,
39    PageUp,
40    PageDown,
41    Esc,
42    Mouse(MouseEvent),
43}
44
45impl Input {
46    pub fn from_char(c: char) -> Self {
47        match c {
48            '\x1b' => Input::Esc,
49            '\n' | '\r' => Input::Return,
50            '\x7f' => Input::Backspace,
51            '\t' => Input::Tab,
52            c @ '\x01'..='\x1A' => Input::Ctrl((c as u8 - 0x1 + b'a') as char),
53            c @ '\x1C'..='\x1F' => Input::Ctrl((c as u8 - 0x1C + b'4') as char),
54            _ => Input::Char(c),
55        }
56    }
57
58    pub fn try_from_seq2(c1: char, c2: char) -> Option<Self> {
59        match (c1, c2) {
60            ('O', 'H') => Some(Input::Home),
61            ('O', 'F') => Some(Input::End),
62
63            ('[', 'A') => Some(Input::Arrow(Arrow::Up)),
64            ('[', 'B') => Some(Input::Arrow(Arrow::Down)),
65            ('[', 'C') => Some(Input::Arrow(Arrow::Right)),
66            ('[', 'D') => Some(Input::Arrow(Arrow::Left)),
67            ('[', 'H') => Some(Input::Home),
68            ('[', 'Z') => Some(Input::BackTab),
69            ('\x1b', c) if c.is_ascii() => match Self::from_char(c) {
70                Input::Char(c) => Some(Input::Alt(c)),
71                Input::Ctrl(c) => Some(Input::CtrlAlt(c)),
72                Input::Return => Some(Input::AltReturn),
73                _ => None,
74            },
75            _ => None,
76        }
77    }
78
79    pub fn try_from_bracket_tilde(c: char) -> Option<Self> {
80        match c {
81            '1' | '7' => Some(Input::Home),
82            '4' | '8' => Some(Input::End),
83            '3' => Some(Input::Del),
84            '5' => Some(Input::PageUp),
85            '6' => Some(Input::PageDown),
86            _ => None,
87        }
88    }
89}
90
91#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
92pub enum MouseButton {
93    Left,
94    Middle,
95    Right,
96    WheelUp,
97    WheelDown,
98}
99
100#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
101pub enum MouseMod {
102    NoMod,
103    Alt,
104    Ctrl,
105    AltCtrl,
106}
107
108#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
109pub enum MouseEventKind {
110    Press,
111    Hold,
112    Release,
113}
114
115#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
116pub struct MouseEvent {
117    pub k: MouseEventKind,
118    pub m: MouseMod,
119    pub b: MouseButton,
120    pub x: usize,
121    pub y: usize,
122}
123
124impl MouseEvent {
125    pub(crate) fn try_from_raw(b: usize, x: usize, y: usize, c: char) -> Option<Self> {
126        use MouseButton::*;
127        use MouseEventKind::*;
128        use MouseMod::*;
129
130        let (k, m, b) = match (b, c) {
131            // No modifiers
132            (0, 'M') => (Press, NoMod, Left),
133            (1, 'M') => (Press, NoMod, Middle),
134            (2, 'M') => (Press, NoMod, Right),
135            (64, 'M') => (Press, NoMod, WheelUp),
136            (65, 'M') => (Press, NoMod, WheelDown),
137
138            (0, 'm') | (3, _) => (Release, NoMod, Left),
139            (1, 'm') => (Release, NoMod, Middle),
140            (2, 'm') => (Release, NoMod, Right),
141            (64, 'm') => (Release, NoMod, WheelUp),
142            (65, 'm') => (Release, NoMod, WheelDown),
143
144            (32, _) => (Hold, NoMod, Left),
145            (33, _) => (Hold, NoMod, Middle),
146            (34, _) => (Hold, NoMod, Right),
147
148            // Alt modifier
149            (8, 'M') => (Press, Alt, Left),
150            (9, 'M') => (Press, Alt, Middle),
151            (10, 'M') => (Press, Alt, Right),
152            (72, 'M') => (Press, Alt, WheelUp),
153            (73, 'M') => (Press, Alt, WheelDown),
154
155            (8, 'm') => (Release, Alt, Left),
156            (9, 'm') => (Release, Alt, Middle),
157            (10, 'm') => (Release, Alt, Right),
158            (72, 'm') => (Release, Alt, WheelUp),
159            (73, 'm') => (Release, Alt, WheelDown),
160
161            (40, _) => (Hold, Alt, Left),
162            (41, _) => (Hold, Alt, Middle),
163            (42, _) => (Hold, Alt, Right),
164
165            // Ctrl modifier
166            (16, 'M') => (Press, Ctrl, Left),
167            (17, 'M') => (Press, Ctrl, Middle),
168            (18, 'M') => (Press, Ctrl, Right),
169            (80, 'M') => (Press, Ctrl, WheelUp),
170            (81, 'M') => (Press, Ctrl, WheelDown),
171
172            (16, 'm') => (Release, Ctrl, Left),
173            (17, 'm') => (Release, Ctrl, Middle),
174            (18, 'm') => (Release, Ctrl, Right),
175            (80, 'm') => (Release, Ctrl, WheelUp),
176            (81, 'm') => (Release, Ctrl, WheelDown),
177
178            (48, _) => (Hold, Ctrl, Left),
179            (49, _) => (Hold, Ctrl, Middle),
180            (50, _) => (Hold, Ctrl, Right),
181
182            // Alt+Ctrl modifiers
183            (24, 'M') => (Press, AltCtrl, Left),
184            (25, 'M') => (Press, AltCtrl, Middle),
185            (26, 'M') => (Press, AltCtrl, Right),
186            (88, 'M') => (Press, AltCtrl, WheelUp),
187            (89, 'M') => (Press, AltCtrl, WheelDown),
188
189            (24, 'm') => (Release, AltCtrl, Left),
190            (25, 'm') => (Release, AltCtrl, Middle),
191            (26, 'm') => (Release, AltCtrl, Right),
192            (88, 'm') => (Release, AltCtrl, WheelUp),
193            (89, 'm') => (Release, AltCtrl, WheelDown),
194
195            (56, _) => (Hold, AltCtrl, Left),
196            (57, _) => (Hold, AltCtrl, Middle),
197            (58, _) => (Hold, AltCtrl, Right),
198
199            _ => {
200                trace!("unmapped mouse input: b=b m=m");
201                return None;
202            }
203        };
204
205        Some(MouseEvent { k, m, b, x, y })
206    }
207}