tui_textarea/input/
termion.rs

1use super::{Input, Key};
2use crate::termion::event::{Event, Key as KeyEvent, MouseButton, MouseEvent};
3
4impl From<Event> for Input {
5    /// Convert [`termion::event::Event`] into [`Input`].
6    fn from(event: Event) -> Self {
7        match event {
8            Event::Key(key) => Self::from(key),
9            Event::Mouse(mouse) => Self::from(mouse),
10            _ => Self::default(),
11        }
12    }
13}
14
15impl From<KeyEvent> for Input {
16    /// Convert [`termion::event::Key`] into [`Input`].
17    ///
18    /// termion does not provide a way to get Shift key's state. Instead termion passes key inputs as-is. For example,
19    /// when 'Shift + A' is pressed with US keyboard, termion passes `termion::event::Key::Char('A')`. We cannot know
20    /// how the 'A' character was input.
21    ///
22    /// So the `shift` field of the returned `Input` instance is always `false` except for combinations with arrow keys.
23    /// For example, `termion::event::Key::Char('A')` is converted to `Input { key: Key::Char('A'), shift: false, .. }`.
24    fn from(key: KeyEvent) -> Self {
25        #[cfg(feature = "termion")]
26        let (ctrl, alt, shift) = match key {
27            KeyEvent::Ctrl(_)
28            | KeyEvent::CtrlUp
29            | KeyEvent::CtrlRight
30            | KeyEvent::CtrlDown
31            | KeyEvent::CtrlLeft
32            | KeyEvent::CtrlHome
33            | KeyEvent::CtrlEnd => (true, false, false),
34            KeyEvent::Alt(_)
35            | KeyEvent::AltUp
36            | KeyEvent::AltRight
37            | KeyEvent::AltDown
38            | KeyEvent::AltLeft => (false, true, false),
39            KeyEvent::ShiftUp
40            | KeyEvent::ShiftRight
41            | KeyEvent::ShiftDown
42            | KeyEvent::ShiftLeft => (false, false, true),
43            _ => (false, false, false),
44        };
45
46        #[cfg(feature = "tuirs-termion")]
47        let (ctrl, alt, shift) = match key {
48            KeyEvent::Ctrl(_) => (true, false, false),
49            KeyEvent::Alt(_) => (false, true, false),
50            _ => (false, false, false),
51        };
52
53        #[cfg(feature = "termion")]
54        let key = match key {
55            KeyEvent::Char('\n' | '\r') => Key::Enter,
56            KeyEvent::Char(c) | KeyEvent::Ctrl(c) | KeyEvent::Alt(c) => Key::Char(c),
57            KeyEvent::Backspace => Key::Backspace,
58            KeyEvent::Left | KeyEvent::CtrlLeft | KeyEvent::AltLeft | KeyEvent::ShiftLeft => {
59                Key::Left
60            }
61            KeyEvent::Right | KeyEvent::CtrlRight | KeyEvent::AltRight | KeyEvent::ShiftRight => {
62                Key::Right
63            }
64            KeyEvent::Up | KeyEvent::CtrlUp | KeyEvent::AltUp | KeyEvent::ShiftUp => Key::Up,
65            KeyEvent::Down | KeyEvent::CtrlDown | KeyEvent::AltDown | KeyEvent::ShiftDown => {
66                Key::Down
67            }
68            KeyEvent::Home | KeyEvent::CtrlHome => Key::Home,
69            KeyEvent::End | KeyEvent::CtrlEnd => Key::End,
70            KeyEvent::PageUp => Key::PageUp,
71            KeyEvent::PageDown => Key::PageDown,
72            KeyEvent::BackTab => Key::Tab,
73            KeyEvent::Delete => Key::Delete,
74            KeyEvent::Esc => Key::Esc,
75            KeyEvent::F(x) => Key::F(x),
76            _ => Key::Null,
77        };
78
79        #[cfg(feature = "tuirs-termion")]
80        let key = match key {
81            KeyEvent::Char('\n' | '\r') => Key::Enter,
82            KeyEvent::Char(c) | KeyEvent::Ctrl(c) | KeyEvent::Alt(c) => Key::Char(c),
83            KeyEvent::Backspace => Key::Backspace,
84            KeyEvent::Left => Key::Left,
85            KeyEvent::Right => Key::Right,
86            KeyEvent::Up => Key::Up,
87            KeyEvent::Down => Key::Down,
88            KeyEvent::Home => Key::Home,
89            KeyEvent::End => Key::End,
90            KeyEvent::PageUp => Key::PageUp,
91            KeyEvent::PageDown => Key::PageDown,
92            KeyEvent::BackTab => Key::Tab,
93            KeyEvent::Delete => Key::Delete,
94            KeyEvent::Esc => Key::Esc,
95            KeyEvent::F(x) => Key::F(x),
96            _ => Key::Null,
97        };
98
99        Input {
100            key,
101            ctrl,
102            alt,
103            shift,
104        }
105    }
106}
107
108impl From<MouseButton> for Key {
109    /// Convert [`termion::event::MouseButton`] into [`Key`].
110    fn from(button: MouseButton) -> Self {
111        match button {
112            MouseButton::WheelUp => Key::MouseScrollUp,
113            MouseButton::WheelDown => Key::MouseScrollDown,
114            _ => Key::Null,
115        }
116    }
117}
118
119impl From<MouseEvent> for Input {
120    /// Convert [`termion::event::MouseEvent`] into [`Input`].
121    fn from(mouse: MouseEvent) -> Self {
122        let key = if let MouseEvent::Press(button, ..) = mouse {
123            Key::from(button)
124        } else {
125            Key::Null
126        };
127        Self {
128            key,
129            ctrl: false,
130            alt: false,
131            shift: false,
132        }
133    }
134}
135
136#[cfg(test)]
137mod tests {
138    use super::*;
139    use crate::input::tests::input;
140
141    #[test]
142    fn key_to_input() {
143        for (from, to) in [
144            (
145                KeyEvent::Char('a'),
146                input(Key::Char('a'), false, false, false),
147            ),
148            (
149                KeyEvent::Ctrl('a'),
150                input(Key::Char('a'), true, false, false),
151            ),
152            (
153                KeyEvent::Alt('a'),
154                input(Key::Char('a'), false, true, false),
155            ),
156            (KeyEvent::Char('\n'), input(Key::Enter, false, false, false)),
157            (KeyEvent::Char('\r'), input(Key::Enter, false, false, false)),
158            (KeyEvent::F(1), input(Key::F(1), false, false, false)),
159            (KeyEvent::BackTab, input(Key::Tab, false, false, false)),
160            (KeyEvent::Null, input(Key::Null, false, false, false)),
161            #[cfg(feature = "termion")]
162            (KeyEvent::ShiftDown, input(Key::Down, false, false, true)),
163            #[cfg(feature = "termion")]
164            (KeyEvent::AltUp, input(Key::Up, false, true, false)),
165            #[cfg(feature = "termion")]
166            (KeyEvent::CtrlLeft, input(Key::Left, true, false, false)),
167            #[cfg(feature = "termion")]
168            (KeyEvent::CtrlHome, input(Key::Home, true, false, false)),
169        ] {
170            assert_eq!(Input::from(from), to, "{:?} -> {:?}", from, to);
171        }
172    }
173
174    #[test]
175    fn mouse_to_input() {
176        for (from, to) in [
177            (
178                MouseEvent::Press(MouseButton::WheelDown, 1, 1),
179                input(Key::MouseScrollDown, false, false, false),
180            ),
181            (
182                MouseEvent::Press(MouseButton::WheelUp, 1, 1),
183                input(Key::MouseScrollUp, false, false, false),
184            ),
185            (
186                MouseEvent::Press(MouseButton::Left, 1, 1),
187                input(Key::Null, false, false, false),
188            ),
189            (
190                MouseEvent::Release(1, 1),
191                input(Key::Null, false, false, false),
192            ),
193            (
194                MouseEvent::Hold(1, 1),
195                input(Key::Null, false, false, false),
196            ),
197        ] {
198            assert_eq!(Input::from(from), to, "{:?} -> {:?}", from, to);
199        }
200    }
201
202    #[test]
203    fn event_to_input() {
204        for (from, to) in [
205            (
206                Event::Key(KeyEvent::Char('a')),
207                input(Key::Char('a'), false, false, false),
208            ),
209            (
210                Event::Mouse(MouseEvent::Press(MouseButton::WheelDown, 1, 1)),
211                input(Key::MouseScrollDown, false, false, false),
212            ),
213            (
214                Event::Unsupported(vec![]),
215                input(Key::Null, false, false, false),
216            ),
217        ] {
218            assert_eq!(Input::from(from.clone()), to, "{:?} -> {:?}", from, to);
219        }
220    }
221}