1#![allow(non_snake_case)]
2
3mod runner;
4
5use parking_lot::Mutex;
6use std::{
7 cell::Cell,
8 collections::VecDeque,
9 marker::PhantomData,
10 mem, panic, ptr,
11 rc::Rc,
12 sync::{
13 mpsc::{self, Receiver, Sender},
14 Arc,
15 },
16 thread,
17 time::{Duration, Instant},
18};
19use winapi::shared::basetsd::{DWORD_PTR, UINT_PTR};
20
21use winapi::{
22 shared::{
23 minwindef::{BOOL, DWORD, HIWORD, INT, LOWORD, LPARAM, LRESULT, UINT, WORD, WPARAM},
24 windef::{HWND, POINT, RECT},
25 windowsx, winerror,
26 },
27 um::{
28 commctrl, libloaderapi, ole2, processthreadsapi, winbase,
29 winnt::{HANDLE, LONG, LPCSTR, SHORT},
30 winuser,
31 },
32};
33
34use crate::{
35 dpi::{PhysicalPosition, PhysicalSize},
36 event::{DeviceEvent, Event, Force, KeyboardInput, Touch, TouchPhase, WindowEvent},
37 event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW},
38 monitor::MonitorHandle as RootMonitorHandle,
39 platform_impl::platform::{
40 dark_mode::try_theme,
41 dpi::{become_dpi_aware, dpi_to_scale_factor, enable_non_client_dpi_scaling},
42 drop_handler::FileDropHandler,
43 event::{self, handle_extended_keys, process_key_params, vkey_to_winit_vkey},
44 monitor::{self, MonitorHandle},
45 raw_input, util,
46 window_state::{CursorFlags, WindowFlags, WindowState},
47 wrap_device_id, WindowId, DEVICE_ID,
48 },
49 window::{Fullscreen, WindowId as RootWindowId},
50};
51use runner::{EventLoopRunner, EventLoopRunnerShared};
52
53type GetPointerFrameInfoHistory = unsafe extern "system" fn(
54 pointerId: UINT,
55 entriesCount: *mut UINT,
56 pointerCount: *mut UINT,
57 pointerInfo: *mut winuser::POINTER_INFO,
58) -> BOOL;
59
60type SkipPointerFrameMessages = unsafe extern "system" fn(pointerId: UINT) -> BOOL;
61type GetPointerDeviceRects = unsafe extern "system" fn(
62 device: HANDLE,
63 pointerDeviceRect: *mut RECT,
64 displayRect: *mut RECT,
65) -> BOOL;
66
67type GetPointerTouchInfo =
68 unsafe extern "system" fn(pointerId: UINT, touchInfo: *mut winuser::POINTER_TOUCH_INFO) -> BOOL;
69
70type GetPointerPenInfo =
71 unsafe extern "system" fn(pointId: UINT, penInfo: *mut winuser::POINTER_PEN_INFO) -> BOOL;
72
73lazy_static! {
74 static ref GET_POINTER_FRAME_INFO_HISTORY: Option<GetPointerFrameInfoHistory> =
75 get_function!("user32.dll", GetPointerFrameInfoHistory);
76 static ref SKIP_POINTER_FRAME_MESSAGES: Option<SkipPointerFrameMessages> =
77 get_function!("user32.dll", SkipPointerFrameMessages);
78 static ref GET_POINTER_DEVICE_RECTS: Option<GetPointerDeviceRects> =
79 get_function!("user32.dll", GetPointerDeviceRects);
80 static ref GET_POINTER_TOUCH_INFO: Option<GetPointerTouchInfo> =
81 get_function!("user32.dll", GetPointerTouchInfo);
82 static ref GET_POINTER_PEN_INFO: Option<GetPointerPenInfo> =
83 get_function!("user32.dll", GetPointerPenInfo);
84}
85
86pub(crate) struct SubclassInput<T: 'static> {
87 pub window_state: Arc<Mutex<WindowState>>,
88 pub event_loop_runner: EventLoopRunnerShared<T>,
89 pub file_drop_handler: Option<FileDropHandler>,
90 pub subclass_removed: Cell<bool>,
91 pub recurse_depth: Cell<u32>,
92}
93
94impl<T> SubclassInput<T> {
95 unsafe fn send_event(&self, event: Event<'_, T>) {
96 self.event_loop_runner.send_event(event);
97 }
98}
99
100struct ThreadMsgTargetSubclassInput<T: 'static> {
101 event_loop_runner: EventLoopRunnerShared<T>,
102 user_event_receiver: Receiver<T>,
103}
104
105impl<T> ThreadMsgTargetSubclassInput<T> {
106 unsafe fn send_event(&self, event: Event<'_, T>) {
107 self.event_loop_runner.send_event(event);
108 }
109}
110
111pub struct EventLoop<T: 'static> {
112 thread_msg_sender: Sender<T>,
113 window_target: RootELW<T>,
114}
115
116pub struct EventLoopWindowTarget<T: 'static> {
117 thread_id: DWORD,
118 thread_msg_target: HWND,
119 pub(crate) runner_shared: EventLoopRunnerShared<T>,
120}
121
122macro_rules! main_thread_check {
123 ($fn_name:literal) => {{
124 let thread_id = unsafe { processthreadsapi::GetCurrentThreadId() };
125 if thread_id != main_thread_id() {
126 panic!(concat!(
127 "Initializing the event loop outside of the main thread is a significant \
128 cross-platform compatibility hazard. If you really, absolutely need to create an \
129 EventLoop on a different thread, please use the `EventLoopExtWindows::",
130 $fn_name,
131 "` function."
132 ));
133 }
134 }};
135}
136
137impl<T: 'static> EventLoop<T> {
138 pub fn new() -> EventLoop<T> {
139 main_thread_check!("new_any_thread");
140
141 Self::new_any_thread()
142 }
143
144 pub fn new_any_thread() -> EventLoop<T> {
145 become_dpi_aware();
146 Self::new_dpi_unaware_any_thread()
147 }
148
149 pub fn new_dpi_unaware() -> EventLoop<T> {
150 main_thread_check!("new_dpi_unaware_any_thread");
151
152 Self::new_dpi_unaware_any_thread()
153 }
154
155 pub fn new_dpi_unaware_any_thread() -> EventLoop<T> {
156 let thread_id = unsafe { processthreadsapi::GetCurrentThreadId() };
157
158 let thread_msg_target = create_event_target_window();
159
160 let send_thread_msg_target = thread_msg_target as usize;
161 thread::spawn(move || wait_thread(thread_id, send_thread_msg_target as HWND));
162 let wait_thread_id = get_wait_thread_id();
163
164 let runner_shared = Rc::new(EventLoopRunner::new(thread_msg_target, wait_thread_id));
165
166 let thread_msg_sender =
167 subclass_event_target_window(thread_msg_target, runner_shared.clone());
168 raw_input::register_all_mice_and_keyboards_for_raw_input(thread_msg_target);
169
170 EventLoop {
171 thread_msg_sender,
172 window_target: RootELW {
173 p: EventLoopWindowTarget {
174 thread_id,
175 thread_msg_target,
176 runner_shared,
177 },
178 _marker: PhantomData,
179 },
180 }
181 }
182
183 pub fn window_target(&self) -> &RootELW<T> {
184 &self.window_target
185 }
186
187 pub fn run<F>(mut self, event_handler: F) -> !
188 where
189 F: 'static + FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
190 {
191 self.run_return(event_handler);
192 ::std::process::exit(0);
193 }
194
195 pub fn run_return<F>(&mut self, mut event_handler: F)
196 where
197 F: FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
198 {
199 let event_loop_windows_ref = &self.window_target;
200
201 unsafe {
202 self.window_target
203 .p
204 .runner_shared
205 .set_event_handler(move |event, control_flow| {
206 event_handler(event, event_loop_windows_ref, control_flow)
207 });
208 }
209
210 let runner = &self.window_target.p.runner_shared;
211
212 unsafe {
213 let mut msg = mem::zeroed();
214
215 runner.poll();
216 'main: loop {
217 if 0 == winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) {
218 break 'main;
219 }
220 winuser::TranslateMessage(&mut msg);
221 winuser::DispatchMessageW(&mut msg);
222
223 if let Err(payload) = runner.take_panic_error() {
224 runner.reset_runner();
225 panic::resume_unwind(payload);
226 }
227
228 if runner.control_flow() == ControlFlow::Exit && !runner.handling_events() {
229 break 'main;
230 }
231 }
232 }
233
234 unsafe {
235 runner.loop_destroyed();
236 }
237 runner.reset_runner();
238 }
239
240 pub fn create_proxy(&self) -> EventLoopProxy<T> {
241 EventLoopProxy {
242 target_window: self.window_target.p.thread_msg_target,
243 event_send: self.thread_msg_sender.clone(),
244 }
245 }
246}
247
248impl<T> EventLoopWindowTarget<T> {
249 #[inline(always)]
250 pub(crate) fn create_thread_executor(&self) -> EventLoopThreadExecutor {
251 EventLoopThreadExecutor {
252 thread_id: self.thread_id,
253 target_window: self.thread_msg_target,
254 }
255 }
256
257 pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
259 monitor::available_monitors()
260 }
261
262 pub fn primary_monitor(&self) -> Option<RootMonitorHandle> {
263 let monitor = monitor::primary_monitor();
264 Some(RootMonitorHandle { inner: monitor })
265 }
266}
267
268fn main_thread_id() -> DWORD {
269 static mut MAIN_THREAD_ID: DWORD = 0;
270 #[used]
271 #[allow(non_upper_case_globals)]
272 #[link_section = ".CRT$XCU"]
273 static INIT_MAIN_THREAD_ID: unsafe fn() = {
274 unsafe fn initer() {
275 MAIN_THREAD_ID = processthreadsapi::GetCurrentThreadId();
276 }
277 initer
278 };
279
280 unsafe { MAIN_THREAD_ID }
281}
282
283fn get_wait_thread_id() -> DWORD {
284 unsafe {
285 let mut msg = mem::zeroed();
286 let result = winuser::GetMessageW(
287 &mut msg,
288 -1 as _,
289 *SEND_WAIT_THREAD_ID_MSG_ID,
290 *SEND_WAIT_THREAD_ID_MSG_ID,
291 );
292 assert_eq!(
293 msg.message, *SEND_WAIT_THREAD_ID_MSG_ID,
294 "this shouldn't be possible. please open an issue with Winit. error code: {}",
295 result
296 );
297 msg.lParam as DWORD
298 }
299}
300
301fn wait_thread(parent_thread_id: DWORD, msg_window_id: HWND) {
302 unsafe {
303 let mut msg: winuser::MSG;
304
305 let cur_thread_id = processthreadsapi::GetCurrentThreadId();
306 winuser::PostThreadMessageW(
307 parent_thread_id,
308 *SEND_WAIT_THREAD_ID_MSG_ID,
309 0,
310 cur_thread_id as LPARAM,
311 );
312
313 let mut wait_until_opt = None;
314 'main: loop {
315 msg = mem::zeroed();
319
320 if wait_until_opt.is_some() {
321 if 0 != winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, winuser::PM_REMOVE) {
322 winuser::TranslateMessage(&mut msg);
323 winuser::DispatchMessageW(&mut msg);
324 }
325 } else {
326 if 0 == winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) {
327 break 'main;
328 } else {
329 winuser::TranslateMessage(&mut msg);
330 winuser::DispatchMessageW(&mut msg);
331 }
332 }
333
334 if msg.message == *WAIT_UNTIL_MSG_ID {
335 wait_until_opt = Some(*WaitUntilInstantBox::from_raw(msg.lParam as *mut _));
336 } else if msg.message == *CANCEL_WAIT_UNTIL_MSG_ID {
337 wait_until_opt = None;
338 }
339
340 if let Some(wait_until) = wait_until_opt {
341 let now = Instant::now();
342 if now < wait_until {
343 let resume_reason = winuser::MsgWaitForMultipleObjectsEx(
347 0,
348 ptr::null(),
349 dur2timeout(wait_until - now).saturating_sub(1),
350 winuser::QS_ALLEVENTS,
351 winuser::MWMO_INPUTAVAILABLE,
352 );
353 if resume_reason == winerror::WAIT_TIMEOUT {
354 winuser::PostMessageW(msg_window_id, *PROCESS_NEW_EVENTS_MSG_ID, 0, 0);
355 wait_until_opt = None;
356 }
357 } else {
358 winuser::PostMessageW(msg_window_id, *PROCESS_NEW_EVENTS_MSG_ID, 0, 0);
359 wait_until_opt = None;
360 }
361 }
362 }
363 }
364}
365
366fn dur2timeout(dur: Duration) -> DWORD {
368 dur.as_secs()
376 .checked_mul(1000)
377 .and_then(|ms| ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000))
378 .and_then(|ms| {
379 ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 {
380 1
381 } else {
382 0
383 })
384 })
385 .map(|ms| {
386 if ms > DWORD::max_value() as u64 {
387 winbase::INFINITE
388 } else {
389 ms as DWORD
390 }
391 })
392 .unwrap_or(winbase::INFINITE)
393}
394
395impl<T> Drop for EventLoop<T> {
396 fn drop(&mut self) {
397 unsafe {
398 winuser::DestroyWindow(self.window_target.p.thread_msg_target);
399 }
400 }
401}
402
403pub(crate) struct EventLoopThreadExecutor {
404 thread_id: DWORD,
405 target_window: HWND,
406}
407
408unsafe impl Send for EventLoopThreadExecutor {}
409unsafe impl Sync for EventLoopThreadExecutor {}
410
411impl EventLoopThreadExecutor {
412 pub(super) fn in_event_loop_thread(&self) -> bool {
414 let cur_thread_id = unsafe { processthreadsapi::GetCurrentThreadId() };
415 self.thread_id == cur_thread_id
416 }
417
418 pub(super) fn execute_in_thread<F>(&self, mut function: F)
432 where
433 F: FnMut() + Send + 'static,
434 {
435 unsafe {
436 if self.in_event_loop_thread() {
437 function();
438 } else {
439 let boxed = Box::new(function) as Box<dyn FnMut()>;
441 let boxed2: ThreadExecFn = Box::new(boxed);
442
443 let raw = Box::into_raw(boxed2);
444
445 let res = winuser::PostMessageW(
446 self.target_window,
447 *EXEC_MSG_ID,
448 raw as *mut () as usize as WPARAM,
449 0,
450 );
451 assert!(res != 0, "PostMessage failed ; is the messages queue full?");
452 }
453 }
454 }
455}
456
457type ThreadExecFn = Box<Box<dyn FnMut()>>;
458
459pub struct EventLoopProxy<T: 'static> {
460 target_window: HWND,
461 event_send: Sender<T>,
462}
463unsafe impl<T: Send + 'static> Send for EventLoopProxy<T> {}
464
465impl<T: 'static> Clone for EventLoopProxy<T> {
466 fn clone(&self) -> Self {
467 Self {
468 target_window: self.target_window,
469 event_send: self.event_send.clone(),
470 }
471 }
472}
473
474impl<T: 'static> EventLoopProxy<T> {
475 pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
476 unsafe {
477 if winuser::PostMessageW(self.target_window, *USER_EVENT_MSG_ID, 0, 0) != 0 {
478 self.event_send.send(event).ok();
479 Ok(())
480 } else {
481 Err(EventLoopClosed(event))
482 }
483 }
484 }
485}
486
487type WaitUntilInstantBox = Box<Instant>;
488
489lazy_static! {
490 static ref USER_EVENT_MSG_ID: u32 = {
493 unsafe {
494 winuser::RegisterWindowMessageA("Winit::WakeupMsg\0".as_ptr() as LPCSTR)
495 }
496 };
497 static ref EXEC_MSG_ID: u32 = {
501 unsafe {
502 winuser::RegisterWindowMessageA("Winit::ExecMsg\0".as_ptr() as *const i8)
503 }
504 };
505 static ref PROCESS_NEW_EVENTS_MSG_ID: u32 = {
506 unsafe {
507 winuser::RegisterWindowMessageA("Winit::ProcessNewEvents\0".as_ptr() as *const i8)
508 }
509 };
510 static ref SEND_WAIT_THREAD_ID_MSG_ID: u32 = {
512 unsafe {
513 winuser::RegisterWindowMessageA("Winit::SendWaitThreadId\0".as_ptr() as *const i8)
514 }
515 };
516 static ref WAIT_UNTIL_MSG_ID: u32 = {
519 unsafe {
520 winuser::RegisterWindowMessageA("Winit::WaitUntil\0".as_ptr() as *const i8)
521 }
522 };
523 static ref CANCEL_WAIT_UNTIL_MSG_ID: u32 = {
524 unsafe {
525 winuser::RegisterWindowMessageA("Winit::CancelWaitUntil\0".as_ptr() as *const i8)
526 }
527 };
528 pub static ref DESTROY_MSG_ID: u32 = {
531 unsafe {
532 winuser::RegisterWindowMessageA("Winit::DestroyMsg\0".as_ptr() as LPCSTR)
533 }
534 };
535 pub static ref SET_RETAIN_STATE_ON_SIZE_MSG_ID: u32 = unsafe {
538 winuser::RegisterWindowMessageA("Winit::SetRetainMaximized\0".as_ptr() as LPCSTR)
539 };
540 static ref THREAD_EVENT_TARGET_WINDOW_CLASS: Vec<u16> = unsafe {
541 use std::ffi::OsStr;
542 use std::os::windows::ffi::OsStrExt;
543
544 let class_name: Vec<_> = OsStr::new("Winit Thread Event Target")
545 .encode_wide()
546 .chain(Some(0).into_iter())
547 .collect();
548
549 let class = winuser::WNDCLASSEXW {
550 cbSize: mem::size_of::<winuser::WNDCLASSEXW>() as UINT,
551 style: 0,
552 lpfnWndProc: Some(winuser::DefWindowProcW),
553 cbClsExtra: 0,
554 cbWndExtra: 0,
555 hInstance: libloaderapi::GetModuleHandleW(ptr::null()),
556 hIcon: ptr::null_mut(),
557 hCursor: ptr::null_mut(), hbrBackground: ptr::null_mut(),
559 lpszMenuName: ptr::null(),
560 lpszClassName: class_name.as_ptr(),
561 hIconSm: ptr::null_mut(),
562 };
563
564 winuser::RegisterClassExW(&class);
565
566 class_name
567 };
568}
569
570fn create_event_target_window() -> HWND {
571 unsafe {
572 let window = winuser::CreateWindowExW(
573 winuser::WS_EX_NOACTIVATE | winuser::WS_EX_TRANSPARENT | winuser::WS_EX_LAYERED,
574 THREAD_EVENT_TARGET_WINDOW_CLASS.as_ptr(),
575 ptr::null_mut(),
576 0,
577 0,
578 0,
579 0,
580 0,
581 ptr::null_mut(),
582 ptr::null_mut(),
583 libloaderapi::GetModuleHandleW(ptr::null()),
584 ptr::null_mut(),
585 );
586 winuser::SetWindowLongPtrW(
587 window,
588 winuser::GWL_STYLE,
589 (winuser::WS_VISIBLE | winuser::WS_POPUP) as _,
593 );
594 window
595 }
596}
597
598fn subclass_event_target_window<T>(
599 window: HWND,
600 event_loop_runner: EventLoopRunnerShared<T>,
601) -> Sender<T> {
602 unsafe {
603 let (tx, rx) = mpsc::channel();
604
605 let subclass_input = ThreadMsgTargetSubclassInput {
606 event_loop_runner,
607 user_event_receiver: rx,
608 };
609 let input_ptr = Box::into_raw(Box::new(subclass_input));
610 let subclass_result = commctrl::SetWindowSubclass(
611 window,
612 Some(thread_event_target_callback::<T>),
613 THREAD_EVENT_TARGET_SUBCLASS_ID,
614 input_ptr as DWORD_PTR,
615 );
616 assert_eq!(subclass_result, 1);
617
618 tx
619 }
620}
621
622fn remove_event_target_window_subclass<T: 'static>(window: HWND) {
623 let removal_result = unsafe {
624 commctrl::RemoveWindowSubclass(
625 window,
626 Some(thread_event_target_callback::<T>),
627 THREAD_EVENT_TARGET_SUBCLASS_ID,
628 )
629 };
630 assert_eq!(removal_result, 1);
631}
632
633unsafe fn capture_mouse(window: HWND, window_state: &mut WindowState) {
636 window_state.mouse.capture_count += 1;
637 winuser::SetCapture(window);
638}
639
640unsafe fn release_mouse(mut window_state: parking_lot::MutexGuard<'_, WindowState>) {
643 window_state.mouse.capture_count = window_state.mouse.capture_count.saturating_sub(1);
644 if window_state.mouse.capture_count == 0 {
645 drop(window_state);
647 winuser::ReleaseCapture();
648 }
649}
650
651const WINDOW_SUBCLASS_ID: UINT_PTR = 0;
652const THREAD_EVENT_TARGET_SUBCLASS_ID: UINT_PTR = 1;
653pub(crate) fn subclass_window<T>(window: HWND, subclass_input: SubclassInput<T>) {
654 subclass_input.event_loop_runner.register_window(window);
655 let input_ptr = Box::into_raw(Box::new(subclass_input));
656 let subclass_result = unsafe {
657 commctrl::SetWindowSubclass(
658 window,
659 Some(public_window_callback::<T>),
660 WINDOW_SUBCLASS_ID,
661 input_ptr as DWORD_PTR,
662 )
663 };
664 assert_eq!(subclass_result, 1);
665}
666
667fn remove_window_subclass<T: 'static>(window: HWND) {
668 let removal_result = unsafe {
669 commctrl::RemoveWindowSubclass(
670 window,
671 Some(public_window_callback::<T>),
672 WINDOW_SUBCLASS_ID,
673 )
674 };
675 assert_eq!(removal_result, 1);
676}
677
678fn normalize_pointer_pressure(pressure: u32) -> Option<Force> {
679 match pressure {
680 1..=1024 => Some(Force::Normalized(pressure as f64 / 1024.0)),
681 _ => None,
682 }
683}
684
685#[must_use]
698unsafe fn flush_paint_messages<T: 'static>(
699 except: Option<HWND>,
700 runner: &EventLoopRunner<T>,
701) -> bool {
702 if !runner.redrawing() {
703 runner.main_events_cleared();
704 let mut msg = mem::zeroed();
705 runner.owned_windows(|redraw_window| {
706 if Some(redraw_window) == except {
707 return;
708 }
709
710 if 0 == winuser::PeekMessageW(
711 &mut msg,
712 redraw_window,
713 winuser::WM_PAINT,
714 winuser::WM_PAINT,
715 winuser::PM_REMOVE | winuser::PM_QS_PAINT,
716 ) {
717 return;
718 }
719
720 winuser::TranslateMessage(&mut msg);
721 winuser::DispatchMessageW(&mut msg);
722 });
723 true
724 } else {
725 false
726 }
727}
728
729unsafe fn process_control_flow<T: 'static>(runner: &EventLoopRunner<T>) {
730 match runner.control_flow() {
731 ControlFlow::Poll => {
732 winuser::PostMessageW(runner.thread_msg_target(), *PROCESS_NEW_EVENTS_MSG_ID, 0, 0);
733 }
734 ControlFlow::Wait => (),
735 ControlFlow::WaitUntil(until) => {
736 winuser::PostThreadMessageW(
737 runner.wait_thread_id(),
738 *WAIT_UNTIL_MSG_ID,
739 0,
740 Box::into_raw(WaitUntilInstantBox::new(until)) as LPARAM,
741 );
742 }
743 ControlFlow::Exit => (),
744 }
745}
746
747fn update_modifiers<T>(window: HWND, subclass_input: &SubclassInput<T>) {
749 use crate::event::WindowEvent::ModifiersChanged;
750
751 let modifiers = event::get_key_mods();
752 let mut window_state = subclass_input.window_state.lock();
753 if window_state.modifiers_state != modifiers {
754 window_state.modifiers_state = modifiers;
755
756 drop(window_state);
758
759 unsafe {
760 subclass_input.send_event(Event::WindowEvent {
761 window_id: RootWindowId(WindowId(window)),
762 event: ModifiersChanged(modifiers),
763 });
764 }
765 }
766}
767
768unsafe extern "system" fn public_window_callback<T: 'static>(
776 window: HWND,
777 msg: UINT,
778 wparam: WPARAM,
779 lparam: LPARAM,
780 uidsubclass: UINT_PTR,
781 subclass_input_ptr: DWORD_PTR,
782) -> LRESULT {
783 let subclass_input_ptr = subclass_input_ptr as *mut SubclassInput<T>;
784 let (result, subclass_removed, recurse_depth) = {
785 let subclass_input = &*subclass_input_ptr;
786 subclass_input
787 .recurse_depth
788 .set(subclass_input.recurse_depth.get() + 1);
789
790 let result =
791 public_window_callback_inner(window, msg, wparam, lparam, uidsubclass, subclass_input);
792
793 let subclass_removed = subclass_input.subclass_removed.get();
794 let recurse_depth = subclass_input.recurse_depth.get() - 1;
795 subclass_input.recurse_depth.set(recurse_depth);
796
797 (result, subclass_removed, recurse_depth)
798 };
799
800 if subclass_removed && recurse_depth == 0 {
801 Box::from_raw(subclass_input_ptr);
802 }
803
804 result
805}
806
807unsafe fn public_window_callback_inner<T: 'static>(
808 window: HWND,
809 msg: UINT,
810 wparam: WPARAM,
811 lparam: LPARAM,
812 _: UINT_PTR,
813 subclass_input: &SubclassInput<T>,
814) -> LRESULT {
815 winuser::RedrawWindow(
816 subclass_input.event_loop_runner.thread_msg_target(),
817 ptr::null(),
818 ptr::null_mut(),
819 winuser::RDW_INTERNALPAINT,
820 );
821
822 let callback = || match msg {
826 winuser::WM_ENTERSIZEMOVE => {
827 subclass_input
828 .window_state
829 .lock()
830 .set_window_flags_in_place(|f| f.insert(WindowFlags::MARKER_IN_SIZE_MOVE));
831 0
832 }
833
834 winuser::WM_EXITSIZEMOVE => {
835 subclass_input
836 .window_state
837 .lock()
838 .set_window_flags_in_place(|f| f.remove(WindowFlags::MARKER_IN_SIZE_MOVE));
839 0
840 }
841
842 winuser::WM_NCCREATE => {
843 enable_non_client_dpi_scaling(window);
844 commctrl::DefSubclassProc(window, msg, wparam, lparam)
845 }
846 winuser::WM_NCLBUTTONDOWN => {
847 if wparam == winuser::HTCAPTION as _ {
848 winuser::PostMessageW(window, winuser::WM_MOUSEMOVE, 0, lparam);
849 }
850 commctrl::DefSubclassProc(window, msg, wparam, lparam)
851 }
852
853 winuser::WM_CLOSE => {
854 use crate::event::WindowEvent::CloseRequested;
855 subclass_input.send_event(Event::WindowEvent {
856 window_id: RootWindowId(WindowId(window)),
857 event: CloseRequested,
858 });
859 0
860 }
861
862 winuser::WM_DESTROY => {
863 use crate::event::WindowEvent::Destroyed;
864 ole2::RevokeDragDrop(window);
865 subclass_input.send_event(Event::WindowEvent {
866 window_id: RootWindowId(WindowId(window)),
867 event: Destroyed,
868 });
869 subclass_input.event_loop_runner.remove_window(window);
870 0
871 }
872
873 winuser::WM_NCDESTROY => {
874 remove_window_subclass::<T>(window);
875 subclass_input.subclass_removed.set(true);
876 0
877 }
878
879 winuser::WM_PAINT => {
880 if subclass_input.event_loop_runner.should_buffer() {
881 winuser::RedrawWindow(
884 window,
885 ptr::null(),
886 ptr::null_mut(),
887 winuser::RDW_INTERNALPAINT,
888 );
889 } else {
890 let managing_redraw =
891 flush_paint_messages(Some(window), &subclass_input.event_loop_runner);
892 subclass_input.send_event(Event::RedrawRequested(RootWindowId(WindowId(window))));
893 if managing_redraw {
894 subclass_input.event_loop_runner.redraw_events_cleared();
895 process_control_flow(&subclass_input.event_loop_runner);
896 }
897 }
898
899 commctrl::DefSubclassProc(window, msg, wparam, lparam)
900 }
901
902 winuser::WM_WINDOWPOSCHANGING => {
903 let mut window_state = subclass_input.window_state.lock();
904 if let Some(ref mut fullscreen) = window_state.fullscreen {
905 let window_pos = &mut *(lparam as *mut winuser::WINDOWPOS);
906 let new_rect = RECT {
907 left: window_pos.x,
908 top: window_pos.y,
909 right: window_pos.x + window_pos.cx,
910 bottom: window_pos.y + window_pos.cy,
911 };
912 let new_monitor =
913 winuser::MonitorFromRect(&new_rect, winuser::MONITOR_DEFAULTTONULL);
914 match fullscreen {
915 Fullscreen::Borderless(ref mut fullscreen_monitor) => {
916 if new_monitor != ptr::null_mut()
917 && fullscreen_monitor
918 .as_ref()
919 .map(|monitor| new_monitor != monitor.inner.hmonitor())
920 .unwrap_or(true)
921 {
922 if let Ok(new_monitor_info) = monitor::get_monitor_info(new_monitor) {
923 let new_monitor_rect = new_monitor_info.rcMonitor;
924 window_pos.x = new_monitor_rect.left;
925 window_pos.y = new_monitor_rect.top;
926 window_pos.cx = new_monitor_rect.right - new_monitor_rect.left;
927 window_pos.cy = new_monitor_rect.bottom - new_monitor_rect.top;
928 }
929 *fullscreen_monitor = Some(crate::monitor::MonitorHandle {
930 inner: MonitorHandle::new(new_monitor),
931 });
932 }
933 }
934 Fullscreen::Exclusive(ref video_mode) => {
935 let old_monitor = video_mode.video_mode.monitor.hmonitor();
936 if let Ok(old_monitor_info) = monitor::get_monitor_info(old_monitor) {
937 let old_monitor_rect = old_monitor_info.rcMonitor;
938 window_pos.x = old_monitor_rect.left;
939 window_pos.y = old_monitor_rect.top;
940 window_pos.cx = old_monitor_rect.right - old_monitor_rect.left;
941 window_pos.cy = old_monitor_rect.bottom - old_monitor_rect.top;
942 }
943 }
944 }
945 }
946
947 0
948 }
949
950 winuser::WM_WINDOWPOSCHANGED => {
952 use crate::event::WindowEvent::Moved;
953
954 let windowpos = lparam as *const winuser::WINDOWPOS;
955 if (*windowpos).flags & winuser::SWP_NOMOVE != winuser::SWP_NOMOVE {
956 let physical_position =
957 PhysicalPosition::new((*windowpos).x as i32, (*windowpos).y as i32);
958 subclass_input.send_event(Event::WindowEvent {
959 window_id: RootWindowId(WindowId(window)),
960 event: Moved(physical_position),
961 });
962 }
963
964 commctrl::DefSubclassProc(window, msg, wparam, lparam)
966 }
967
968 winuser::WM_SIZE => {
969 use crate::event::WindowEvent::Resized;
970 let w = LOWORD(lparam as DWORD) as u32;
971 let h = HIWORD(lparam as DWORD) as u32;
972
973 let physical_size = PhysicalSize::new(w, h);
974 let event = Event::WindowEvent {
975 window_id: RootWindowId(WindowId(window)),
976 event: Resized(physical_size),
977 };
978
979 {
980 let mut w = subclass_input.window_state.lock();
981 if !w
983 .window_flags()
984 .contains(WindowFlags::MARKER_RETAIN_STATE_ON_SIZE)
985 {
986 let maximized = wparam == winuser::SIZE_MAXIMIZED;
987 w.set_window_flags_in_place(|f| f.set(WindowFlags::MAXIMIZED, maximized));
988 }
989 }
990
991 subclass_input.send_event(event);
992 0
993 }
994
995 winuser::WM_CHAR | winuser::WM_SYSCHAR => {
996 use crate::event::WindowEvent::ReceivedCharacter;
997 use std::char;
998 let is_high_surrogate = 0xD800 <= wparam && wparam <= 0xDBFF;
999 let is_low_surrogate = 0xDC00 <= wparam && wparam <= 0xDFFF;
1000
1001 if is_high_surrogate {
1002 subclass_input.window_state.lock().high_surrogate = Some(wparam as u16);
1003 } else if is_low_surrogate {
1004 let high_surrogate = subclass_input.window_state.lock().high_surrogate.take();
1005
1006 if let Some(high_surrogate) = high_surrogate {
1007 let pair = [high_surrogate, wparam as u16];
1008 if let Some(Ok(chr)) = char::decode_utf16(pair.iter().copied()).next() {
1009 subclass_input.send_event(Event::WindowEvent {
1010 window_id: RootWindowId(WindowId(window)),
1011 event: ReceivedCharacter(chr),
1012 });
1013 }
1014 }
1015 } else {
1016 subclass_input.window_state.lock().high_surrogate = None;
1017
1018 if let Some(chr) = char::from_u32(wparam as u32) {
1019 subclass_input.send_event(Event::WindowEvent {
1020 window_id: RootWindowId(WindowId(window)),
1021 event: ReceivedCharacter(chr),
1022 });
1023 }
1024 }
1025 0
1026 }
1027
1028 winuser::WM_SYSCOMMAND => {
1030 if wparam == winuser::SC_RESTORE {
1031 let mut w = subclass_input.window_state.lock();
1032 w.set_window_flags_in_place(|f| f.set(WindowFlags::MINIMIZED, false));
1033 }
1034 if wparam == winuser::SC_MINIMIZE {
1035 let mut w = subclass_input.window_state.lock();
1036 w.set_window_flags_in_place(|f| f.set(WindowFlags::MINIMIZED, true));
1037 }
1038 if wparam == winuser::SC_SCREENSAVE {
1041 let window_state = subclass_input.window_state.lock();
1042 if window_state.fullscreen.is_some() {
1043 return 0;
1044 }
1045 }
1046
1047 winuser::DefWindowProcW(window, msg, wparam, lparam)
1048 }
1049
1050 winuser::WM_MOUSEMOVE => {
1051 use crate::event::WindowEvent::{CursorEntered, CursorMoved};
1052 let mouse_was_outside_window = {
1053 let mut w = subclass_input.window_state.lock();
1054
1055 let was_outside_window = !w.mouse.cursor_flags().contains(CursorFlags::IN_WINDOW);
1056 w.mouse
1057 .set_cursor_flags(window, |f| f.set(CursorFlags::IN_WINDOW, true))
1058 .ok();
1059 was_outside_window
1060 };
1061
1062 if mouse_was_outside_window {
1063 subclass_input.send_event(Event::WindowEvent {
1064 window_id: RootWindowId(WindowId(window)),
1065 event: CursorEntered {
1066 device_id: DEVICE_ID,
1067 },
1068 });
1069
1070 winuser::TrackMouseEvent(&mut winuser::TRACKMOUSEEVENT {
1072 cbSize: mem::size_of::<winuser::TRACKMOUSEEVENT>() as DWORD,
1073 dwFlags: winuser::TME_LEAVE,
1074 hwndTrack: window,
1075 dwHoverTime: winuser::HOVER_DEFAULT,
1076 });
1077 }
1078
1079 let x = windowsx::GET_X_LPARAM(lparam) as f64;
1080 let y = windowsx::GET_Y_LPARAM(lparam) as f64;
1081 let position = PhysicalPosition::new(x, y);
1082 let cursor_moved;
1083 {
1084 let mut w = subclass_input.window_state.lock();
1088 cursor_moved = w.mouse.last_position != Some(position);
1089 w.mouse.last_position = Some(position);
1090 }
1091 if cursor_moved {
1092 update_modifiers(window, subclass_input);
1093
1094 subclass_input.send_event(Event::WindowEvent {
1095 window_id: RootWindowId(WindowId(window)),
1096 event: CursorMoved {
1097 device_id: DEVICE_ID,
1098 position,
1099 modifiers: event::get_key_mods(),
1100 },
1101 });
1102 }
1103
1104 0
1105 }
1106
1107 winuser::WM_MOUSELEAVE => {
1108 use crate::event::WindowEvent::CursorLeft;
1109 {
1110 let mut w = subclass_input.window_state.lock();
1111 w.mouse
1112 .set_cursor_flags(window, |f| f.set(CursorFlags::IN_WINDOW, false))
1113 .ok();
1114 }
1115
1116 subclass_input.send_event(Event::WindowEvent {
1117 window_id: RootWindowId(WindowId(window)),
1118 event: CursorLeft {
1119 device_id: DEVICE_ID,
1120 },
1121 });
1122
1123 0
1124 }
1125
1126 winuser::WM_MOUSEWHEEL => {
1127 use crate::event::MouseScrollDelta::LineDelta;
1128
1129 let value = (wparam >> 16) as i16;
1130 let value = value as i32;
1131 let value = value as f32 / winuser::WHEEL_DELTA as f32;
1132
1133 update_modifiers(window, subclass_input);
1134
1135 subclass_input.send_event(Event::WindowEvent {
1136 window_id: RootWindowId(WindowId(window)),
1137 event: WindowEvent::MouseWheel {
1138 device_id: DEVICE_ID,
1139 delta: LineDelta(0.0, value),
1140 phase: TouchPhase::Moved,
1141 modifiers: event::get_key_mods(),
1142 },
1143 });
1144
1145 0
1146 }
1147
1148 winuser::WM_MOUSEHWHEEL => {
1149 use crate::event::MouseScrollDelta::LineDelta;
1150
1151 let value = (wparam >> 16) as i16;
1152 let value = value as i32;
1153 let value = value as f32 / winuser::WHEEL_DELTA as f32;
1154
1155 update_modifiers(window, subclass_input);
1156
1157 subclass_input.send_event(Event::WindowEvent {
1158 window_id: RootWindowId(WindowId(window)),
1159 event: WindowEvent::MouseWheel {
1160 device_id: DEVICE_ID,
1161 delta: LineDelta(value, 0.0),
1162 phase: TouchPhase::Moved,
1163 modifiers: event::get_key_mods(),
1164 },
1165 });
1166
1167 0
1168 }
1169
1170 winuser::WM_KEYDOWN | winuser::WM_SYSKEYDOWN => {
1171 use crate::event::{ElementState::Pressed, VirtualKeyCode};
1172 if msg == winuser::WM_SYSKEYDOWN && wparam as i32 == winuser::VK_F4 {
1173 commctrl::DefSubclassProc(window, msg, wparam, lparam)
1174 } else {
1175 if let Some((scancode, vkey)) = process_key_params(wparam, lparam) {
1176 update_modifiers(window, subclass_input);
1177
1178 #[allow(deprecated)]
1179 subclass_input.send_event(Event::WindowEvent {
1180 window_id: RootWindowId(WindowId(window)),
1181 event: WindowEvent::KeyboardInput {
1182 device_id: DEVICE_ID,
1183 input: KeyboardInput {
1184 state: Pressed,
1185 scancode,
1186 virtual_keycode: vkey,
1187 modifiers: event::get_key_mods(),
1188 },
1189 is_synthetic: false,
1190 },
1191 });
1192 if vkey == Some(VirtualKeyCode::Delete) {
1195 subclass_input.send_event(Event::WindowEvent {
1196 window_id: RootWindowId(WindowId(window)),
1197 event: WindowEvent::ReceivedCharacter('\u{7F}'),
1198 });
1199 }
1200 }
1201 0
1202 }
1203 }
1204
1205 winuser::WM_KEYUP | winuser::WM_SYSKEYUP => {
1206 use crate::event::ElementState::Released;
1207 if let Some((scancode, vkey)) = process_key_params(wparam, lparam) {
1208 update_modifiers(window, subclass_input);
1209
1210 #[allow(deprecated)]
1211 subclass_input.send_event(Event::WindowEvent {
1212 window_id: RootWindowId(WindowId(window)),
1213 event: WindowEvent::KeyboardInput {
1214 device_id: DEVICE_ID,
1215 input: KeyboardInput {
1216 state: Released,
1217 scancode,
1218 virtual_keycode: vkey,
1219 modifiers: event::get_key_mods(),
1220 },
1221 is_synthetic: false,
1222 },
1223 });
1224 }
1225 0
1226 }
1227
1228 winuser::WM_LBUTTONDOWN => {
1229 use crate::event::{ElementState::Pressed, MouseButton::Left, WindowEvent::MouseInput};
1230
1231 capture_mouse(window, &mut *subclass_input.window_state.lock());
1232
1233 update_modifiers(window, subclass_input);
1234
1235 subclass_input.send_event(Event::WindowEvent {
1236 window_id: RootWindowId(WindowId(window)),
1237 event: MouseInput {
1238 device_id: DEVICE_ID,
1239 state: Pressed,
1240 button: Left,
1241 modifiers: event::get_key_mods(),
1242 },
1243 });
1244 0
1245 }
1246
1247 winuser::WM_LBUTTONUP => {
1248 use crate::event::{
1249 ElementState::Released, MouseButton::Left, WindowEvent::MouseInput,
1250 };
1251
1252 release_mouse(subclass_input.window_state.lock());
1253
1254 update_modifiers(window, subclass_input);
1255
1256 subclass_input.send_event(Event::WindowEvent {
1257 window_id: RootWindowId(WindowId(window)),
1258 event: MouseInput {
1259 device_id: DEVICE_ID,
1260 state: Released,
1261 button: Left,
1262 modifiers: event::get_key_mods(),
1263 },
1264 });
1265 0
1266 }
1267
1268 winuser::WM_RBUTTONDOWN => {
1269 use crate::event::{
1270 ElementState::Pressed, MouseButton::Right, WindowEvent::MouseInput,
1271 };
1272
1273 capture_mouse(window, &mut *subclass_input.window_state.lock());
1274
1275 update_modifiers(window, subclass_input);
1276
1277 subclass_input.send_event(Event::WindowEvent {
1278 window_id: RootWindowId(WindowId(window)),
1279 event: MouseInput {
1280 device_id: DEVICE_ID,
1281 state: Pressed,
1282 button: Right,
1283 modifiers: event::get_key_mods(),
1284 },
1285 });
1286 0
1287 }
1288
1289 winuser::WM_RBUTTONUP => {
1290 use crate::event::{
1291 ElementState::Released, MouseButton::Right, WindowEvent::MouseInput,
1292 };
1293
1294 release_mouse(subclass_input.window_state.lock());
1295
1296 update_modifiers(window, subclass_input);
1297
1298 subclass_input.send_event(Event::WindowEvent {
1299 window_id: RootWindowId(WindowId(window)),
1300 event: MouseInput {
1301 device_id: DEVICE_ID,
1302 state: Released,
1303 button: Right,
1304 modifiers: event::get_key_mods(),
1305 },
1306 });
1307 0
1308 }
1309
1310 winuser::WM_MBUTTONDOWN => {
1311 use crate::event::{
1312 ElementState::Pressed, MouseButton::Middle, WindowEvent::MouseInput,
1313 };
1314
1315 capture_mouse(window, &mut *subclass_input.window_state.lock());
1316
1317 update_modifiers(window, subclass_input);
1318
1319 subclass_input.send_event(Event::WindowEvent {
1320 window_id: RootWindowId(WindowId(window)),
1321 event: MouseInput {
1322 device_id: DEVICE_ID,
1323 state: Pressed,
1324 button: Middle,
1325 modifiers: event::get_key_mods(),
1326 },
1327 });
1328 0
1329 }
1330
1331 winuser::WM_MBUTTONUP => {
1332 use crate::event::{
1333 ElementState::Released, MouseButton::Middle, WindowEvent::MouseInput,
1334 };
1335
1336 release_mouse(subclass_input.window_state.lock());
1337
1338 update_modifiers(window, subclass_input);
1339
1340 subclass_input.send_event(Event::WindowEvent {
1341 window_id: RootWindowId(WindowId(window)),
1342 event: MouseInput {
1343 device_id: DEVICE_ID,
1344 state: Released,
1345 button: Middle,
1346 modifiers: event::get_key_mods(),
1347 },
1348 });
1349 0
1350 }
1351
1352 winuser::WM_XBUTTONDOWN => {
1353 use crate::event::{
1354 ElementState::Pressed, MouseButton::Other, WindowEvent::MouseInput,
1355 };
1356 let xbutton = winuser::GET_XBUTTON_WPARAM(wparam);
1357
1358 capture_mouse(window, &mut *subclass_input.window_state.lock());
1359
1360 update_modifiers(window, subclass_input);
1361
1362 subclass_input.send_event(Event::WindowEvent {
1363 window_id: RootWindowId(WindowId(window)),
1364 event: MouseInput {
1365 device_id: DEVICE_ID,
1366 state: Pressed,
1367 button: Other(xbutton),
1368 modifiers: event::get_key_mods(),
1369 },
1370 });
1371 0
1372 }
1373
1374 winuser::WM_XBUTTONUP => {
1375 use crate::event::{
1376 ElementState::Released, MouseButton::Other, WindowEvent::MouseInput,
1377 };
1378 let xbutton = winuser::GET_XBUTTON_WPARAM(wparam);
1379
1380 release_mouse(subclass_input.window_state.lock());
1381
1382 update_modifiers(window, subclass_input);
1383
1384 subclass_input.send_event(Event::WindowEvent {
1385 window_id: RootWindowId(WindowId(window)),
1386 event: MouseInput {
1387 device_id: DEVICE_ID,
1388 state: Released,
1389 button: Other(xbutton),
1390 modifiers: event::get_key_mods(),
1391 },
1392 });
1393 0
1394 }
1395
1396 winuser::WM_CAPTURECHANGED => {
1397 if lparam != window as isize {
1402 subclass_input.window_state.lock().mouse.capture_count = 0;
1403 }
1404 0
1405 }
1406
1407 winuser::WM_TOUCH => {
1408 let pcount = LOWORD(wparam as DWORD) as usize;
1409 let mut inputs = Vec::with_capacity(pcount);
1410 inputs.set_len(pcount);
1411 let htouch = lparam as winuser::HTOUCHINPUT;
1412 if winuser::GetTouchInputInfo(
1413 htouch,
1414 pcount as UINT,
1415 inputs.as_mut_ptr(),
1416 mem::size_of::<winuser::TOUCHINPUT>() as INT,
1417 ) > 0
1418 {
1419 for input in &inputs {
1420 let mut location = POINT {
1421 x: input.x / 100,
1422 y: input.y / 100,
1423 };
1424
1425 if winuser::ScreenToClient(window, &mut location as *mut _) == 0 {
1426 continue;
1427 }
1428
1429 let x = location.x as f64 + (input.x % 100) as f64 / 100f64;
1430 let y = location.y as f64 + (input.y % 100) as f64 / 100f64;
1431 let location = PhysicalPosition::new(x, y);
1432 subclass_input.send_event(Event::WindowEvent {
1433 window_id: RootWindowId(WindowId(window)),
1434 event: WindowEvent::Touch(Touch {
1435 phase: if input.dwFlags & winuser::TOUCHEVENTF_DOWN != 0 {
1436 TouchPhase::Started
1437 } else if input.dwFlags & winuser::TOUCHEVENTF_UP != 0 {
1438 TouchPhase::Ended
1439 } else if input.dwFlags & winuser::TOUCHEVENTF_MOVE != 0 {
1440 TouchPhase::Moved
1441 } else {
1442 continue;
1443 },
1444 location,
1445 force: None, id: input.dwID as u64,
1447 device_id: DEVICE_ID,
1448 }),
1449 });
1450 }
1451 }
1452 winuser::CloseTouchInputHandle(htouch);
1453 0
1454 }
1455
1456 winuser::WM_POINTERDOWN | winuser::WM_POINTERUPDATE | winuser::WM_POINTERUP => {
1457 if let (
1458 Some(GetPointerFrameInfoHistory),
1459 Some(SkipPointerFrameMessages),
1460 Some(GetPointerDeviceRects),
1461 ) = (
1462 *GET_POINTER_FRAME_INFO_HISTORY,
1463 *SKIP_POINTER_FRAME_MESSAGES,
1464 *GET_POINTER_DEVICE_RECTS,
1465 ) {
1466 let pointer_id = LOWORD(wparam as DWORD) as UINT;
1467 let mut entries_count = 0 as UINT;
1468 let mut pointers_count = 0 as UINT;
1469 if GetPointerFrameInfoHistory(
1470 pointer_id,
1471 &mut entries_count as *mut _,
1472 &mut pointers_count as *mut _,
1473 std::ptr::null_mut(),
1474 ) == 0
1475 {
1476 return 0;
1477 }
1478
1479 let pointer_info_count = (entries_count * pointers_count) as usize;
1480 let mut pointer_infos = Vec::with_capacity(pointer_info_count);
1481 pointer_infos.set_len(pointer_info_count);
1482 if GetPointerFrameInfoHistory(
1483 pointer_id,
1484 &mut entries_count as *mut _,
1485 &mut pointers_count as *mut _,
1486 pointer_infos.as_mut_ptr(),
1487 ) == 0
1488 {
1489 return 0;
1490 }
1491
1492 for pointer_info in pointer_infos.iter().rev() {
1496 let mut device_rect = mem::MaybeUninit::uninit();
1497 let mut display_rect = mem::MaybeUninit::uninit();
1498
1499 if (GetPointerDeviceRects(
1500 pointer_info.sourceDevice,
1501 device_rect.as_mut_ptr(),
1502 display_rect.as_mut_ptr(),
1503 )) == 0
1504 {
1505 continue;
1506 }
1507
1508 let device_rect = device_rect.assume_init();
1509 let display_rect = display_rect.assume_init();
1510
1511 let himetric_to_pixel_ratio_x = (display_rect.right - display_rect.left) as f64
1514 / (device_rect.right - device_rect.left) as f64;
1515 let himetric_to_pixel_ratio_y = (display_rect.bottom - display_rect.top) as f64
1516 / (device_rect.bottom - device_rect.top) as f64;
1517
1518 let x = display_rect.left as f64
1522 + pointer_info.ptHimetricLocation.x as f64 * himetric_to_pixel_ratio_x;
1523 let y = display_rect.top as f64
1524 + pointer_info.ptHimetricLocation.y as f64 * himetric_to_pixel_ratio_y;
1525
1526 let mut location = POINT {
1527 x: x.floor() as i32,
1528 y: y.floor() as i32,
1529 };
1530
1531 if winuser::ScreenToClient(window, &mut location as *mut _) == 0 {
1532 continue;
1533 }
1534
1535 let force = match pointer_info.pointerType {
1536 winuser::PT_TOUCH => {
1537 let mut touch_info = mem::MaybeUninit::uninit();
1538 GET_POINTER_TOUCH_INFO.and_then(|GetPointerTouchInfo| {
1539 match GetPointerTouchInfo(
1540 pointer_info.pointerId,
1541 touch_info.as_mut_ptr(),
1542 ) {
1543 0 => None,
1544 _ => normalize_pointer_pressure(
1545 touch_info.assume_init().pressure,
1546 ),
1547 }
1548 })
1549 }
1550 winuser::PT_PEN => {
1551 let mut pen_info = mem::MaybeUninit::uninit();
1552 GET_POINTER_PEN_INFO.and_then(|GetPointerPenInfo| {
1553 match GetPointerPenInfo(
1554 pointer_info.pointerId,
1555 pen_info.as_mut_ptr(),
1556 ) {
1557 0 => None,
1558 _ => {
1559 normalize_pointer_pressure(pen_info.assume_init().pressure)
1560 }
1561 }
1562 })
1563 }
1564 _ => None,
1565 };
1566
1567 let x = location.x as f64 + x.fract();
1568 let y = location.y as f64 + y.fract();
1569 let location = PhysicalPosition::new(x, y);
1570 subclass_input.send_event(Event::WindowEvent {
1571 window_id: RootWindowId(WindowId(window)),
1572 event: WindowEvent::Touch(Touch {
1573 phase: if pointer_info.pointerFlags & winuser::POINTER_FLAG_DOWN != 0 {
1574 TouchPhase::Started
1575 } else if pointer_info.pointerFlags & winuser::POINTER_FLAG_UP != 0 {
1576 TouchPhase::Ended
1577 } else if pointer_info.pointerFlags & winuser::POINTER_FLAG_UPDATE != 0
1578 {
1579 TouchPhase::Moved
1580 } else {
1581 continue;
1582 },
1583 location,
1584 force,
1585 id: pointer_info.pointerId as u64,
1586 device_id: DEVICE_ID,
1587 }),
1588 });
1589 }
1590
1591 SkipPointerFrameMessages(pointer_id);
1592 }
1593 0
1594 }
1595
1596 winuser::WM_SETFOCUS => {
1597 use crate::event::{ElementState::Released, WindowEvent::Focused};
1598 for windows_keycode in event::get_pressed_keys() {
1599 let scancode =
1600 winuser::MapVirtualKeyA(windows_keycode as _, winuser::MAPVK_VK_TO_VSC);
1601 let virtual_keycode = event::vkey_to_winit_vkey(windows_keycode);
1602
1603 update_modifiers(window, subclass_input);
1604
1605 #[allow(deprecated)]
1606 subclass_input.send_event(Event::WindowEvent {
1607 window_id: RootWindowId(WindowId(window)),
1608 event: WindowEvent::KeyboardInput {
1609 device_id: DEVICE_ID,
1610 input: KeyboardInput {
1611 scancode,
1612 virtual_keycode,
1613 state: Released,
1614 modifiers: event::get_key_mods(),
1615 },
1616 is_synthetic: true,
1617 },
1618 })
1619 }
1620
1621 subclass_input.send_event(Event::WindowEvent {
1622 window_id: RootWindowId(WindowId(window)),
1623 event: Focused(true),
1624 });
1625
1626 0
1627 }
1628
1629 winuser::WM_KILLFOCUS => {
1630 use crate::event::{
1631 ElementState::Released,
1632 ModifiersState,
1633 WindowEvent::{Focused, ModifiersChanged},
1634 };
1635 for windows_keycode in event::get_pressed_keys() {
1636 let scancode =
1637 winuser::MapVirtualKeyA(windows_keycode as _, winuser::MAPVK_VK_TO_VSC);
1638 let virtual_keycode = event::vkey_to_winit_vkey(windows_keycode);
1639
1640 #[allow(deprecated)]
1641 subclass_input.send_event(Event::WindowEvent {
1642 window_id: RootWindowId(WindowId(window)),
1643 event: WindowEvent::KeyboardInput {
1644 device_id: DEVICE_ID,
1645 input: KeyboardInput {
1646 scancode,
1647 virtual_keycode,
1648 state: Released,
1649 modifiers: event::get_key_mods(),
1650 },
1651 is_synthetic: true,
1652 },
1653 })
1654 }
1655
1656 subclass_input.window_state.lock().modifiers_state = ModifiersState::empty();
1657 subclass_input.send_event(Event::WindowEvent {
1658 window_id: RootWindowId(WindowId(window)),
1659 event: ModifiersChanged(ModifiersState::empty()),
1660 });
1661
1662 subclass_input.send_event(Event::WindowEvent {
1663 window_id: RootWindowId(WindowId(window)),
1664 event: Focused(false),
1665 });
1666 0
1667 }
1668
1669 winuser::WM_SETCURSOR => {
1670 let set_cursor_to = {
1671 let window_state = subclass_input.window_state.lock();
1672 let in_client_area = LOWORD(lparam as DWORD) == winuser::HTCLIENT as WORD;
1676 if in_client_area {
1677 Some(window_state.mouse.cursor)
1678 } else {
1679 None
1680 }
1681 };
1682
1683 match set_cursor_to {
1684 Some(cursor) => {
1685 let cursor = winuser::LoadCursorW(ptr::null_mut(), cursor.to_windows_cursor());
1686 winuser::SetCursor(cursor);
1687 0
1688 }
1689 None => winuser::DefWindowProcW(window, msg, wparam, lparam),
1690 }
1691 }
1692
1693 winuser::WM_DROPFILES => {
1694 0
1696 }
1697
1698 winuser::WM_GETMINMAXINFO => {
1699 let mmi = lparam as *mut winuser::MINMAXINFO;
1700
1701 let window_state = subclass_input.window_state.lock();
1702
1703 if window_state.min_size.is_some() || window_state.max_size.is_some() {
1704 if let Some(min_size) = window_state.min_size {
1705 let min_size = min_size.to_physical(window_state.scale_factor);
1706 let (width, height): (u32, u32) = util::adjust_size(window, min_size).into();
1707 (*mmi).ptMinTrackSize = POINT {
1708 x: width as i32,
1709 y: height as i32,
1710 };
1711 }
1712 if let Some(max_size) = window_state.max_size {
1713 let max_size = max_size.to_physical(window_state.scale_factor);
1714 let (width, height): (u32, u32) = util::adjust_size(window, max_size).into();
1715 (*mmi).ptMaxTrackSize = POINT {
1716 x: width as i32,
1717 y: height as i32,
1718 };
1719 }
1720 }
1721
1722 0
1723 }
1724
1725 winuser::WM_DPICHANGED => {
1728 use crate::event::WindowEvent::ScaleFactorChanged;
1729
1730 let new_dpi_x = u32::from(LOWORD(wparam as DWORD));
1735 let new_scale_factor = dpi_to_scale_factor(new_dpi_x);
1736 let old_scale_factor: f64;
1737
1738 let allow_resize = {
1739 let mut window_state = subclass_input.window_state.lock();
1740 old_scale_factor = window_state.scale_factor;
1741 window_state.scale_factor = new_scale_factor;
1742
1743 if new_scale_factor == old_scale_factor {
1744 return 0;
1745 }
1746
1747 window_state.fullscreen.is_none()
1748 && !window_state.window_flags().contains(WindowFlags::MAXIMIZED)
1749 };
1750
1751 let style = winuser::GetWindowLongW(window, winuser::GWL_STYLE) as _;
1752 let style_ex = winuser::GetWindowLongW(window, winuser::GWL_EXSTYLE) as _;
1753
1754 let suggested_rect = *(lparam as *const RECT);
1756
1757 let margin_left: i32;
1762 let margin_top: i32;
1763 {
1766 let adjusted_rect =
1767 util::adjust_window_rect_with_styles(window, style, style_ex, suggested_rect)
1768 .unwrap_or(suggested_rect);
1769 margin_left = suggested_rect.left - adjusted_rect.left;
1770 margin_top = suggested_rect.top - adjusted_rect.top;
1771 }
1774
1775 let old_physical_inner_rect = {
1776 let mut old_physical_inner_rect = mem::zeroed();
1777 winuser::GetClientRect(window, &mut old_physical_inner_rect);
1778 let mut origin = mem::zeroed();
1779 winuser::ClientToScreen(window, &mut origin);
1780
1781 old_physical_inner_rect.left += origin.x;
1782 old_physical_inner_rect.right += origin.x;
1783 old_physical_inner_rect.top += origin.y;
1784 old_physical_inner_rect.bottom += origin.y;
1785
1786 old_physical_inner_rect
1787 };
1788 let old_physical_inner_size = PhysicalSize::new(
1789 (old_physical_inner_rect.right - old_physical_inner_rect.left) as u32,
1790 (old_physical_inner_rect.bottom - old_physical_inner_rect.top) as u32,
1791 );
1792
1793 let mut new_physical_inner_size = match allow_resize {
1796 true => old_physical_inner_size
1799 .to_logical::<f64>(old_scale_factor)
1800 .to_physical::<u32>(new_scale_factor),
1801 false => old_physical_inner_size,
1802 };
1803
1804 let _ = subclass_input.send_event(Event::WindowEvent {
1805 window_id: RootWindowId(WindowId(window)),
1806 event: ScaleFactorChanged {
1807 scale_factor: new_scale_factor,
1808 new_inner_size: &mut new_physical_inner_size,
1809 },
1810 });
1811
1812 let dragging_window: bool;
1813
1814 {
1815 let window_state = subclass_input.window_state.lock();
1816 dragging_window = window_state
1817 .window_flags()
1818 .contains(WindowFlags::MARKER_IN_SIZE_MOVE);
1819 if new_physical_inner_size != old_physical_inner_size {
1821 WindowState::set_window_flags(window_state, window, |f| {
1822 f.set(WindowFlags::MAXIMIZED, false)
1823 });
1824 }
1825 }
1826
1827 let new_outer_rect: RECT;
1828 {
1829 let suggested_ul = (
1830 suggested_rect.left + margin_left,
1831 suggested_rect.top + margin_top,
1832 );
1833
1834 let mut conservative_rect = RECT {
1835 left: suggested_ul.0,
1836 top: suggested_ul.1,
1837 right: suggested_ul.0 + new_physical_inner_size.width as LONG,
1838 bottom: suggested_ul.1 + new_physical_inner_size.height as LONG,
1839 };
1840
1841 conservative_rect = util::adjust_window_rect_with_styles(
1842 window,
1843 style,
1844 style_ex,
1845 conservative_rect,
1846 )
1847 .unwrap_or(conservative_rect);
1848
1849 if dragging_window {
1852 let bias = {
1853 let cursor_pos = {
1854 let mut pos = mem::zeroed();
1855 winuser::GetCursorPos(&mut pos);
1856 pos
1857 };
1858 let suggested_cursor_horizontal_ratio = (cursor_pos.x - suggested_rect.left)
1859 as f64
1860 / (suggested_rect.right - suggested_rect.left) as f64;
1861
1862 (cursor_pos.x
1863 - (suggested_cursor_horizontal_ratio
1864 * (conservative_rect.right - conservative_rect.left) as f64)
1865 as LONG)
1866 - conservative_rect.left
1867 };
1868 conservative_rect.left += bias;
1869 conservative_rect.right += bias;
1870 }
1871
1872 let new_dpi_monitor = winuser::MonitorFromWindow(window, 0);
1875 let conservative_rect_monitor = winuser::MonitorFromRect(&conservative_rect, 0);
1876 new_outer_rect = if conservative_rect_monitor == new_dpi_monitor {
1877 conservative_rect
1878 } else {
1879 let get_monitor_rect = |monitor| {
1880 let mut monitor_info = winuser::MONITORINFO {
1881 cbSize: mem::size_of::<winuser::MONITORINFO>() as _,
1882 ..mem::zeroed()
1883 };
1884 winuser::GetMonitorInfoW(monitor, &mut monitor_info);
1885 monitor_info.rcMonitor
1886 };
1887 let wrong_monitor = conservative_rect_monitor;
1888 let wrong_monitor_rect = get_monitor_rect(wrong_monitor);
1889 let new_monitor_rect = get_monitor_rect(new_dpi_monitor);
1890
1891 let delta_nudge_to_dpi_monitor = (
1895 if wrong_monitor_rect.left == new_monitor_rect.right {
1896 -1
1897 } else if wrong_monitor_rect.right == new_monitor_rect.left {
1898 1
1899 } else {
1900 0
1901 },
1902 if wrong_monitor_rect.bottom == new_monitor_rect.top {
1903 1
1904 } else if wrong_monitor_rect.top == new_monitor_rect.bottom {
1905 -1
1906 } else {
1907 0
1908 },
1909 );
1910
1911 let abort_after_iterations = new_monitor_rect.right - new_monitor_rect.left
1912 + new_monitor_rect.bottom
1913 - new_monitor_rect.top;
1914 for _ in 0..abort_after_iterations {
1915 conservative_rect.left += delta_nudge_to_dpi_monitor.0;
1916 conservative_rect.right += delta_nudge_to_dpi_monitor.0;
1917 conservative_rect.top += delta_nudge_to_dpi_monitor.1;
1918 conservative_rect.bottom += delta_nudge_to_dpi_monitor.1;
1919
1920 if winuser::MonitorFromRect(&conservative_rect, 0) == new_dpi_monitor {
1921 break;
1922 }
1923 }
1924
1925 conservative_rect
1926 };
1927 }
1928
1929 winuser::SetWindowPos(
1930 window,
1931 ptr::null_mut(),
1932 new_outer_rect.left,
1933 new_outer_rect.top,
1934 new_outer_rect.right - new_outer_rect.left,
1935 new_outer_rect.bottom - new_outer_rect.top,
1936 winuser::SWP_NOZORDER | winuser::SWP_NOACTIVATE,
1937 );
1938
1939 0
1940 }
1941
1942 winuser::WM_SETTINGCHANGE => {
1943 use crate::event::WindowEvent::ThemeChanged;
1944
1945 let preferred_theme = subclass_input.window_state.lock().preferred_theme;
1946
1947 if preferred_theme == None {
1948 let new_theme = try_theme(window, preferred_theme);
1949 let mut window_state = subclass_input.window_state.lock();
1950
1951 if window_state.current_theme != new_theme {
1952 window_state.current_theme = new_theme;
1953 mem::drop(window_state);
1954 subclass_input.send_event(Event::WindowEvent {
1955 window_id: RootWindowId(WindowId(window)),
1956 event: ThemeChanged(new_theme),
1957 });
1958 }
1959 }
1960
1961 commctrl::DefSubclassProc(window, msg, wparam, lparam)
1962 }
1963
1964 _ => {
1965 if msg == *DESTROY_MSG_ID {
1966 winuser::DestroyWindow(window);
1967 0
1968 } else if msg == *SET_RETAIN_STATE_ON_SIZE_MSG_ID {
1969 let mut window_state = subclass_input.window_state.lock();
1970 window_state.set_window_flags_in_place(|f| {
1971 f.set(WindowFlags::MARKER_RETAIN_STATE_ON_SIZE, wparam != 0)
1972 });
1973 0
1974 } else {
1975 commctrl::DefSubclassProc(window, msg, wparam, lparam)
1976 }
1977 }
1978 };
1979
1980 subclass_input
1981 .event_loop_runner
1982 .catch_unwind(callback)
1983 .unwrap_or(-1)
1984}
1985
1986unsafe extern "system" fn thread_event_target_callback<T: 'static>(
1987 window: HWND,
1988 msg: UINT,
1989 wparam: WPARAM,
1990 lparam: LPARAM,
1991 _: UINT_PTR,
1992 subclass_input_ptr: DWORD_PTR,
1993) -> LRESULT {
1994 let subclass_input = Box::from_raw(subclass_input_ptr as *mut ThreadMsgTargetSubclassInput<T>);
1995
1996 if msg != winuser::WM_PAINT {
1997 winuser::RedrawWindow(
1998 window,
1999 ptr::null(),
2000 ptr::null_mut(),
2001 winuser::RDW_INTERNALPAINT,
2002 );
2003 }
2004
2005 let mut subclass_removed = false;
2006
2007 let callback = || match msg {
2011 winuser::WM_NCDESTROY => {
2012 remove_event_target_window_subclass::<T>(window);
2013 subclass_removed = true;
2014 0
2015 }
2016 winuser::WM_PAINT => {
2019 winuser::ValidateRect(window, ptr::null());
2020 if subclass_input.event_loop_runner.handling_events() {
2024 if subclass_input.event_loop_runner.should_buffer() {
2025 winuser::RedrawWindow(
2028 window,
2029 ptr::null(),
2030 ptr::null_mut(),
2031 winuser::RDW_INTERNALPAINT,
2032 );
2033 } else {
2034 assert!(flush_paint_messages(
2037 None,
2038 &subclass_input.event_loop_runner
2039 ));
2040 subclass_input.event_loop_runner.redraw_events_cleared();
2041 process_control_flow(&subclass_input.event_loop_runner);
2042 }
2043 }
2044
2045 commctrl::DefSubclassProc(window, msg, wparam, lparam)
2047 }
2048
2049 winuser::WM_INPUT_DEVICE_CHANGE => {
2050 let event = match wparam as _ {
2051 winuser::GIDC_ARRIVAL => DeviceEvent::Added,
2052 winuser::GIDC_REMOVAL => DeviceEvent::Removed,
2053 _ => unreachable!(),
2054 };
2055
2056 subclass_input.send_event(Event::DeviceEvent {
2057 device_id: wrap_device_id(lparam as _),
2058 event,
2059 });
2060
2061 0
2062 }
2063
2064 winuser::WM_INPUT => {
2065 use crate::event::{
2066 DeviceEvent::{Button, Key, Motion, MouseMotion, MouseWheel},
2067 ElementState::{Pressed, Released},
2068 MouseScrollDelta::LineDelta,
2069 };
2070
2071 if let Some(data) = raw_input::get_raw_input_data(lparam as _) {
2072 let device_id = wrap_device_id(data.header.hDevice as _);
2073
2074 if data.header.dwType == winuser::RIM_TYPEMOUSE {
2075 let mouse = data.data.mouse();
2076
2077 if util::has_flag(mouse.usFlags, winuser::MOUSE_MOVE_RELATIVE) {
2078 let x = mouse.lLastX as f64;
2079 let y = mouse.lLastY as f64;
2080
2081 if x != 0.0 {
2082 subclass_input.send_event(Event::DeviceEvent {
2083 device_id,
2084 event: Motion { axis: 0, value: x },
2085 });
2086 }
2087
2088 if y != 0.0 {
2089 subclass_input.send_event(Event::DeviceEvent {
2090 device_id,
2091 event: Motion { axis: 1, value: y },
2092 });
2093 }
2094
2095 if x != 0.0 || y != 0.0 {
2096 subclass_input.send_event(Event::DeviceEvent {
2097 device_id,
2098 event: MouseMotion { delta: (x, y) },
2099 });
2100 }
2101 }
2102
2103 if util::has_flag(mouse.usButtonFlags, winuser::RI_MOUSE_WHEEL) {
2104 let delta =
2105 mouse.usButtonData as SHORT as f32 / winuser::WHEEL_DELTA as f32;
2106 subclass_input.send_event(Event::DeviceEvent {
2107 device_id,
2108 event: MouseWheel {
2109 delta: LineDelta(0.0, delta),
2110 },
2111 });
2112 }
2113
2114 let button_state = raw_input::get_raw_mouse_button_state(mouse.usButtonFlags);
2115 for (index, state) in button_state.iter().enumerate() {
2117 if let Some(state) = *state {
2118 let button = (index + 1) as _;
2122 subclass_input.send_event(Event::DeviceEvent {
2123 device_id,
2124 event: Button { button, state },
2125 });
2126 }
2127 }
2128 } else if data.header.dwType == winuser::RIM_TYPEKEYBOARD {
2129 let keyboard = data.data.keyboard();
2130
2131 let pressed = keyboard.Message == winuser::WM_KEYDOWN
2132 || keyboard.Message == winuser::WM_SYSKEYDOWN;
2133 let released = keyboard.Message == winuser::WM_KEYUP
2134 || keyboard.Message == winuser::WM_SYSKEYUP;
2135
2136 if pressed || released {
2137 let state = if pressed { Pressed } else { Released };
2138
2139 let scancode = keyboard.MakeCode as _;
2140 let extended = util::has_flag(keyboard.Flags, winuser::RI_KEY_E0 as _)
2141 | util::has_flag(keyboard.Flags, winuser::RI_KEY_E1 as _);
2142
2143 if let Some((vkey, scancode)) =
2144 handle_extended_keys(keyboard.VKey as _, scancode, extended)
2145 {
2146 let virtual_keycode = vkey_to_winit_vkey(vkey);
2147
2148 #[allow(deprecated)]
2149 subclass_input.send_event(Event::DeviceEvent {
2150 device_id,
2151 event: Key(KeyboardInput {
2152 scancode,
2153 state,
2154 virtual_keycode,
2155 modifiers: event::get_key_mods(),
2156 }),
2157 });
2158 }
2159 }
2160 }
2161 }
2162
2163 commctrl::DefSubclassProc(window, msg, wparam, lparam)
2164 }
2165
2166 _ if msg == *USER_EVENT_MSG_ID => {
2167 if let Ok(event) = subclass_input.user_event_receiver.recv() {
2168 subclass_input.send_event(Event::UserEvent(event));
2169 }
2170 0
2171 }
2172 _ if msg == *EXEC_MSG_ID => {
2173 let mut function: ThreadExecFn = Box::from_raw(wparam as usize as *mut _);
2174 function();
2175 0
2176 }
2177 _ if msg == *PROCESS_NEW_EVENTS_MSG_ID => {
2178 winuser::PostThreadMessageW(
2179 subclass_input.event_loop_runner.wait_thread_id(),
2180 *CANCEL_WAIT_UNTIL_MSG_ID,
2181 0,
2182 0,
2183 );
2184
2185 if let ControlFlow::WaitUntil(wait_until) =
2188 subclass_input.event_loop_runner.control_flow()
2189 {
2190 let mut msg = mem::zeroed();
2191 while Instant::now() < wait_until {
2192 if 0 != winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 0) {
2193 if msg.message == winuser::WM_PAINT {
2200 let mut rect = mem::zeroed();
2201 if 0 == winuser::GetUpdateRect(msg.hwnd, &mut rect, 0) {
2202 winuser::RedrawWindow(
2203 msg.hwnd,
2204 ptr::null(),
2205 ptr::null_mut(),
2206 winuser::RDW_INTERNALPAINT,
2207 );
2208 }
2209 }
2210
2211 break;
2212 }
2213 }
2214 }
2215 subclass_input.event_loop_runner.poll();
2216 0
2217 }
2218 _ => commctrl::DefSubclassProc(window, msg, wparam, lparam),
2219 };
2220
2221 let result = subclass_input
2222 .event_loop_runner
2223 .catch_unwind(callback)
2224 .unwrap_or(-1);
2225 if subclass_removed {
2226 mem::drop(subclass_input);
2227 } else {
2228 Box::into_raw(subclass_input);
2229 }
2230 result
2231}