1use winit::event::{ElementState, MouseButton as WinitMouseButton, MouseScrollDelta, WindowEvent};
21use winit::keyboard::{KeyCode, PhysicalKey};
22
23#[derive(Debug, Clone, PartialEq)]
28pub enum InputEvent {
29 KeyPressed {
31 key_code: String,
33 },
34 KeyReleased {
36 key_code: String,
38 },
39 MouseButtonPressed {
41 button: MouseButton,
43 },
44 MouseButtonReleased {
46 button: MouseButton,
48 },
49 MouseMoved {
51 x: f32,
53 y: f32,
55 },
56 MouseWheelScrolled {
58 delta_x: f32,
60 delta_y: f32,
62 },
63}
64
65#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
67pub enum MouseButton {
68 Left,
70 Right,
72 Middle,
74 Back,
76 Forward,
78 Other(u16),
80}
81
82pub fn translate_winit_input(event: &WindowEvent) -> Option<InputEvent> {
96 match event {
97 WindowEvent::KeyboardInput {
98 event: key_event, ..
99 } => {
100 if let PhysicalKey::Code(keycode) = key_event.physical_key {
101 let key_code_str = map_keycode_to_string(keycode);
102 match key_event.state {
103 ElementState::Pressed if !key_event.repeat => Some(InputEvent::KeyPressed {
104 key_code: key_code_str,
105 }),
106 ElementState::Released => Some(InputEvent::KeyReleased {
107 key_code: key_code_str,
108 }),
109 _ => None,
110 }
111 } else {
112 None
113 }
114 }
115 WindowEvent::CursorMoved { position, .. } => Some(InputEvent::MouseMoved {
116 x: position.x as f32,
117 y: position.y as f32,
118 }),
119 WindowEvent::MouseInput { state, button, .. } => {
120 let khora_button = map_mouse_button(*button);
121 match state {
122 ElementState::Pressed => Some(InputEvent::MouseButtonPressed {
123 button: khora_button,
124 }),
125 ElementState::Released => Some(InputEvent::MouseButtonReleased {
126 button: khora_button,
127 }),
128 }
129 }
130 WindowEvent::MouseWheel { delta, .. } => {
131 let (dx, dy): (f32, f32) = match delta {
132 MouseScrollDelta::LineDelta(x, y) => (*x, *y),
133 MouseScrollDelta::PixelDelta(pos) => (pos.x as f32, pos.y as f32),
134 };
135 if dx != 0.0 || dy != 0.0 {
136 Some(InputEvent::MouseWheelScrolled {
137 delta_x: dx,
138 delta_y: dy,
139 })
140 } else {
141 None
142 }
143 }
144 _ => None,
145 }
146}
147
148fn map_keycode_to_string(keycode: KeyCode) -> String {
152 format!("{keycode:?}")
153}
154
155fn map_mouse_button(button: WinitMouseButton) -> MouseButton {
157 match button {
158 WinitMouseButton::Left => MouseButton::Left,
159 WinitMouseButton::Right => MouseButton::Right,
160 WinitMouseButton::Middle => MouseButton::Middle,
161 WinitMouseButton::Back => MouseButton::Back,
162 WinitMouseButton::Forward => MouseButton::Forward,
163 WinitMouseButton::Other(id) => MouseButton::Other(id),
164 }
165}
166
167#[cfg(test)]
169mod tests {
170 use super::*;
171 use winit::{dpi::PhysicalPosition, event::WindowEvent, keyboard::KeyCode};
172
173 #[test]
175 fn test_map_keycode_simple() {
176 assert_eq!(map_keycode_to_string(KeyCode::KeyA), "KeyA");
177 assert_eq!(map_keycode_to_string(KeyCode::Digit1), "Digit1");
178 assert_eq!(map_keycode_to_string(KeyCode::Space), "Space");
179 }
180
181 #[test]
183 fn test_map_mouse_button_standard() {
184 assert_eq!(map_mouse_button(WinitMouseButton::Left), MouseButton::Left);
185 assert_eq!(
186 map_mouse_button(WinitMouseButton::Right),
187 MouseButton::Right
188 );
189 assert_eq!(
190 map_mouse_button(WinitMouseButton::Middle),
191 MouseButton::Middle
192 );
193 assert_eq!(map_mouse_button(WinitMouseButton::Back), MouseButton::Back);
194 assert_eq!(
195 map_mouse_button(WinitMouseButton::Forward),
196 MouseButton::Forward
197 );
198 }
199
200 #[test]
202 fn test_map_mouse_button_other() {
203 assert_eq!(
204 map_mouse_button(WinitMouseButton::Other(8)),
205 MouseButton::Other(8)
206 );
207 assert_eq!(
208 map_mouse_button(WinitMouseButton::Other(15)),
209 MouseButton::Other(15)
210 );
211 }
212
213 #[test]
215 fn test_translate_mouse_button_pressed() {
216 let winit_event = WindowEvent::MouseInput {
217 device_id: winit::event::DeviceId::dummy(),
218 state: ElementState::Pressed,
219 button: WinitMouseButton::Left,
220 };
221 let expected = Some(InputEvent::MouseButtonPressed {
222 button: MouseButton::Left,
223 });
224 assert_eq!(translate_winit_input(&winit_event), expected);
225 }
226
227 #[test]
229 fn test_translate_mouse_button_released() {
230 let winit_event = WindowEvent::MouseInput {
231 device_id: winit::event::DeviceId::dummy(),
232 state: ElementState::Released,
233 button: WinitMouseButton::Right,
234 };
235 let expected = Some(InputEvent::MouseButtonReleased {
236 button: MouseButton::Right,
237 });
238 assert_eq!(translate_winit_input(&winit_event), expected);
239 }
240
241 #[test]
243 fn test_translate_cursor_moved() {
244 let winit_event = WindowEvent::CursorMoved {
245 device_id: winit::event::DeviceId::dummy(),
246 position: PhysicalPosition::new(100.5, 200.75),
247 };
248 let expected = Some(InputEvent::MouseMoved {
249 x: 100.5,
250 y: 200.75,
251 });
252 assert_eq!(translate_winit_input(&winit_event), expected);
253 }
254
255 #[test]
257 fn test_translate_mouse_wheel_line() {
258 let winit_event = WindowEvent::MouseWheel {
259 device_id: winit::event::DeviceId::dummy(),
260 delta: MouseScrollDelta::LineDelta(-1.0, 2.0),
261 phase: winit::event::TouchPhase::Moved,
262 };
263 let expected = Some(InputEvent::MouseWheelScrolled {
264 delta_x: -1.0,
265 delta_y: 2.0,
266 });
267 assert_eq!(translate_winit_input(&winit_event), expected);
268 }
269
270 #[test]
272 fn test_translate_mouse_wheel_pixel() {
273 let winit_event = WindowEvent::MouseWheel {
274 device_id: winit::event::DeviceId::dummy(),
275 delta: MouseScrollDelta::PixelDelta(PhysicalPosition::new(5.5, -10.0)),
276 phase: winit::event::TouchPhase::Moved,
277 };
278 let expected = Some(InputEvent::MouseWheelScrolled {
279 delta_x: 5.5,
280 delta_y: -10.0,
281 });
282 assert_eq!(translate_winit_input(&winit_event), expected);
283 }
284
285 #[test]
287 fn test_translate_non_input_returns_none() {
288 let winit_event_resize = WindowEvent::Resized(winit::dpi::PhysicalSize::new(100, 100));
289 let winit_event_focus = WindowEvent::Focused(true);
290 let winit_event_close = WindowEvent::CloseRequested;
291 assert_eq!(translate_winit_input(&winit_event_resize), None);
292 assert_eq!(translate_winit_input(&winit_event_focus), None);
293 assert_eq!(translate_winit_input(&winit_event_close), None);
294 }
295}