fix(platform-winit): map lifecycle and pointer state
This commit is contained in:
@@ -57,6 +57,9 @@ impl MonotonicClock for WinitClock {
|
|||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct WinitEventSource {
|
pub struct WinitEventSource {
|
||||||
queue: VecDeque<PlatformEvent>,
|
queue: VecDeque<PlatformEvent>,
|
||||||
|
cursor_position: Option<(f64, f64)>,
|
||||||
|
minimized: Option<bool>,
|
||||||
|
occluded: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WinitEventSource {
|
impl WinitEventSource {
|
||||||
@@ -65,6 +68,9 @@ impl WinitEventSource {
|
|||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
queue: VecDeque::new(),
|
queue: VecDeque::new(),
|
||||||
|
cursor_position: None,
|
||||||
|
minimized: None,
|
||||||
|
occluded: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,20 +83,24 @@ impl WinitEventSource {
|
|||||||
pub fn push_window_event(&mut self, event: &WindowEvent) {
|
pub fn push_window_event(&mut self, event: &WindowEvent) {
|
||||||
match event {
|
match event {
|
||||||
WindowEvent::KeyboardInput { event, .. } => {
|
WindowEvent::KeyboardInput { event, .. } => {
|
||||||
|
if let Some(scancode) = event.physical_key.to_scancode() {
|
||||||
self.queue.push_back(PlatformEvent::KeyboardInput {
|
self.queue.push_back(PlatformEvent::KeyboardInput {
|
||||||
scancode: event.physical_key.to_scancode().unwrap_or(0),
|
scancode,
|
||||||
pressed: event.state.is_pressed(),
|
pressed: event.state.is_pressed(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
WindowEvent::MouseInput { state, button, .. } => {
|
WindowEvent::MouseInput { state, button, .. } => {
|
||||||
|
let (x, y) = self.cursor_position.unwrap_or((0.0, 0.0));
|
||||||
self.queue.push_back(PlatformEvent::MouseInput {
|
self.queue.push_back(PlatformEvent::MouseInput {
|
||||||
button: mouse_button_code(*button),
|
button: mouse_button_code(*button),
|
||||||
pressed: state.is_pressed(),
|
pressed: state.is_pressed(),
|
||||||
x: 0.0,
|
x,
|
||||||
y: 0.0,
|
y,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
WindowEvent::CursorMoved { position, .. } => {
|
WindowEvent::CursorMoved { position, .. } => {
|
||||||
|
self.cursor_position = Some((position.x, position.y));
|
||||||
self.queue.push_back(PlatformEvent::CursorMoved {
|
self.queue.push_back(PlatformEvent::CursorMoved {
|
||||||
x: position.x,
|
x: position.x,
|
||||||
y: position.y,
|
y: position.y,
|
||||||
@@ -101,11 +111,24 @@ impl WinitEventSource {
|
|||||||
width: size.width,
|
width: size.width,
|
||||||
height: size.height,
|
height: size.height,
|
||||||
});
|
});
|
||||||
|
let minimized = size.width == 0 || size.height == 0;
|
||||||
|
if self.minimized != Some(minimized) {
|
||||||
|
self.minimized = Some(minimized);
|
||||||
|
self.queue.push_back(PlatformEvent::Minimized { minimized });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
WindowEvent::Focused(focused) => {
|
WindowEvent::Focused(focused) => {
|
||||||
self.queue
|
self.queue
|
||||||
.push_back(PlatformEvent::FocusChanged { focused: *focused });
|
.push_back(PlatformEvent::FocusChanged { focused: *focused });
|
||||||
}
|
}
|
||||||
|
WindowEvent::Occluded(occluded) => {
|
||||||
|
if self.occluded != Some(*occluded) {
|
||||||
|
self.occluded = Some(*occluded);
|
||||||
|
self.queue.push_back(PlatformEvent::Occluded {
|
||||||
|
occluded: *occluded,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
|
WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
|
||||||
self.queue.push_back(PlatformEvent::DpiChanged {
|
self.queue.push_back(PlatformEvent::DpiChanged {
|
||||||
scale: *scale_factor,
|
scale: *scale_factor,
|
||||||
@@ -120,8 +143,11 @@ impl WinitEventSource {
|
|||||||
|
|
||||||
/// Pushes events from an event loop event.
|
/// Pushes events from an event loop event.
|
||||||
pub fn push_event<T>(&mut self, event: &Event<T>) {
|
pub fn push_event<T>(&mut self, event: &Event<T>) {
|
||||||
if let Event::WindowEvent { event, .. } = event {
|
match event {
|
||||||
self.push_window_event(event);
|
Event::Resumed => self.queue.push_back(PlatformEvent::Resumed),
|
||||||
|
Event::Suspended => self.queue.push_back(PlatformEvent::Suspended),
|
||||||
|
Event::WindowEvent { event, .. } => self.push_window_event(event),
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,7 +159,7 @@ fn mouse_button_code(button: MouseButton) -> u16 {
|
|||||||
MouseButton::Middle => 2,
|
MouseButton::Middle => 2,
|
||||||
MouseButton::Back => 3,
|
MouseButton::Back => 3,
|
||||||
MouseButton::Forward => 4,
|
MouseButton::Forward => 4,
|
||||||
MouseButton::Other(index) => 100 + index,
|
MouseButton::Other(index) => 100_u16.saturating_add(index),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,6 +311,7 @@ pub fn window_native_handles(window: &Window) -> Option<NativeWindowHandles> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use winit::event::{DeviceId, ElementState};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn event_source_buffers_synthetic_events() -> Result<(), PlatformError> {
|
fn event_source_buffers_synthetic_events() -> Result<(), PlatformError> {
|
||||||
@@ -375,6 +402,68 @@ mod tests {
|
|||||||
assert!(events.contains(&PlatformEvent::FocusChanged { focused: false }));
|
assert!(events.contains(&PlatformEvent::FocusChanged { focused: false }));
|
||||||
assert!(events.contains(&PlatformEvent::QuitRequested));
|
assert!(events.contains(&PlatformEvent::QuitRequested));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn push_event_maps_lifecycle_resumed_and_suspended() -> Result<(), PlatformError> {
|
||||||
|
let mut source = WinitEventSource::new();
|
||||||
|
source.push_event(&Event::<()>::Resumed);
|
||||||
|
source.push_event(&Event::<()>::Suspended);
|
||||||
|
|
||||||
|
let mut events = Vec::new();
|
||||||
|
source.poll(&mut events)?;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
events,
|
||||||
|
vec![PlatformEvent::Resumed, PlatformEvent::Suspended]
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cursor_position_and_occlusion_are_preserved_for_mouse_input() -> Result<(), PlatformError> {
|
||||||
|
let mut source = WinitEventSource::new();
|
||||||
|
source.push_window_event(&WindowEvent::CursorMoved {
|
||||||
|
device_id: DeviceId::dummy(),
|
||||||
|
position: (320.0, 240.0).into(),
|
||||||
|
});
|
||||||
|
source.push_window_event(&WindowEvent::MouseInput {
|
||||||
|
device_id: DeviceId::dummy(),
|
||||||
|
state: ElementState::Pressed,
|
||||||
|
button: MouseButton::Other(u16::MAX),
|
||||||
|
});
|
||||||
|
source.push_window_event(&WindowEvent::Occluded(true));
|
||||||
|
|
||||||
|
let mut events = Vec::new();
|
||||||
|
source.poll(&mut events)?;
|
||||||
|
|
||||||
|
assert!(events.contains(&PlatformEvent::CursorMoved { x: 320.0, y: 240.0 }));
|
||||||
|
assert!(events.contains(&PlatformEvent::MouseInput {
|
||||||
|
button: u16::MAX,
|
||||||
|
pressed: true,
|
||||||
|
x: 320.0,
|
||||||
|
y: 240.0,
|
||||||
|
}));
|
||||||
|
assert!(events.contains(&PlatformEvent::Occluded { occluded: true }));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn zero_extent_resize_updates_minimized_state() -> Result<(), PlatformError> {
|
||||||
|
let mut source = WinitEventSource::new();
|
||||||
|
source.push_window_event(&WindowEvent::Resized(winit::dpi::PhysicalSize::new(
|
||||||
|
0u32, 720u32,
|
||||||
|
)));
|
||||||
|
source.push_window_event(&WindowEvent::Resized(winit::dpi::PhysicalSize::new(
|
||||||
|
1280u32, 720u32,
|
||||||
|
)));
|
||||||
|
|
||||||
|
let mut events = Vec::new();
|
||||||
|
source.poll(&mut events)?;
|
||||||
|
|
||||||
|
assert!(events.contains(&PlatformEvent::Minimized { minimized: true }));
|
||||||
|
assert!(events.contains(&PlatformEvent::Minimized { minimized: false }));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: no unsafe usage in this crate.
|
// SAFETY: no unsafe usage in this crate.
|
||||||
|
|||||||
Reference in New Issue
Block a user