From 4122ff28d44a2c965ece074f67d9e212d44118db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Sat, 21 Jan 2023 00:01:28 +0000 Subject: [PATCH] break feedback loop when moving cursor (#7298) # Objective - Fixes #7294 ## Solution - Do not trigger change detection when setting the cursor position from winit When moving the cursor continuously, Winit sends events: - CursorMoved(0) - CursorMoved(1) - => start of Bevy schedule execution - CursorMoved(2) - CursorMoved(3) - <= End of Bevy schedule execution if Bevy schedule runs after the event 1, events 2 and 3 would happen during the execution but would be read only on the next system run. During the execution, the system would detect a change on cursor position, and send back an order to winit to move it back to 1, so event 2 and 3 would be ignored. By bypassing change detection when setting the cursor from winit event, it doesn't trigger sending back that change to winit out of order. --- crates/bevy_winit/src/lib.rs | 12 ++++++++++-- .../tools/scene_viewer/camera_controller_plugin.rs | 3 ++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index ff4eda67c5260..84303caaa1c99 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -396,7 +396,11 @@ pub fn winit_runner(mut app: App) { window.resolution.physical_height() as f64 - position.y, ); - window.set_physical_cursor_position(Some(physical_position)); + // bypassing change detection to not trigger feedback loop with system `changed_window` + // this system change the cursor position in winit + window + .bypass_change_detection() + .set_physical_cursor_position(Some(physical_position)); cursor_events.cursor_moved.send(CursorMoved { window: window_entity, @@ -412,7 +416,11 @@ pub fn winit_runner(mut app: App) { WindowEvent::CursorLeft { .. } => { // Component if let Ok((mut window, _)) = window_query.get_mut(window_entity) { - window.set_physical_cursor_position(None); + // bypassing change detection to not trigger feedback loop with system `changed_window` + // this system change the cursor position in winit + window + .bypass_change_detection() + .set_physical_cursor_position(None); } cursor_events.cursor_left.send(CursorLeft { diff --git a/examples/tools/scene_viewer/camera_controller_plugin.rs b/examples/tools/scene_viewer/camera_controller_plugin.rs index 701947bb775e8..2c2dcac4522bf 100644 --- a/examples/tools/scene_viewer/camera_controller_plugin.rs +++ b/examples/tools/scene_viewer/camera_controller_plugin.rs @@ -177,7 +177,8 @@ fn camera_controller( for mouse_event in mouse_events.iter() { mouse_delta += mouse_event.delta; } - } else { + } + if mouse_button_input.just_released(options.mouse_key_enable_mouse) { for mut window in &mut windows { window.cursor.grab_mode = CursorGrabMode::None; window.cursor.visible = true;