use {
crate::{
high_word,
signed_high_word,
signed_low_word,
user::{
LParam,
WParam,
},
},
dpi::PhysicalPosition,
keyboard_types::Modifiers,
pointer_types::{
ButtonState,
mouse::{
MouseButton,
MouseEvent,
},
},
windows_sys::Win32::{
System::SystemServices::{
MK_LBUTTON,
MK_MBUTTON,
MK_RBUTTON,
MK_XBUTTON1,
MK_XBUTTON2,
},
UI::WindowsAndMessaging,
},
};
pub(crate) fn mouse_event(message: u32, w_param: WParam, l_param: LParam) -> MouseEvent {
let flags = w_param.0 as u32;
let button: MouseButton = {
match message {
WindowsAndMessaging::WM_LBUTTONDBLCLK
| WindowsAndMessaging::WM_LBUTTONDOWN
| WindowsAndMessaging::WM_LBUTTONUP => MouseButton::Left,
WindowsAndMessaging::WM_MBUTTONDBLCLK
| WindowsAndMessaging::WM_MBUTTONDOWN
| WindowsAndMessaging::WM_MBUTTONUP => MouseButton::Middle,
WindowsAndMessaging::WM_RBUTTONDBLCLK
| WindowsAndMessaging::WM_RBUTTONDOWN
| WindowsAndMessaging::WM_RBUTTONUP => MouseButton::Right,
WindowsAndMessaging::WM_XBUTTONDBLCLK
| WindowsAndMessaging::WM_XBUTTONDOWN
| WindowsAndMessaging::WM_XBUTTONUP => {
let hi_flags = high_word(flags);
if (hi_flags & WindowsAndMessaging::XBUTTON1) == WindowsAndMessaging::XBUTTON1 {
MouseButton::Back
} else {
MouseButton::Forward
}
},
_ => unimplemented!("Unexpected mouse message: {message}"),
}
};
let is_double_click = matches!(
message,
WindowsAndMessaging::WM_LBUTTONDBLCLK
| WindowsAndMessaging::WM_MBUTTONDBLCLK
| WindowsAndMessaging::WM_RBUTTONDBLCLK
| WindowsAndMessaging::WM_XBUTTONDBLCLK
);
let state = {
let mod_flags = flags;
let is_l_down = (mod_flags & MK_LBUTTON) == MK_LBUTTON;
let is_m_down = (mod_flags & MK_MBUTTON) == MK_MBUTTON;
let is_r_down = (mod_flags & MK_RBUTTON) == MK_RBUTTON;
let is_x1_down = (mod_flags & MK_XBUTTON1) == MK_XBUTTON1;
let is_x2_down = (mod_flags & MK_XBUTTON2) == MK_XBUTTON2;
let is_down = match message {
WindowsAndMessaging::WM_LBUTTONDBLCLK | WindowsAndMessaging::WM_LBUTTONDOWN if is_l_down => true,
WindowsAndMessaging::WM_MBUTTONDBLCLK | WindowsAndMessaging::WM_MBUTTONDOWN if is_m_down => true,
WindowsAndMessaging::WM_RBUTTONDBLCLK | WindowsAndMessaging::WM_RBUTTONDOWN if is_r_down => true,
WindowsAndMessaging::WM_XBUTTONDBLCLK | WindowsAndMessaging::WM_XBUTTONDOWN if is_x1_down || is_x2_down => true,
_ => false,
};
if is_down { ButtonState::Down } else { ButtonState::Up }
};
let (x, y) = (signed_low_word(l_param.0 as i32), signed_high_word(l_param.0 as i32));
let position = PhysicalPosition::new(x as f64, y as f64);
MouseEvent::Button {
position,
state,
button,
modifiers: Modifiers::empty(), is_double_click,
}
}