Skip to content

Commit 26b019d

Browse files
authored
Merge pull request #150 from Fredemus/feature/windows-cursor-enter-leave
Add logic for CursorEntered/CursorLeft on Windows
2 parents 2c1b1a7 + d8cedc8 commit 26b019d

1 file changed

Lines changed: 37 additions & 9 deletions

File tree

src/win/window.rs

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ use winapi::um::winuser::{
88
AdjustWindowRectEx, CreateWindowExW, DefWindowProcW, DestroyWindow, DispatchMessageW,
99
GetDpiForWindow, GetMessageW, GetWindowLongPtrW, LoadCursorW, PostMessageW, RegisterClassW,
1010
ReleaseCapture, SetCapture, SetProcessDpiAwarenessContext, SetTimer, SetWindowLongPtrW,
11-
SetWindowPos, TranslateMessage, UnregisterClassW, CS_OWNDC, GET_XBUTTON_WPARAM, GWLP_USERDATA,
12-
IDC_ARROW, MSG, SWP_NOMOVE, SWP_NOZORDER, WHEEL_DELTA, WM_CHAR, WM_CLOSE, WM_CREATE,
13-
WM_DPICHANGED, WM_INPUTLANGCHANGE, WM_KEYDOWN, WM_KEYUP, WM_LBUTTONDOWN, WM_LBUTTONUP,
14-
WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MOUSEHWHEEL, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_NCDESTROY,
15-
WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SHOWWINDOW, WM_SIZE, WM_SYSCHAR, WM_SYSKEYDOWN, WM_SYSKEYUP,
16-
WM_TIMER, WM_USER, WM_XBUTTONDOWN, WM_XBUTTONUP, WNDCLASSW, WS_CAPTION, WS_CHILD,
17-
WS_CLIPSIBLINGS, WS_MAXIMIZEBOX, WS_MINIMIZEBOX, WS_POPUPWINDOW, WS_SIZEBOX, WS_VISIBLE,
18-
XBUTTON1, XBUTTON2,
11+
SetWindowPos, TrackMouseEvent, TranslateMessage, UnregisterClassW, CS_OWNDC,
12+
GET_XBUTTON_WPARAM, GWLP_USERDATA, IDC_ARROW, MSG, SWP_NOMOVE, SWP_NOZORDER, TRACKMOUSEEVENT,
13+
WHEEL_DELTA, WM_CHAR, WM_CLOSE, WM_CREATE, WM_DPICHANGED, WM_INPUTLANGCHANGE, WM_KEYDOWN,
14+
WM_KEYUP, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MOUSEHWHEEL,
15+
WM_MOUSELEAVE, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_NCDESTROY, WM_RBUTTONDOWN, WM_RBUTTONUP,
16+
WM_SHOWWINDOW, WM_SIZE, WM_SYSCHAR, WM_SYSKEYDOWN, WM_SYSKEYUP, WM_TIMER, WM_USER,
17+
WM_XBUTTONDOWN, WM_XBUTTONUP, WNDCLASSW, WS_CAPTION, WS_CHILD, WS_CLIPSIBLINGS, WS_MAXIMIZEBOX,
18+
WS_MINIMIZEBOX, WS_POPUPWINDOW, WS_SIZEBOX, WS_VISIBLE, XBUTTON1, XBUTTON2,
1919
};
2020

2121
use std::cell::{Cell, Ref, RefCell, RefMut};
@@ -170,21 +170,47 @@ unsafe fn wnd_proc_inner(
170170
WM_MOUSEMOVE => {
171171
let mut window = crate::Window::new(window_state.create_window());
172172

173+
let mut mouse_was_outside_window = window_state.mouse_was_outside_window.borrow_mut();
174+
if *mouse_was_outside_window {
175+
// this makes Windows track whether the mouse leaves the window.
176+
// When the mouse leaves it results in a `WM_MOUSELEAVE` event.
177+
let mut track_mouse =TRACKMOUSEEVENT {
178+
cbSize: std::mem::size_of::<TRACKMOUSEEVENT>() as u32,
179+
dwFlags: winapi::um::winuser::TME_LEAVE,
180+
hwndTrack: hwnd,
181+
dwHoverTime: winapi::um::winuser::HOVER_DEFAULT,
182+
};
183+
// Couldn't find a good way to track whether the mouse enters,
184+
// but if `WM_MOUSEMOVE` happens, the mouse must have entered.
185+
TrackMouseEvent(&mut track_mouse);
186+
*mouse_was_outside_window = false;
187+
188+
let enter_event = Event::Mouse(MouseEvent::CursorEntered);
189+
window_state.handler.borrow_mut().as_mut().unwrap().on_event(&mut window, enter_event);
190+
}
191+
173192
let x = (lparam & 0xFFFF) as i16 as i32;
174193
let y = ((lparam >> 16) & 0xFFFF) as i16 as i32;
175194

176195
let physical_pos = PhyPoint { x, y };
177196
let logical_pos = physical_pos.to_logical(&window_state.window_info.borrow());
178-
let event = Event::Mouse(MouseEvent::CursorMoved {
197+
let move_event = Event::Mouse(MouseEvent::CursorMoved {
179198
position: logical_pos,
180199
modifiers: window_state
181200
.keyboard_state
182201
.borrow()
183202
.get_modifiers_from_mouse_wparam(wparam),
184203
});
204+
window_state.handler.borrow_mut().as_mut().unwrap().on_event(&mut window, move_event);
205+
Some(0)
206+
}
185207

208+
WM_MOUSELEAVE => {
209+
let mut window = crate::Window::new(window_state.create_window());
210+
let event = Event::Mouse(MouseEvent::CursorLeft);
186211
window_state.handler.borrow_mut().as_mut().unwrap().on_event(&mut window, event);
187212

213+
*window_state.mouse_was_outside_window.borrow_mut() = true;
188214
Some(0)
189215
}
190216
WM_MOUSEWHEEL | WM_MOUSEHWHEEL => {
@@ -448,6 +474,7 @@ pub(super) struct WindowState {
448474
_parent_handle: Option<ParentHandle>,
449475
keyboard_state: RefCell<KeyboardState>,
450476
mouse_button_counter: Cell<usize>,
477+
mouse_was_outside_window: RefCell<bool>,
451478
// Initialized late so the `Window` can hold a reference to this `WindowState`
452479
handler: RefCell<Option<Box<dyn WindowHandler>>>,
453480
_drop_target: RefCell<Option<Rc<DropTarget>>>,
@@ -655,6 +682,7 @@ impl Window<'_> {
655682
_parent_handle: parent_handle,
656683
keyboard_state: RefCell::new(KeyboardState::new()),
657684
mouse_button_counter: Cell::new(0),
685+
mouse_was_outside_window: RefCell::new(true),
658686
// The Window refers to this `WindowState`, so this `handler` needs to be
659687
// initialized later
660688
handler: RefCell::new(None),

0 commit comments

Comments
 (0)