diff --git a/CHANGELOG.md b/CHANGELOG.md index bfc304e6..f9adaf47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ And please only add new entries to the top of this list, right below the `# Unre # Unreleased +- On Windows, Added `EventLoopBuilderExtWindows::with_msg_hook` - On Windows, remove internally unique DC per window. - macOS: Remove the need to call `set_ime_position` after moving the window. - Added `Window::is_visible`. diff --git a/src/event_loop.rs b/src/event_loop.rs index a86cfee1..17bca97c 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -50,7 +50,7 @@ pub struct EventLoopWindowTarget { /// /// This is used to make specifying options that affect the whole application /// easier. But note that constructing multiple event loops is not supported. -#[derive(Debug, Clone, Default)] +#[derive(Default)] pub struct EventLoopBuilder { pub(crate) platform_specific: platform_impl::PlatformSpecificEventLoopAttributes, _p: PhantomData, @@ -95,7 +95,7 @@ impl EventLoopBuilder { #[inline] pub fn build(&mut self) -> EventLoop { EventLoop { - event_loop: platform_impl::EventLoop::new(&self.platform_specific), + event_loop: platform_impl::EventLoop::new(&mut self.platform_specific), _marker: PhantomData, } } diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 0f5902c9..c10eb4bc 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -1,6 +1,6 @@ #![cfg(target_os = "windows")] -use std::path::Path; +use std::{ffi::c_void, path::Path}; use crate::{ dpi::PhysicalSize, @@ -56,6 +56,36 @@ pub trait EventLoopBuilderExtWindows { /// # } /// ``` fn with_dpi_aware(&mut self, dpi_aware: bool) -> &mut Self; + + /// A callback to be executed before dispatching a win32 message to the window procedure. + /// Return true to disable winit's internal message dispatching. + /// + /// # Example + /// + /// ``` + /// # use windows_sys::Win32::UI::WindowsAndMessaging::{ACCEL, CreateAcceleratorTableW, TranslateAcceleratorW, DispatchMessageW, TranslateMessage, MSG}; + /// use winit::event_loop::EventLoopBuilder; + /// #[cfg(target_os = "windows")] + /// use winit::platform::windows::EventLoopBuilderExtWindows; + /// + /// let mut builder = EventLoopBuilder::new(); + /// #[cfg(target_os = "windows")] + /// builder.with_msg_hook(|msg|{ + /// let msg = msg as *const MSG; + /// # let accels: Vec = Vec::new(); + /// let translated = unsafe { + /// TranslateAcceleratorW( + /// (*msg).hwnd, + /// CreateAcceleratorTableW(accels.as_ptr() as _, 1), + /// msg, + /// ) == 1 + /// }; + /// translated + /// }); + /// ``` + fn with_msg_hook(&mut self, callback: F) -> &mut Self + where + F: FnMut(*const c_void) -> bool + 'static; } impl EventLoopBuilderExtWindows for EventLoopBuilder { @@ -70,6 +100,15 @@ impl EventLoopBuilderExtWindows for EventLoopBuilder { self.platform_specific.dpi_aware = dpi_aware; self } + + #[inline] + fn with_msg_hook(&mut self, callback: F) -> &mut Self + where + F: FnMut(*const c_void) -> bool + 'static, + { + self.platform_specific.msg_hook = Some(Box::new(callback)); + self + } } /// Additional methods on `Window` that are specific to Windows. diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index c0366ecb..f24e93ec 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -6,6 +6,7 @@ use parking_lot::Mutex; use std::{ cell::Cell, collections::VecDeque, + ffi::c_void, marker::PhantomData, mem, panic, ptr, rc::Rc, @@ -150,12 +151,13 @@ impl ThreadMsgTargetData { pub struct EventLoop { thread_msg_sender: Sender, window_target: RootELW, + msg_hook: Option bool + 'static>>, } -#[derive(Debug, Copy, Clone, PartialEq, Hash)] pub(crate) struct PlatformSpecificEventLoopAttributes { pub(crate) any_thread: bool, pub(crate) dpi_aware: bool, + pub(crate) msg_hook: Option bool + 'static>>, } impl Default for PlatformSpecificEventLoopAttributes { @@ -163,6 +165,7 @@ impl Default for PlatformSpecificEventLoopAttributes { Self { any_thread: false, dpi_aware: true, + msg_hook: None, } } } @@ -174,7 +177,7 @@ pub struct EventLoopWindowTarget { } impl EventLoop { - pub(crate) fn new(attributes: &PlatformSpecificEventLoopAttributes) -> Self { + pub(crate) fn new(attributes: &mut PlatformSpecificEventLoopAttributes) -> Self { let thread_id = unsafe { GetCurrentThreadId() }; if !attributes.any_thread && thread_id != main_thread_id() { @@ -211,6 +214,7 @@ impl EventLoop { }, _marker: PhantomData, }, + msg_hook: attributes.msg_hook.take(), } } @@ -251,8 +255,16 @@ impl EventLoop { if GetMessageW(&mut msg, 0, 0, 0) == false.into() { break 'main 0; } - TranslateMessage(&msg); - DispatchMessageW(&msg); + + let handled = if let Some(callback) = self.msg_hook.as_deref_mut() { + callback(&mut msg as *mut _ as *mut _) + } else { + false + }; + if !handled { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } if let Err(payload) = runner.take_panic_error() { runner.reset_runner();