feat(Windows): add with_msg_hook ()

This commit is contained in:
Amr Bashir 2022-03-30 10:30:45 +02:00 committed by GitHub
parent 945a9e3122
commit 08de2b3fc4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 59 additions and 7 deletions
CHANGELOG.md
src
event_loop.rs
platform
platform_impl/windows

View file

@ -8,6 +8,7 @@ And please only add new entries to the top of this list, right below the `# Unre
# Unreleased # Unreleased
- On Windows, Added `EventLoopBuilderExtWindows::with_msg_hook`
- On Windows, remove internally unique DC per window. - On Windows, remove internally unique DC per window.
- macOS: Remove the need to call `set_ime_position` after moving the window. - macOS: Remove the need to call `set_ime_position` after moving the window.
- Added `Window::is_visible`. - Added `Window::is_visible`.

View file

@ -50,7 +50,7 @@ pub struct EventLoopWindowTarget<T: 'static> {
/// ///
/// This is used to make specifying options that affect the whole application /// This is used to make specifying options that affect the whole application
/// easier. But note that constructing multiple event loops is not supported. /// easier. But note that constructing multiple event loops is not supported.
#[derive(Debug, Clone, Default)] #[derive(Default)]
pub struct EventLoopBuilder<T: 'static> { pub struct EventLoopBuilder<T: 'static> {
pub(crate) platform_specific: platform_impl::PlatformSpecificEventLoopAttributes, pub(crate) platform_specific: platform_impl::PlatformSpecificEventLoopAttributes,
_p: PhantomData<T>, _p: PhantomData<T>,
@ -95,7 +95,7 @@ impl<T> EventLoopBuilder<T> {
#[inline] #[inline]
pub fn build(&mut self) -> EventLoop<T> { pub fn build(&mut self) -> EventLoop<T> {
EventLoop { EventLoop {
event_loop: platform_impl::EventLoop::new(&self.platform_specific), event_loop: platform_impl::EventLoop::new(&mut self.platform_specific),
_marker: PhantomData, _marker: PhantomData,
} }
} }

View file

@ -1,6 +1,6 @@
#![cfg(target_os = "windows")] #![cfg(target_os = "windows")]
use std::path::Path; use std::{ffi::c_void, path::Path};
use crate::{ use crate::{
dpi::PhysicalSize, dpi::PhysicalSize,
@ -56,6 +56,36 @@ pub trait EventLoopBuilderExtWindows {
/// # } /// # }
/// ``` /// ```
fn with_dpi_aware(&mut self, dpi_aware: bool) -> &mut Self; 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<ACCEL> = Vec::new();
/// let translated = unsafe {
/// TranslateAcceleratorW(
/// (*msg).hwnd,
/// CreateAcceleratorTableW(accels.as_ptr() as _, 1),
/// msg,
/// ) == 1
/// };
/// translated
/// });
/// ```
fn with_msg_hook<F>(&mut self, callback: F) -> &mut Self
where
F: FnMut(*const c_void) -> bool + 'static;
} }
impl<T> EventLoopBuilderExtWindows for EventLoopBuilder<T> { impl<T> EventLoopBuilderExtWindows for EventLoopBuilder<T> {
@ -70,6 +100,15 @@ impl<T> EventLoopBuilderExtWindows for EventLoopBuilder<T> {
self.platform_specific.dpi_aware = dpi_aware; self.platform_specific.dpi_aware = dpi_aware;
self self
} }
#[inline]
fn with_msg_hook<F>(&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. /// Additional methods on `Window` that are specific to Windows.

View file

@ -6,6 +6,7 @@ use parking_lot::Mutex;
use std::{ use std::{
cell::Cell, cell::Cell,
collections::VecDeque, collections::VecDeque,
ffi::c_void,
marker::PhantomData, marker::PhantomData,
mem, panic, ptr, mem, panic, ptr,
rc::Rc, rc::Rc,
@ -150,12 +151,13 @@ impl<T> ThreadMsgTargetData<T> {
pub struct EventLoop<T: 'static> { pub struct EventLoop<T: 'static> {
thread_msg_sender: Sender<T>, thread_msg_sender: Sender<T>,
window_target: RootELW<T>, window_target: RootELW<T>,
msg_hook: Option<Box<dyn FnMut(*const c_void) -> bool + 'static>>,
} }
#[derive(Debug, Copy, Clone, PartialEq, Hash)]
pub(crate) struct PlatformSpecificEventLoopAttributes { pub(crate) struct PlatformSpecificEventLoopAttributes {
pub(crate) any_thread: bool, pub(crate) any_thread: bool,
pub(crate) dpi_aware: bool, pub(crate) dpi_aware: bool,
pub(crate) msg_hook: Option<Box<dyn FnMut(*const c_void) -> bool + 'static>>,
} }
impl Default for PlatformSpecificEventLoopAttributes { impl Default for PlatformSpecificEventLoopAttributes {
@ -163,6 +165,7 @@ impl Default for PlatformSpecificEventLoopAttributes {
Self { Self {
any_thread: false, any_thread: false,
dpi_aware: true, dpi_aware: true,
msg_hook: None,
} }
} }
} }
@ -174,7 +177,7 @@ pub struct EventLoopWindowTarget<T: 'static> {
} }
impl<T: 'static> EventLoop<T> { impl<T: 'static> EventLoop<T> {
pub(crate) fn new(attributes: &PlatformSpecificEventLoopAttributes) -> Self { pub(crate) fn new(attributes: &mut PlatformSpecificEventLoopAttributes) -> Self {
let thread_id = unsafe { GetCurrentThreadId() }; let thread_id = unsafe { GetCurrentThreadId() };
if !attributes.any_thread && thread_id != main_thread_id() { if !attributes.any_thread && thread_id != main_thread_id() {
@ -211,6 +214,7 @@ impl<T: 'static> EventLoop<T> {
}, },
_marker: PhantomData, _marker: PhantomData,
}, },
msg_hook: attributes.msg_hook.take(),
} }
} }
@ -251,8 +255,16 @@ impl<T: 'static> EventLoop<T> {
if GetMessageW(&mut msg, 0, 0, 0) == false.into() { if GetMessageW(&mut msg, 0, 0, 0) == false.into() {
break 'main 0; 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() { if let Err(payload) = runner.take_panic_error() {
runner.reset_runner(); runner.reset_runner();