From 1274b1c08ff21b454cba32b82ffbc1ccd8871239 Mon Sep 17 00:00:00 2001 From: Fredemus Date: Mon, 2 Oct 2023 02:58:07 +0200 Subject: [PATCH 1/2] Add logic for CursorEntered/CursorLeft on Windows --- src/win/window.rs | 53 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/src/win/window.rs b/src/win/window.rs index 2c68b99c..7959ad7c 100644 --- a/src/win/window.rs +++ b/src/win/window.rs @@ -2,23 +2,23 @@ use winapi::shared::guiddef::GUID; use winapi::shared::minwindef::{ATOM, FALSE, LPARAM, LRESULT, UINT, WPARAM}; use winapi::shared::windef::{HWND, RECT}; use winapi::um::combaseapi::CoCreateGuid; -use winapi::um::ole2::{RegisterDragDrop, OleInitialize, RevokeDragDrop}; +use winapi::um::ole2::{OleInitialize, RegisterDragDrop, RevokeDragDrop}; use winapi::um::oleidl::LPDROPTARGET; use winapi::um::winuser::{ AdjustWindowRectEx, CreateWindowExW, DefWindowProcW, DestroyWindow, DispatchMessageW, GetDpiForWindow, GetMessageW, GetWindowLongPtrW, LoadCursorW, PostMessageW, RegisterClassW, ReleaseCapture, SetCapture, SetProcessDpiAwarenessContext, SetTimer, SetWindowLongPtrW, - SetWindowPos, TranslateMessage, UnregisterClassW, CS_OWNDC, GET_XBUTTON_WPARAM, GWLP_USERDATA, - IDC_ARROW, MSG, SWP_NOMOVE, SWP_NOZORDER, WHEEL_DELTA, WM_CHAR, WM_CLOSE, WM_CREATE, - WM_DPICHANGED, WM_INPUTLANGCHANGE, WM_KEYDOWN, WM_KEYUP, WM_LBUTTONDOWN, WM_LBUTTONUP, - WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MOUSEHWHEEL, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_NCDESTROY, - WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SHOWWINDOW, WM_SIZE, WM_SYSCHAR, WM_SYSKEYDOWN, WM_SYSKEYUP, - WM_TIMER, WM_USER, WM_XBUTTONDOWN, WM_XBUTTONUP, WNDCLASSW, WS_CAPTION, WS_CHILD, - WS_CLIPSIBLINGS, WS_MAXIMIZEBOX, WS_MINIMIZEBOX, WS_POPUPWINDOW, WS_SIZEBOX, WS_VISIBLE, - XBUTTON1, XBUTTON2, + SetWindowPos, TrackMouseEvent, TranslateMessage, UnregisterClassW, CS_OWNDC, + GET_XBUTTON_WPARAM, GWLP_USERDATA, IDC_ARROW, MSG, SWP_NOMOVE, SWP_NOZORDER, TRACKMOUSEEVENT, + WHEEL_DELTA, WM_CHAR, WM_CLOSE, WM_CREATE, WM_DPICHANGED, WM_INPUTLANGCHANGE, WM_KEYDOWN, + WM_KEYUP, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MOUSEHWHEEL, + WM_MOUSELEAVE, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_NCDESTROY, WM_RBUTTONDOWN, WM_RBUTTONUP, + WM_SHOWWINDOW, WM_SIZE, WM_SYSCHAR, WM_SYSKEYDOWN, WM_SYSKEYUP, WM_TIMER, WM_USER, + WM_XBUTTONDOWN, WM_XBUTTONUP, WNDCLASSW, WS_CAPTION, WS_CHILD, WS_CLIPSIBLINGS, WS_MAXIMIZEBOX, + WS_MINIMIZEBOX, WS_POPUPWINDOW, WS_SIZEBOX, WS_VISIBLE, XBUTTON1, XBUTTON2, }; -use std::cell::{Cell, RefCell, Ref, RefMut}; +use std::cell::{Cell, Ref, RefCell, RefMut}; use std::collections::VecDeque; use std::ffi::{c_void, OsStr}; use std::marker::PhantomData; @@ -175,22 +175,51 @@ unsafe fn wnd_proc_inner( WM_MOUSEMOVE => { let mut window = window_state.create_window(); let mut window = crate::Window::new(&mut window); + let mut handler = window_state.handler.borrow_mut(); + let handler = handler.as_mut().unwrap(); + + let mut mouse_was_outside_window = window_state.mouse_was_outside_window.borrow_mut(); + if *mouse_was_outside_window { + // this makes Windows track whether the mouse leaves the window. + // When the mouse leaves it results in a `WM_MOUSELEAVE` event. + let track_mouse = Rc::new(TRACKMOUSEEVENT { + cbSize: std::mem::size_of::() as u32, + dwFlags: winapi::um::winuser::TME_LEAVE, + hwndTrack: hwnd, + dwHoverTime: winapi::um::winuser::HOVER_DEFAULT, + }); + // Couldn't find a good way to track whether the mouse enters, + // but if `WM_MOUSEMOVE` happens, the mouse must have entered. + TrackMouseEvent(Rc::as_ptr(&track_mouse) as winapi::um::winuser::LPTRACKMOUSEEVENT); + *mouse_was_outside_window = false; + + let enter_event = Event::Mouse(MouseEvent::CursorEntered); + handler.on_event(&mut window, enter_event); + } let x = (lparam & 0xFFFF) as i16 as i32; let y = ((lparam >> 16) & 0xFFFF) as i16 as i32; let physical_pos = PhyPoint { x, y }; let logical_pos = physical_pos.to_logical(&window_state.window_info.borrow()); - let event = Event::Mouse(MouseEvent::CursorMoved { + let move_event = Event::Mouse(MouseEvent::CursorMoved { position: logical_pos, modifiers: window_state .keyboard_state .borrow() .get_modifiers_from_mouse_wparam(wparam), }); + handler.on_event(&mut window, move_event); + Some(0) + } + WM_MOUSELEAVE => { + let mut window = window_state.create_window(); + let mut window = crate::Window::new(&mut window); + let event = Event::Mouse(MouseEvent::CursorLeft); window_state.handler.borrow_mut().as_mut().unwrap().on_event(&mut window, event); + *window_state.mouse_was_outside_window.borrow_mut() = true; Some(0) } WM_MOUSEWHEEL | WM_MOUSEHWHEEL => { @@ -460,6 +489,7 @@ pub(super) struct WindowState { _parent_handle: Option, keyboard_state: RefCell, mouse_button_counter: Cell, + mouse_was_outside_window: RefCell, // Initialized late so the `Window` can hold a reference to this `WindowState` handler: RefCell>>, _drop_target: RefCell>>, @@ -678,6 +708,7 @@ impl Window<'_> { _parent_handle: parent_handle, keyboard_state: RefCell::new(KeyboardState::new()), mouse_button_counter: Cell::new(0), + mouse_was_outside_window: RefCell::new(true), // The Window refers to this `WindowState`, so this `handler` needs to be // initialized later handler: RefCell::new(None), From 475bd5f88a2e2ea72601039f69b68c0380c9d9e0 Mon Sep 17 00:00:00 2001 From: Fredemus Date: Sat, 28 Oct 2023 17:35:26 +0200 Subject: [PATCH 2/2] remove unneeded allocation --- src/win/window.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/win/window.rs b/src/win/window.rs index 7959ad7c..0a92ba80 100644 --- a/src/win/window.rs +++ b/src/win/window.rs @@ -182,15 +182,15 @@ unsafe fn wnd_proc_inner( if *mouse_was_outside_window { // this makes Windows track whether the mouse leaves the window. // When the mouse leaves it results in a `WM_MOUSELEAVE` event. - let track_mouse = Rc::new(TRACKMOUSEEVENT { + let mut track_mouse =TRACKMOUSEEVENT { cbSize: std::mem::size_of::() as u32, dwFlags: winapi::um::winuser::TME_LEAVE, hwndTrack: hwnd, dwHoverTime: winapi::um::winuser::HOVER_DEFAULT, - }); + }; // Couldn't find a good way to track whether the mouse enters, // but if `WM_MOUSEMOVE` happens, the mouse must have entered. - TrackMouseEvent(Rc::as_ptr(&track_mouse) as winapi::um::winuser::LPTRACKMOUSEEVENT); + TrackMouseEvent(&mut track_mouse); *mouse_was_outside_window = false; let enter_event = Event::Mouse(MouseEvent::CursorEntered);