use cgmath::Vector2; use winit::event::{ElementState, KeyEvent, MouseScrollDelta, Modifiers, WindowEvent}; use winit::keyboard::{Key as WinitKey, ModifiersKeyState}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Key { // Symbols Comma, Period, Minus, Plus, Slash, Backslash, Semicolon, Apostrophe, LeftBracket, RightBracket, Grave, Equal, // Digits Num0, Num1, Num2, Num3, Num4, Num5, Num6, Num7, Num8, Num9, // Letters A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, // Arrows ArrowUp, ArrowDown, ArrowLeft, ArrowRight, // Controls Escape, Enter, Space, Tab, Backspace, Insert, Delete, Home, End, PageUp, PageDown, // Modifier keys Shift, Control, Alt, Super, // Function keys F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, // Numpad Numpad0, Numpad1, Numpad2, Numpad3, Numpad4, Numpad5, Numpad6, Numpad7, Numpad8, Numpad9, NumpadAdd, NumpadSubtract, NumpadMultiply, NumpadDivide, NumpadEnter, Unknown, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct KeyModifiers { pub lshift: bool, pub rshift: bool, pub lcontrol: bool, pub rcontrol: bool, pub lalt: bool, pub ralt: bool, pub rsuper_key: bool, pub lsuper_key: bool, } #[derive(Debug, Clone, Copy, PartialEq)] pub enum MouseButton { Left, Right, Middle, Other(u16), } #[derive(Debug, Clone)] pub enum InputEvent { KeyPressed { key: Key, modifiers: KeyModifiers, text: String, }, KeyReleased { key: Key, modifiers: KeyModifiers, }, MouseMoved { position: (f64, f64), }, MouseDragged { delta: Vector2, button: MouseButton, }, MouseWheel { delta: f32, }, } #[derive(Default)] pub struct InputTracker { pub last_cursor_pos: Option<(f64, f64)>, pub dragging_button: Option, } impl InputTracker { pub fn handle_window_event(&mut self, event: &WindowEvent, modifiers: Modifiers) -> Option { match event { WindowEvent::KeyboardInput { event, .. } => { Some(handle_keyboard_input(event, modifiers)) } WindowEvent::CursorMoved { position, .. } => { if let (Some(last), Some(button)) = (self.last_cursor_pos, self.dragging_button) { let delta = Vector2::new(position.x - last.0, position.y - last.1); self.last_cursor_pos = Some((position.x, position.y)); Some(InputEvent::MouseDragged { delta, button }) } else { self.last_cursor_pos = Some((position.x, position.y)); Some(InputEvent::MouseMoved { position: (position.x, position.y), }) } } WindowEvent::MouseInput { state, button, .. } => { let mapped = map_button(*button); match state { ElementState::Pressed => { self.dragging_button = Some(mapped); } ElementState::Released => { self.dragging_button = None; } } None } WindowEvent::MouseWheel { delta, .. } => { let scroll = match delta { MouseScrollDelta::LineDelta(_, y) => *y, MouseScrollDelta::PixelDelta(p) => p.y as f32, }; Some(InputEvent::MouseWheel { delta: scroll }) } _ => None, } } } fn handle_keyboard_input(event: &KeyEvent, modifiers: Modifiers) -> InputEvent { let key = map_winit_key(&event.logical_key); let mods = KeyModifiers { lshift: modifiers.lshift_state() == ModifiersKeyState::Pressed, rshift: modifiers.rshift_state() == ModifiersKeyState::Pressed, lcontrol: modifiers.lcontrol_state() == ModifiersKeyState::Pressed, rcontrol: modifiers.rcontrol_state() == ModifiersKeyState::Pressed, lalt: modifiers.lalt_state() == ModifiersKeyState::Pressed, ralt: modifiers.ralt_state() == ModifiersKeyState::Pressed, rsuper_key: modifiers.rsuper_state() == ModifiersKeyState::Pressed, lsuper_key: modifiers.lsuper_state() == ModifiersKeyState::Pressed, }; match event.state { ElementState::Pressed => InputEvent::KeyPressed { key, modifiers: mods, text: event.text.clone().unwrap_or_default().into(), }, ElementState::Released => InputEvent::KeyReleased { key, modifiers: mods, }, } } pub fn map_button(button: winit::event::MouseButton) -> MouseButton { match button { winit::event::MouseButton::Left => MouseButton::Left, winit::event::MouseButton::Right => MouseButton::Right, winit::event::MouseButton::Middle => MouseButton::Middle, winit::event::MouseButton::Other(n) => MouseButton::Other(n), _ => MouseButton::Other(0), } } pub fn map_winit_key(key: &WinitKey) -> Key { use Key::*; use winit::keyboard::NamedKey; match key { WinitKey::Character(s) => match s.as_str() { "a" | "A" => A, "b" | "B" => B, "c" | "C" => C, "d" | "D" => D, "e" | "E" => E, "f" | "F" => F, "g" | "G" => G, "h" | "H" => H, "i" | "I" => I, "j" | "J" => J, "k" | "K" => K, "l" | "L" => L, "m" | "M" => M, "n" | "N" => N, "o" | "O" => O, "p" | "P" => P, "q" | "Q" => Q, "r" | "R" => R, "s" | "S" => S, "t" | "T" => T, "u" | "U" => U, "v" | "V" => V, "w" | "W" => W, "x" | "X" => X, "y" | "Y" => Y, "z" | "Z" => Z, "0" => Num0, "1" => Num1, "2" => Num2, "3" => Num3, "4" => Num4, "5" => Num5, "6" => Num6, "7" => Num7, "8" => Num8, "9" => Num9, "," => Comma, "." => Period, "-" => Minus, "+" => Plus, "/" => Slash, "\\" => Backslash, ";" => Semicolon, "'" => Apostrophe, "[" => LeftBracket, "]" => RightBracket, "`" => Grave, "=" => Equal, _ => Unknown, }, WinitKey::Named(named_key) => match named_key { NamedKey::ArrowUp => ArrowUp, NamedKey::ArrowDown => ArrowDown, NamedKey::ArrowLeft => ArrowLeft, NamedKey::ArrowRight => ArrowRight, NamedKey::Escape => Escape, NamedKey::Enter => Enter, NamedKey::Tab => Tab, NamedKey::Space => Space, NamedKey::Backspace => Backspace, NamedKey::Insert => Insert, NamedKey::Delete => Delete, NamedKey::Home => Home, NamedKey::End => End, NamedKey::PageUp => PageUp, NamedKey::PageDown => PageDown, NamedKey::Shift => Shift, NamedKey::Control => Control, NamedKey::Alt => Alt, NamedKey::Super => Super, NamedKey::F1 => F1, NamedKey::F2 => F2, NamedKey::F3 => F3, NamedKey::F4 => F4, NamedKey::F5 => F5, NamedKey::F6 => F6, NamedKey::F7 => F7, NamedKey::F8 => F8, NamedKey::F9 => F9, NamedKey::F10 => F10, NamedKey::F11 => F11, NamedKey::F12 => F12, _ => Unknown, }, _ => Unknown, } }