1use super::{Input, Key};
2use ratatui_crossterm::crossterm::event::{
3 Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers, MouseEvent, MouseEventKind,
4};
5
6impl From<Event> for Input {
7 fn from(event: Event) -> Self {
9 match event {
10 Event::Key(key) => Self::from(key),
11 Event::Mouse(mouse) => Self::from(mouse),
12 _ => Self::default(),
13 }
14 }
15}
16
17impl From<KeyCode> for Key {
18 fn from(code: KeyCode) -> Self {
20 match code {
21 KeyCode::Char(c) => Key::Char(c),
22 KeyCode::Backspace => Key::Backspace,
23 KeyCode::Enter => Key::Enter,
24 KeyCode::Left => Key::Left,
25 KeyCode::Right => Key::Right,
26 KeyCode::Up => Key::Up,
27 KeyCode::Down => Key::Down,
28 KeyCode::Tab => Key::Tab,
29 KeyCode::Delete => Key::Delete,
30 KeyCode::Home => Key::Home,
31 KeyCode::End => Key::End,
32 KeyCode::PageUp => Key::PageUp,
33 KeyCode::PageDown => Key::PageDown,
34 KeyCode::Esc => Key::Esc,
35 KeyCode::F(x) => Key::F(x),
36 _ => Key::Null,
37 }
38 }
39}
40
41impl From<KeyEvent> for Input {
42 fn from(key: KeyEvent) -> Self {
44 if key.kind == KeyEventKind::Release {
45 return Self::default();
48 }
49 let ctrl = key.modifiers.contains(KeyModifiers::CONTROL);
50 let alt = key.modifiers.contains(KeyModifiers::ALT);
51
52 if key.code == KeyCode::BackTab {
53 return Self {
55 key: Key::Tab,
56 shift: true,
57 ctrl,
58 alt,
59 };
60 }
61
62 let shift = key.modifiers.contains(KeyModifiers::SHIFT);
63 let key = Key::from(key.code);
64
65 Self {
66 key,
67 ctrl,
68 alt,
69 shift,
70 }
71 }
72}
73
74impl From<MouseEventKind> for Key {
75 fn from(kind: MouseEventKind) -> Self {
77 match kind {
78 MouseEventKind::ScrollDown => Key::MouseScrollDown,
79 MouseEventKind::ScrollUp => Key::MouseScrollUp,
80 _ => Key::Null,
81 }
82 }
83}
84
85impl From<MouseEvent> for Input {
86 fn from(mouse: MouseEvent) -> Self {
88 let key = Key::from(mouse.kind);
89 let ctrl = mouse.modifiers.contains(KeyModifiers::CONTROL);
90 let alt = mouse.modifiers.contains(KeyModifiers::ALT);
91 let shift = mouse.modifiers.contains(KeyModifiers::SHIFT);
92 Self {
93 key,
94 ctrl,
95 alt,
96 shift,
97 }
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104 use crate::input::tests::input;
105 use ratatui_crossterm::crossterm::event::KeyEventState;
106
107 fn key_event(code: KeyCode, modifiers: KeyModifiers) -> KeyEvent {
108 KeyEvent {
109 code,
110 modifiers,
111 kind: KeyEventKind::Press,
112 state: KeyEventState::empty(),
113 }
114 }
115
116 fn mouse_event(kind: MouseEventKind, modifiers: KeyModifiers) -> MouseEvent {
117 MouseEvent {
118 kind,
119 column: 1,
120 row: 1,
121 modifiers,
122 }
123 }
124
125 #[test]
126 fn key_to_input() {
127 for (from, to) in [
128 (
129 key_event(KeyCode::Char('a'), KeyModifiers::empty()),
130 input(Key::Char('a'), false, false, false),
131 ),
132 (
133 key_event(KeyCode::Enter, KeyModifiers::empty()),
134 input(Key::Enter, false, false, false),
135 ),
136 (
137 key_event(KeyCode::Left, KeyModifiers::CONTROL),
138 input(Key::Left, true, false, false),
139 ),
140 (
141 key_event(KeyCode::Right, KeyModifiers::SHIFT),
142 input(Key::Right, false, false, true),
143 ),
144 (
145 key_event(KeyCode::Home, KeyModifiers::ALT),
146 input(Key::Home, false, true, false),
147 ),
148 (
149 key_event(
150 KeyCode::F(1),
151 KeyModifiers::ALT | KeyModifiers::CONTROL | KeyModifiers::SHIFT,
152 ),
153 input(Key::F(1), true, true, true),
154 ),
155 (
156 key_event(KeyCode::NumLock, KeyModifiers::CONTROL),
157 input(Key::Null, true, false, false),
158 ),
159 ] {
160 assert_eq!(Input::from(from), to, "{:?} -> {:?}", from, to);
161 }
162 }
163
164 #[test]
165 fn mouse_to_input() {
166 for (from, to) in [
167 (
168 mouse_event(MouseEventKind::ScrollDown, KeyModifiers::empty()),
169 input(Key::MouseScrollDown, false, false, false),
170 ),
171 (
172 mouse_event(MouseEventKind::ScrollUp, KeyModifiers::CONTROL),
173 input(Key::MouseScrollUp, true, false, false),
174 ),
175 (
176 mouse_event(MouseEventKind::ScrollUp, KeyModifiers::SHIFT),
177 input(Key::MouseScrollUp, false, false, true),
178 ),
179 (
180 mouse_event(MouseEventKind::ScrollDown, KeyModifiers::ALT),
181 input(Key::MouseScrollDown, false, true, false),
182 ),
183 (
184 mouse_event(
185 MouseEventKind::ScrollUp,
186 KeyModifiers::CONTROL | KeyModifiers::ALT,
187 ),
188 input(Key::MouseScrollUp, true, true, false),
189 ),
190 (
191 mouse_event(MouseEventKind::Moved, KeyModifiers::CONTROL),
192 input(Key::Null, true, false, false),
193 ),
194 ] {
195 assert_eq!(Input::from(from), to, "{:?} -> {:?}", from, to);
196 }
197 }
198
199 #[test]
200 fn event_to_input() {
201 for (from, to) in [
202 (
203 Event::Key(key_event(KeyCode::Char('a'), KeyModifiers::empty())),
204 input(Key::Char('a'), false, false, false),
205 ),
206 (
207 Event::Mouse(mouse_event(
208 MouseEventKind::ScrollDown,
209 KeyModifiers::empty(),
210 )),
211 input(Key::MouseScrollDown, false, false, false),
212 ),
213 (Event::FocusGained, input(Key::Null, false, false, false)),
214 ] {
215 assert_eq!(Input::from(from.clone()), to, "{:?} -> {:?}", from, to);
216 }
217 }
218
219 #[test]
221 fn ignore_key_release_event() {
222 let mut from = key_event(KeyCode::Char('a'), KeyModifiers::empty());
223 from.kind = KeyEventKind::Release;
224 let to = input(Key::Null, false, false, false);
225 assert_eq!(Input::from(from), to, "{:?} -> {:?}", from, to);
226 }
227}