diff options
| author | HampusM <hampus@hampusmat.com> | 2026-05-25 19:49:15 +0200 |
|---|---|---|
| committer | HampusM <hampus@hampusmat.com> | 2026-05-25 19:49:15 +0200 |
| commit | f8b7c0cfc73eaeb7ef8dfb3151f93879c97b220a (patch) | |
| tree | 5ff078443f5d64e4f99fd0487b3a2e72ef961540 /engine/src/windowing.rs | |
| parent | 8a41f5aeb3ac143d731928d1c343cd9338190f0a (diff) | |
fix(engine): prevent dropped cursor motion input on Windows
Diffstat (limited to 'engine/src/windowing.rs')
| -rw-r--r-- | engine/src/windowing.rs | 173 |
1 files changed, 97 insertions, 76 deletions
diff --git a/engine/src/windowing.rs b/engine/src/windowing.rs index ea5a692..096a23f 100644 --- a/engine/src/windowing.rs +++ b/engine/src/windowing.rs @@ -1,3 +1,4 @@ +use std::hint::cold_path; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Weak}; use std::thread::{Builder as ThreadBuilder, JoinHandle as ThreadJoinHandle}; @@ -33,8 +34,7 @@ use crate::ecs::sole::Single; use crate::ecs::system::observer::Observe; use crate::ecs::uid::Uid; use crate::ecs::{declare_entity, Query, Sole}; -use crate::util::MapVec; -use crate::vector::Vec2; +use crate::util::{AtomicTwoF64, MapVec}; use crate::windowing::keyboard::{Key, KeyState, Keyboard, UnknownKeyCodeError}; use crate::windowing::mouse::{ Button as MouseButton, @@ -130,7 +130,18 @@ fn update_stuff( { keyboard.make_key_states_previous(); mouse_buttons.make_states_previous(); - mouse.curr_tick_position_delta = Vec2::default(); + + mouse.curr_tick_position_delta = context + .shared_state + .relative_mouse_pos_delta + .swap((0.0, 0.0), Ordering::Relaxed) + .into(); + + mouse.position = context + .shared_state + .absolute_mouse_pos + .load(Ordering::Relaxed) + .into(); let Context { ref message_from_app_receiver, @@ -235,12 +246,6 @@ fn update_stuff( MessageFromApp::KeyboardKeyStateChanged(key, key_state) => { keyboard.set_key_state(key, key_state); } - MessageFromApp::MouseMovedTo { position } => { - mouse.position = position; - } - MessageFromApp::MouseMoved { position_delta } => { - mouse.curr_tick_position_delta += position_delta; - } MessageFromApp::MouseButtonStateChanged(mouse_button, mouse_button_state) => { mouse_buttons.set(mouse_button, mouse_button_state); } @@ -300,9 +305,9 @@ fn handle_window_removed( pub struct Context { _thread: ThreadJoinHandle<()>, - is_dropped: Arc<AtomicBool>, message_from_app_receiver: ChannelReceiver<MessageFromApp>, message_to_app_sender: ChannelSender<MessageToApp>, + shared_state: Arc<SharedState>, display_handle: Option<OwnedDisplayHandle>, windows: MapVec<WindowId, (Arc<winit::window::Window>, Uid)>, } @@ -362,10 +367,6 @@ impl Default for Context { fn default() -> Self { - let is_dropped = Arc::new(AtomicBool::new(false)); - - let is_dropped_b = is_dropped.clone(); - let (message_from_app_sender, message_from_app_receiver) = bounded_channel::<MessageFromApp>(MESSAGE_FROM_APP_CHANNEL_CAP); @@ -374,6 +375,9 @@ impl Default for Context let (message_to_app_sender, message_to_app_receiver) = bounded_channel::<MessageToApp>(MESSAGE_TO_APP_CHANNEL_CAP); + let shared_state = Arc::new(SharedState::default()); + let shared_state_b = shared_state.clone(); + Self { _thread: ThreadBuilder::new() .name("windowing".to_string()) @@ -382,9 +386,8 @@ impl Default for Context message_from_app_sender, message_from_app_receiver: message_from_app_receiver_b, message_to_app_receiver, - is_dropped: is_dropped_b, + shared_state: shared_state_b, windows: MapVec::default(), - focused_window_id: None, }; let event_loop = match create_event_loop() { @@ -402,9 +405,9 @@ impl Default for Context } }) .expect("Failed to create windowing thread"), - is_dropped, message_from_app_receiver, message_to_app_sender, + shared_state, display_handle: None, windows: MapVec::default(), } @@ -415,7 +418,7 @@ impl Drop for Context { fn drop(&mut self) { - self.is_dropped.store(true, Ordering::Relaxed); + self.shared_state.is_dropped.store(true, Ordering::Relaxed); } } @@ -450,14 +453,6 @@ enum MessageFromApp WindowCloseRequested(WindowId), WindowScaleFactorChanged(WindowId, f64), KeyboardKeyStateChanged(Key, KeyState), - MouseMovedTo - { - position: Vec2<f64>, - }, - MouseMoved - { - position_delta: Vec2<f64>, - }, MouseButtonStateChanged(MouseButton, MouseButtonState), } @@ -469,14 +464,33 @@ enum MessageToApp } #[derive(Debug)] +struct SharedState +{ + relative_mouse_pos_delta: AtomicTwoF64, + absolute_mouse_pos: AtomicTwoF64, + is_dropped: AtomicBool, +} + +impl Default for SharedState +{ + fn default() -> Self + { + Self { + relative_mouse_pos_delta: AtomicTwoF64::new((0.0, 0.0)), + absolute_mouse_pos: AtomicTwoF64::new((0.0, 0.0)), + is_dropped: AtomicBool::new(false), + } + } +} + +#[derive(Debug)] struct App { message_from_app_sender: ChannelSender<MessageFromApp>, message_from_app_receiver: ChannelReceiver<MessageFromApp>, message_to_app_receiver: ChannelReceiver<MessageToApp>, - is_dropped: Arc<AtomicBool>, + shared_state: Arc<SharedState>, windows: MapVec<WindowId, (Weak<WinitWindow>, WindowSettings)>, - focused_window_id: Option<WindowId>, } impl App @@ -567,7 +581,7 @@ impl ApplicationHandler for App )); } StartCause::Poll => { - if self.is_dropped.load(Ordering::Relaxed) { + if self.shared_state.is_dropped.load(Ordering::Relaxed) { event_loop.exit(); return; } @@ -642,9 +656,38 @@ impl ApplicationHandler for App )); } WindowEvent::CursorMoved { device_id: _, position } => { - self.send_message(MessageFromApp::MouseMovedTo { - position: Vec2 { x: position.x, y: position.y }, - }); + self.shared_state + .absolute_mouse_pos + .store((position.x, position.y), Ordering::Relaxed); + + let Some((window, window_settings)) = + self.windows.get(&WindowId::from_inner(window_id)) + else { + cold_path(); + return; + }; + + if window_settings.cursor_grab_mode != CursorGrabMode::Locked { + return; + } + + let Some(window) = window.upgrade() else { + cold_path(); + return; + }; + + let window_size = window.inner_size(); + + if let Err(err) = window.set_cursor_position(PhysicalPosition { + x: window_size.width / 2, + y: window_size.height / 2, + }) { + cold_path(); + tracing::error!( + window_id=?window_id, + "Failed to lock cursor position: {err}" + ); + }; } WindowEvent::MouseInput { device_id: _, state, button } => { self.send_message(MessageFromApp::MouseButtonStateChanged( @@ -652,13 +695,6 @@ impl ApplicationHandler for App state.into(), )); } - WindowEvent::Focused(is_focused) => { - if is_focused { - self.focused_window_id = Some(WindowId::from_inner(window_id)); - } else { - self.focused_window_id = None; - } - } WindowEvent::ScaleFactorChanged { scale_factor, inner_size_writer: _ } => { self.send_message(MessageFromApp::WindowScaleFactorChanged( WindowId::from_inner(window_id), @@ -679,44 +715,29 @@ impl ApplicationHandler for App { match device_event { DeviceEvent::MouseMotion { delta } => { - self.send_message(MessageFromApp::MouseMoved { - position_delta: Vec2 { x: delta.0, y: delta.1 }, - }); - - let Some(focused_window_id) = self.focused_window_id else { - return; - }; - - let Some((focused_window, focused_window_settings)) = - self.windows.get(&focused_window_id) - else { - tracing::error!( - window_id=?focused_window_id, - "Focused window not found" - ); - return; - }; - - if focused_window_settings.cursor_grab_mode != CursorGrabMode::Locked { - return; + let curr_mouse_pos_delta = self + .shared_state + .relative_mouse_pos_delta + .load(Ordering::Relaxed); + + if self + .shared_state + .relative_mouse_pos_delta + .compare_exchange( + curr_mouse_pos_delta, + ( + curr_mouse_pos_delta.0 + delta.0, + curr_mouse_pos_delta.1 + delta.1, + ), + Ordering::Relaxed, + Ordering::Relaxed, + ) + .is_err() + { + self.shared_state + .relative_mouse_pos_delta + .store(delta, Ordering::Relaxed); } - - // TODO: This might need to be optimized - let Some(focused_window) = focused_window.upgrade() else { - return; - }; - - let focused_window_size = focused_window.inner_size(); - - if let Err(err) = focused_window.set_cursor_position(PhysicalPosition { - x: focused_window_size.width / 2, - y: focused_window_size.height / 2, - }) { - tracing::error!( - window_id=?focused_window_id, - "Failed to set cursor position in focused window: {err}" - ); - }; } _ => {} } |
