use winit::{event::{DeviceId, KeyboardInput, ModifiersState, MouseScrollDelta, TouchPhase, MouseButton, AxisId, Touch, WindowEvent, ElementState}, dpi::PhysicalPosition}; use crate::ecs::world::Resource; /// Wrapper around events from `winit::WindowEvent` that are specific to input related events. /// /// The `winit::WindowEvent` enum has many values that are related to inputs. /// Ex: /// * winit::WindowEvent::KeyboardInput /// * winit::WindowEvent::CursorMoved /// * winit::WindowEvent::CursorEntered /// * winit::WindowEvent::MouseWheel /// * winit::WindowEvent::CursorLeft /// * winit::WindowEvent::MouseInput /// etc. /// /// Its easier for these to all be in a single `InputEvent` type enum to check if any input was received. /// The comments for all the methods were taken from `winit::WindowEvent` #[derive(Debug, PartialEq, Clone)] pub enum InputEvent { /// An event from the keyboard has been received. KeyboardInput { device_id: DeviceId, input: KeyboardInput, /// If true, the event was generated synthetically by winit in one of the following circumstances: /// Synthetic key press events are generated for all keys pressed when a window gains focus. /// Likewise, synthetic key release events are generated for all keys pressed when a window goes out of focus. /// Currently, this is only functional on X11 and Windows is_synthetic: bool, }, /// The cursor has moved on the window. CursorMoved { device_id: DeviceId, position: PhysicalPosition, modifiers: ModifiersState, }, /// The cursor has entered the window. CursorEntered { device_id: DeviceId, }, /// The cursor has left the window. CursorLeft { device_id: DeviceId, }, /// A mouse wheel movement or touchpad scroll occurred. MouseWheel { device_id: DeviceId, delta: MouseScrollDelta, phase: TouchPhase, /// Deprecated in favor of WindowEvent::ModifiersChanged modifiers: ModifiersState, }, /// An mouse button press has been received. MouseInput { device_id: DeviceId, state: ElementState, button: MouseButton, #[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"] modifiers: ModifiersState, }, /// Touchpad magnification event with two-finger pinch gesture. /// Positive delta values indicate magnification (zooming in) and negative delta values indicate shrinking (zooming out). /// /// Note: Only available on macOS TouchpadMagnify { device_id: DeviceId, delta: f64, phase: TouchPhase, }, /// Smart magnification event. /// /// On a Mac, smart magnification is triggered by a double tap with two fingers /// on the trackpad and is commonly used to zoom on a certain object /// (e.g. a paragraph of a PDF) or (sort of like a toggle) to reset any zoom. /// The gesture is also supported in Safari, Pages, etc. /// /// The event is general enough that its generating gesture is allowed to vary /// across platforms. It could also be generated by another device. /// /// Unfortunatly, neither [Windows](https://support.microsoft.com/en-us/windows/touch-gestures-for-windows-a9d28305-4818-a5df-4e2b-e5590f850741) /// nor [Wayland](https://wayland.freedesktop.org/libinput/doc/latest/gestures.html) /// support this gesture or any other gesture with the same effect. /// /// ## Platform-specific /// /// - Only available on **macOS 10.8** and later. SmartMagnify { device_id: DeviceId }, /// Touchpad rotation event with two-finger rotation gesture. /// /// Positive delta values indicate rotation counterclockwise and /// negative delta values indicate rotation clockwise. /// /// ## Platform-specific /// /// - Only available on **macOS**. TouchpadRotate { device_id: DeviceId, delta: f32, phase: TouchPhase, }, /// Touchpad pressure event. /// /// At the moment, only supported on Apple forcetouch-capable macbooks. /// The parameters are: pressure level (value between 0 and 1 representing how hard the touchpad /// is being pressed) and stage (integer representing the click level). TouchpadPressure { device_id: DeviceId, pressure: f32, stage: i64, }, /// Motion on some analog axis. May report data redundant to other, more specific events. AxisMotion { device_id: DeviceId, axis: AxisId, value: f64, }, /// Touch event has been received /// /// ## Platform-specific /// /// - **macOS:** Unsupported. Touch(Touch), } #[derive(Debug, PartialEq)] pub enum InputEventConversionError<'a> { FromError(&'a WindowEvent<'a>) } impl<'a> Into> for InputEvent { fn into(self) -> WindowEvent<'a> { match self { InputEvent::KeyboardInput { device_id, input, is_synthetic } => WindowEvent::KeyboardInput { device_id, input, is_synthetic }, InputEvent::CursorMoved { device_id, position, modifiers } => WindowEvent::CursorMoved { device_id, position, modifiers }, InputEvent::CursorEntered { device_id } => WindowEvent::CursorEntered { device_id }, InputEvent::CursorLeft { device_id } => WindowEvent::CursorLeft { device_id }, InputEvent::MouseWheel { device_id, delta, phase, modifiers } => WindowEvent::MouseWheel { device_id, delta, phase, modifiers }, InputEvent::MouseInput { device_id, state, button, modifiers } => WindowEvent::MouseInput { device_id, state, button, modifiers }, InputEvent::TouchpadMagnify { device_id, delta, phase } => WindowEvent::TouchpadMagnify { device_id, delta, phase }, InputEvent::SmartMagnify { device_id } => WindowEvent::SmartMagnify { device_id }, InputEvent::TouchpadRotate { device_id, delta, phase } => WindowEvent::TouchpadRotate { device_id, delta, phase }, InputEvent::TouchpadPressure { device_id, pressure, stage } => WindowEvent::TouchpadPressure { device_id, pressure, stage }, InputEvent::AxisMotion { device_id, axis, value } => WindowEvent::AxisMotion { device_id, axis, value }, InputEvent::Touch(t) => WindowEvent::Touch(t), } } } impl<'a> TryFrom<&'a WindowEvent<'a>> for InputEvent { type Error = InputEventConversionError<'a>; fn try_from(value: &'a WindowEvent<'a>) -> Result { match value { WindowEvent::KeyboardInput { device_id, input, is_synthetic } => Ok(InputEvent::KeyboardInput { device_id: device_id.clone(), input: input.clone(), is_synthetic: is_synthetic.clone() }), WindowEvent::CursorMoved { device_id, position, modifiers } => Ok(InputEvent::CursorMoved { device_id: device_id.clone(), position: position.clone(), modifiers: modifiers.clone() }), WindowEvent::CursorEntered { device_id } => Ok(InputEvent::CursorEntered { device_id: device_id.clone() }), WindowEvent::CursorLeft { device_id } => Ok(InputEvent::CursorLeft { device_id: device_id.clone() }), WindowEvent::MouseWheel { device_id, delta, phase, modifiers } => Ok(InputEvent::MouseWheel { device_id: device_id.clone(), delta: delta.clone(), phase: phase.clone(), modifiers: modifiers.clone() }), WindowEvent::MouseInput { device_id, state, button, modifiers } => Ok(InputEvent::MouseInput { device_id: device_id.clone(), state: state.clone(), button: button.clone(), modifiers: modifiers.clone() }), WindowEvent::TouchpadMagnify { device_id, delta, phase } => Ok(InputEvent::TouchpadMagnify { device_id: device_id.clone(), delta: delta.clone(), phase: phase.clone() }), WindowEvent::SmartMagnify { device_id } => Ok(InputEvent::SmartMagnify { device_id: device_id.clone() }), WindowEvent::TouchpadRotate { device_id, delta, phase } => Ok(InputEvent::TouchpadRotate { device_id: device_id.clone(), delta: delta.clone(), phase: phase.clone() }), WindowEvent::TouchpadPressure { device_id, pressure, stage } => Ok(InputEvent::TouchpadPressure { device_id: device_id.clone(), pressure: pressure.clone(), stage: stage.clone() }), WindowEvent::AxisMotion { device_id, axis, value } => Ok(InputEvent::AxisMotion { device_id: device_id.clone(), axis: axis.clone(), value: value.clone() }), WindowEvent::Touch(t) => Ok(InputEvent::Touch(t.clone())), _ => Err(InputEventConversionError::FromError(value)) } } } impl Resource for InputEvent { fn as_any(&self) -> &dyn std::any::Any { self } fn as_any_mut(&mut self) -> &mut dyn std::any::Any { self } }