@@ -7,6 +7,7 @@ use windows::Win32::{
Graphics::Gdi::*,
System::SystemServices::*,
UI::{
+ Controls::*,
HiDpi::*,
Input::{Ime::*, KeyboardAndMouse::*},
WindowsAndMessaging::*,
@@ -43,7 +44,8 @@ pub(crate) fn handle_msg(
WM_PAINT => handle_paint_msg(handle, state_ptr),
WM_CLOSE => handle_close_msg(state_ptr),
WM_DESTROY => handle_destroy_msg(handle, state_ptr),
- WM_MOUSEMOVE => handle_mouse_move_msg(lparam, wparam, state_ptr),
+ WM_MOUSEMOVE => handle_mouse_move_msg(handle, lparam, wparam, state_ptr),
+ WM_MOUSELEAVE => handle_mouse_leave_msg(state_ptr),
WM_NCMOUSEMOVE => handle_nc_mouse_move_msg(handle, lparam, state_ptr),
WM_NCLBUTTONDOWN => {
handle_nc_mouse_down_msg(handle, MouseButton::Left, wparam, lparam, state_ptr)
@@ -234,10 +236,32 @@ fn handle_destroy_msg(handle: HWND, state_ptr: Rc<WindowsWindowStatePtr>) -> Opt
}
fn handle_mouse_move_msg(
+ handle: HWND,
lparam: LPARAM,
wparam: WPARAM,
state_ptr: Rc<WindowsWindowStatePtr>,
) -> Option<isize> {
+ let mut lock = state_ptr.state.borrow_mut();
+ if !lock.hovered {
+ lock.hovered = true;
+ unsafe {
+ TrackMouseEvent(&mut TRACKMOUSEEVENT {
+ cbSize: std::mem::size_of::<TRACKMOUSEEVENT>() as u32,
+ dwFlags: TME_LEAVE,
+ hwndTrack: handle,
+ dwHoverTime: HOVER_DEFAULT,
+ })
+ .log_err()
+ };
+ if let Some(mut callback) = lock.callbacks.hovered_status_change.take() {
+ drop(lock);
+ callback(true);
+ state_ptr.state.borrow_mut().callbacks.hovered_status_change = Some(callback);
+ }
+ } else {
+ drop(lock);
+ }
+
let mut lock = state_ptr.state.borrow_mut();
if let Some(mut callback) = lock.callbacks.input.take() {
let scale_factor = lock.scale_factor;
@@ -272,6 +296,18 @@ fn handle_mouse_move_msg(
Some(1)
}
+fn handle_mouse_leave_msg(state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> {
+ let mut lock = state_ptr.state.borrow_mut();
+ lock.hovered = false;
+ if let Some(mut callback) = lock.callbacks.hovered_status_change.take() {
+ drop(lock);
+ callback(false);
+ state_ptr.state.borrow_mut().callbacks.hovered_status_change = Some(callback);
+ }
+
+ Some(0)
+}
+
fn handle_syskeydown_msg(
wparam: WPARAM,
lparam: LPARAM,
@@ -42,6 +42,7 @@ pub struct WindowsWindowState {
pub callbacks: Callbacks,
pub input_handler: Option<PlatformInputHandler>,
pub system_key_handled: bool,
+ pub hovered: bool,
pub renderer: BladeRenderer,
@@ -95,6 +96,7 @@ impl WindowsWindowState {
let callbacks = Callbacks::default();
let input_handler = None;
let system_key_handled = false;
+ let hovered = false;
let click_state = ClickState::new();
let system_settings = WindowsSystemSettings::new(display);
let nc_button_pressed = None;
@@ -110,6 +112,7 @@ impl WindowsWindowState {
callbacks,
input_handler,
system_key_handled,
+ hovered,
renderer,
click_state,
system_settings,
@@ -326,6 +329,7 @@ pub(crate) struct Callbacks {
pub(crate) request_frame: Option<Box<dyn FnMut(RequestFrameOptions)>>,
pub(crate) input: Option<Box<dyn FnMut(crate::PlatformInput) -> DispatchEventResult>>,
pub(crate) active_status_change: Option<Box<dyn FnMut(bool)>>,
+ pub(crate) hovered_status_change: Option<Box<dyn FnMut(bool)>>,
pub(crate) resize: Option<Box<dyn FnMut(Size<Pixels>, f32)>>,
pub(crate) moved: Option<Box<dyn FnMut()>>,
pub(crate) should_close: Option<Box<dyn FnMut() -> bool>>,
@@ -635,9 +639,8 @@ impl PlatformWindow for WindowsWindow {
self.0.hwnd == unsafe { GetActiveWindow() }
}
- // is_hovered is unused on Windows. See WindowContext::is_window_hovered.
fn is_hovered(&self) -> bool {
- false
+ self.0.state.borrow().hovered
}
fn set_title(&mut self, title: &str) {
@@ -728,7 +731,9 @@ impl PlatformWindow for WindowsWindow {
self.0.state.borrow_mut().callbacks.active_status_change = Some(callback);
}
- fn on_hover_status_change(&self, _: Box<dyn FnMut(bool)>) {}
+ fn on_hover_status_change(&self, callback: Box<dyn FnMut(bool)>) {
+ self.0.state.borrow_mut().callbacks.hovered_status_change = Some(callback);
+ }
fn on_resize(&self, callback: Box<dyn FnMut(Size<Pixels>, f32)>) {
self.0.state.borrow_mut().callbacks.resize = Some(callback);
@@ -1241,7 +1241,11 @@ impl<'a> WindowContext<'a> {
/// that currently owns the mouse cursor.
/// On mac, this is equivalent to `is_window_active`.
pub fn is_window_hovered(&self) -> bool {
- if cfg!(any(target_os = "linux", target_os = "freebsd")) {
+ if cfg!(any(
+ target_os = "windows",
+ target_os = "linux",
+ target_os = "freebsd"
+ )) {
self.window.hovered.get()
} else {
self.is_window_active()