From 0e1fceef2336463be65b1728d66b30c132431b76 Mon Sep 17 00:00:00 2001 From: Samuel Guerra Date: Thu, 10 Dec 2020 20:56:59 -0300 Subject: [PATCH] On Windows, fix bug causing mouse capture to not be released. --- CHANGELOG.md | 4 ++++ src/platform_impl/windows/event_loop.rs | 24 +++++++++++++++-------- src/platform_impl/windows/window_state.rs | 4 ++-- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 559cbc8d13..122f9893ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# Unreleased + +- On Windows, fix bug causing mouse capture to not be released. + # 0.24.0 (2020-12-09) - On Windows, fix applications not exiting gracefully due to thread_event_target_callback accessing corrupted memory. diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 3ccd55c1d0..2a24958587 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -619,15 +619,17 @@ fn subclass_event_target_window( /// Capture mouse input, allowing `window` to receive mouse events when the cursor is outside of /// the window. unsafe fn capture_mouse(window: HWND, window_state: &mut WindowState) { - window_state.mouse.buttons_down += 1; + window_state.mouse.capture_count += 1; winuser::SetCapture(window); } /// Release mouse input, stopping windows on this thread from receiving mouse input when the cursor /// is outside the window. -unsafe fn release_mouse(window_state: &mut WindowState) { - window_state.mouse.buttons_down = window_state.mouse.buttons_down.saturating_sub(1); - if window_state.mouse.buttons_down == 0 { +unsafe fn release_mouse(mut window_state: parking_lot::MutexGuard<'_, WindowState>) { + window_state.mouse.capture_count = window_state.mouse.capture_count.saturating_sub(1); + if window_state.mouse.capture_count == 0 { + // ReleaseCapture() causes a WM_CAPTURECHANGED where we lock the window_state. + drop(window_state); winuser::ReleaseCapture(); } } @@ -1192,7 +1194,7 @@ unsafe extern "system" fn public_window_callback( ElementState::Released, MouseButton::Left, WindowEvent::MouseInput, }; - release_mouse(&mut *subclass_input.window_state.lock()); + release_mouse(subclass_input.window_state.lock()); update_modifiers(window, subclass_input); @@ -1234,7 +1236,7 @@ unsafe extern "system" fn public_window_callback( ElementState::Released, MouseButton::Right, WindowEvent::MouseInput, }; - release_mouse(&mut *subclass_input.window_state.lock()); + release_mouse(subclass_input.window_state.lock()); update_modifiers(window, subclass_input); @@ -1276,7 +1278,7 @@ unsafe extern "system" fn public_window_callback( ElementState::Released, MouseButton::Middle, WindowEvent::MouseInput, }; - release_mouse(&mut *subclass_input.window_state.lock()); + release_mouse(subclass_input.window_state.lock()); update_modifiers(window, subclass_input); @@ -1320,7 +1322,7 @@ unsafe extern "system" fn public_window_callback( }; let xbutton = winuser::GET_XBUTTON_WPARAM(wparam); - release_mouse(&mut *subclass_input.window_state.lock()); + release_mouse(subclass_input.window_state.lock()); update_modifiers(window, subclass_input); @@ -1336,6 +1338,12 @@ unsafe extern "system" fn public_window_callback( 0 } + winuser::WM_CAPTURECHANGED => { + // window lost mouse capture + subclass_input.window_state.lock().mouse.capture_count = 0; + 0 + } + winuser::WM_TOUCH => { let pcount = LOWORD(wparam as DWORD) as usize; let mut inputs = Vec::with_capacity(pcount); diff --git a/src/platform_impl/windows/window_state.rs b/src/platform_impl/windows/window_state.rs index 1369fe7210..c02ca4b431 100644 --- a/src/platform_impl/windows/window_state.rs +++ b/src/platform_impl/windows/window_state.rs @@ -46,7 +46,7 @@ pub struct SavedWindow { #[derive(Clone)] pub struct MouseProperties { pub cursor: CursorIcon, - pub buttons_down: u32, + pub capture_count: u32, cursor_flags: CursorFlags, pub last_position: Option>, } @@ -108,7 +108,7 @@ impl WindowState { WindowState { mouse: MouseProperties { cursor: CursorIcon::default(), - buttons_down: 0, + capture_count: 0, cursor_flags: CursorFlags::empty(), last_position: None, },