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),