Add mouse event capturing when click-dragging out of a win32 window (#292)

* Add mouse event capturing when click-dragging out of a win32 window

* Remove git merge conflict comments

* Add changelog entry
This commit is contained in:
HDM 2018-02-14 04:31:25 -05:00 committed by Pierre Krieger
parent 4abcc164cd
commit 7daf27f389
2 changed files with 58 additions and 2 deletions

View file

@ -1,5 +1,9 @@
# Unreleased # Unreleased
- Implement `MonitorId::get_dimensions` for Android.
- Fixed windows not receiving mouse events when click-dragging the mouse outside the client area of a window, on Windows platforms.
=======
# Version 0.11.0 (2018-02-09) # Version 0.11.0 (2018-02-09)
- Implement `MonitorId::get_dimensions` for Android. - Implement `MonitorId::get_dimensions` for Android.

View file

@ -102,7 +102,8 @@ impl EventsLoop {
*context_stash.borrow_mut() = Some(ThreadLocalData { *context_stash.borrow_mut() = Some(ThreadLocalData {
sender: tx, sender: tx,
windows: HashMap::with_capacity(4), windows: HashMap::with_capacity(4),
win32_block_loop: win32_block_loop_child win32_block_loop: win32_block_loop_child,
mouse_buttons_down: 0
}); });
}); });
@ -296,7 +297,8 @@ thread_local!(static CONTEXT_STASH: RefCell<Option<ThreadLocalData>> = RefCell::
struct ThreadLocalData { struct ThreadLocalData {
sender: mpsc::Sender<Event>, sender: mpsc::Sender<Event>,
windows: HashMap<HWND, Arc<Mutex<WindowState>>>, windows: HashMap<HWND, Arc<Mutex<WindowState>>>,
win32_block_loop: Arc<(Mutex<bool>, Condvar)> win32_block_loop: Arc<(Mutex<bool>, Condvar)>,
mouse_buttons_down: u32
} }
// Utility function that dispatches an event on the current thread. // Utility function that dispatches an event on the current thread.
@ -308,6 +310,32 @@ fn send_event(event: Event) {
}); });
} }
/// Capture mouse input, allowing `window` to receive mouse events when the cursor is outside of
/// the window.
unsafe fn capture_mouse(window: HWND) {
CONTEXT_STASH.with(|context_stash| {
let mut context_stash = context_stash.borrow_mut();
if let Some(context_stash) = context_stash.as_mut() {
context_stash.mouse_buttons_down += 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() {
CONTEXT_STASH.with(|context_stash| {
let mut context_stash = context_stash.borrow_mut();
if let Some(context_stash) = context_stash.as_mut() {
context_stash.mouse_buttons_down = context_stash.mouse_buttons_down.saturating_sub(1);
if context_stash.mouse_buttons_down == 0 {
winuser::ReleaseCapture();
}
}
});
}
/// Any window whose callback is configured to this function will have its events propagated /// Any window whose callback is configured to this function will have its events propagated
/// through the events loop of the thread the window was created in. /// through the events loop of the thread the window was created in.
// //
@ -550,6 +578,9 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
use events::WindowEvent::MouseInput; use events::WindowEvent::MouseInput;
use events::MouseButton::Left; use events::MouseButton::Left;
use events::ElementState::Pressed; use events::ElementState::Pressed;
capture_mouse(window);
send_event(Event::WindowEvent { send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)), window_id: SuperWindowId(WindowId(window)),
event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Left, modifiers: event::get_key_mods() } event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Left, modifiers: event::get_key_mods() }
@ -561,6 +592,9 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
use events::WindowEvent::MouseInput; use events::WindowEvent::MouseInput;
use events::MouseButton::Left; use events::MouseButton::Left;
use events::ElementState::Released; use events::ElementState::Released;
release_mouse();
send_event(Event::WindowEvent { send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)), window_id: SuperWindowId(WindowId(window)),
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Left, modifiers: event::get_key_mods() } event: MouseInput { device_id: DEVICE_ID, state: Released, button: Left, modifiers: event::get_key_mods() }
@ -572,6 +606,9 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
use events::WindowEvent::MouseInput; use events::WindowEvent::MouseInput;
use events::MouseButton::Right; use events::MouseButton::Right;
use events::ElementState::Pressed; use events::ElementState::Pressed;
capture_mouse(window);
send_event(Event::WindowEvent { send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)), window_id: SuperWindowId(WindowId(window)),
event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Right, modifiers: event::get_key_mods() } event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Right, modifiers: event::get_key_mods() }
@ -583,6 +620,9 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
use events::WindowEvent::MouseInput; use events::WindowEvent::MouseInput;
use events::MouseButton::Right; use events::MouseButton::Right;
use events::ElementState::Released; use events::ElementState::Released;
release_mouse();
send_event(Event::WindowEvent { send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)), window_id: SuperWindowId(WindowId(window)),
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Right, modifiers: event::get_key_mods() } event: MouseInput { device_id: DEVICE_ID, state: Released, button: Right, modifiers: event::get_key_mods() }
@ -594,6 +634,9 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
use events::WindowEvent::MouseInput; use events::WindowEvent::MouseInput;
use events::MouseButton::Middle; use events::MouseButton::Middle;
use events::ElementState::Pressed; use events::ElementState::Pressed;
capture_mouse(window);
send_event(Event::WindowEvent { send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)), window_id: SuperWindowId(WindowId(window)),
event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Middle, modifiers: event::get_key_mods() } event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Middle, modifiers: event::get_key_mods() }
@ -605,6 +648,9 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
use events::WindowEvent::MouseInput; use events::WindowEvent::MouseInput;
use events::MouseButton::Middle; use events::MouseButton::Middle;
use events::ElementState::Released; use events::ElementState::Released;
release_mouse();
send_event(Event::WindowEvent { send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)), window_id: SuperWindowId(WindowId(window)),
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Middle, modifiers: event::get_key_mods() } event: MouseInput { device_id: DEVICE_ID, state: Released, button: Middle, modifiers: event::get_key_mods() }
@ -617,6 +663,9 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
use events::MouseButton::Other; use events::MouseButton::Other;
use events::ElementState::Pressed; use events::ElementState::Pressed;
let xbutton = winuser::GET_XBUTTON_WPARAM(wparam); let xbutton = winuser::GET_XBUTTON_WPARAM(wparam);
capture_mouse(window);
send_event(Event::WindowEvent { send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)), window_id: SuperWindowId(WindowId(window)),
event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Other(xbutton as u8), modifiers: event::get_key_mods() } event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Other(xbutton as u8), modifiers: event::get_key_mods() }
@ -629,6 +678,9 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
use events::MouseButton::Other; use events::MouseButton::Other;
use events::ElementState::Released; use events::ElementState::Released;
let xbutton = winuser::GET_XBUTTON_WPARAM(wparam); let xbutton = winuser::GET_XBUTTON_WPARAM(wparam);
release_mouse();
send_event(Event::WindowEvent { send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)), window_id: SuperWindowId(WindowId(window)),
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Other(xbutton as u8), modifiers: event::get_key_mods() } event: MouseInput { device_id: DEVICE_ID, state: Released, button: Other(xbutton as u8), modifiers: event::get_key_mods() }