mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-11-25 05:03:05 +00:00
gpu_display: add Surface implementation for Windows.
This is where we process host display events, such as window size change and mouse input events. MouseInputManager etc are currently no-op. Their implementation will be added later. BUG=b:306024335 Change-Id: Ib67fd64894bd8c9f47cf2ee3cdf2a20901defe3b Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/5053935 Reviewed-by: Richard Zhang <rizhang@google.com> Commit-Queue: Pujun Lun <lunpujun@google.com> Reviewed-by: Noah Gold <nkgold@google.com>
This commit is contained in:
parent
cc6191d72c
commit
165acb2e03
6 changed files with 454 additions and 79 deletions
|
@ -4,8 +4,11 @@
|
|||
|
||||
mod keyboard_input_manager;
|
||||
mod math_util;
|
||||
mod mouse_input_manager;
|
||||
pub mod surface;
|
||||
mod virtual_display_manager;
|
||||
mod window;
|
||||
mod window_manager;
|
||||
mod window_message_dispatcher;
|
||||
mod window_message_processor;
|
||||
pub mod window_procedure_thread;
|
||||
|
@ -29,7 +32,7 @@ use euclid::size2;
|
|||
use euclid::Size2D;
|
||||
use math_util::Size2DCheckedCast;
|
||||
use metrics::sys::windows::Metrics;
|
||||
pub use surface::NoopSurface as Surface;
|
||||
pub use surface::Surface;
|
||||
use vm_control::gpu::DisplayMode;
|
||||
use vm_control::gpu::DisplayParameters;
|
||||
use vm_control::ModifyWaitContext;
|
||||
|
|
50
gpu_display/src/gpu_display_win/mouse_input_manager.rs
Normal file
50
gpu_display/src/gpu_display_win/mouse_input_manager.rs
Normal file
|
@ -0,0 +1,50 @@
|
|||
// Copyright 2023 The ChromiumOS Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use anyhow::Result;
|
||||
use euclid::Size2D;
|
||||
use euclid::Transform2D;
|
||||
use winapi::shared::minwindef::LRESULT;
|
||||
|
||||
use super::window::GuiWindow;
|
||||
use super::window_message_dispatcher::DisplayEventDispatcher;
|
||||
use super::window_message_processor::WindowMessage;
|
||||
use super::HostWindowSpace;
|
||||
use super::VirtualDisplaySpace;
|
||||
use crate::GpuDisplayError;
|
||||
|
||||
/// Responsible for capturing input from a HWND and forwarding it to the guest.
|
||||
pub(crate) struct NoopMouseInputManager {}
|
||||
|
||||
impl NoopMouseInputManager {
|
||||
pub fn new(
|
||||
_window: &GuiWindow,
|
||||
_transform: Transform2D<f64, HostWindowSpace, VirtualDisplaySpace>,
|
||||
_virtual_display_size: Size2D<u32, VirtualDisplaySpace>,
|
||||
_display_event_dispatcher: DisplayEventDispatcher,
|
||||
) -> Result<Self, GpuDisplayError> {
|
||||
Ok(Self {})
|
||||
}
|
||||
|
||||
pub fn update_host_to_guest_transform(
|
||||
&mut self,
|
||||
_transform: Transform2D<f64, HostWindowSpace, VirtualDisplaySpace>,
|
||||
) {
|
||||
}
|
||||
|
||||
/// Possible return values:
|
||||
/// 1. `ControlFlow::Continue`, should continue invoking other modules, such as the window
|
||||
/// manager, to perform more processing.
|
||||
/// 2. `ControlFlow::Break(Some)`, should skip any other processing and return the value.
|
||||
/// 3. `ControlFlow::Break(None)`, should immediately perform default processing.
|
||||
pub fn handle_window_message(
|
||||
&mut self,
|
||||
_window: &GuiWindow,
|
||||
_message: &WindowMessage,
|
||||
) -> ControlFlow<Option<LRESULT>> {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
|
@ -2,53 +2,241 @@
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use std::ops::ControlFlow;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Weak;
|
||||
use std::time::Instant;
|
||||
|
||||
use anyhow::bail;
|
||||
use anyhow::Context;
|
||||
use anyhow::Result;
|
||||
use base::error;
|
||||
use base::info;
|
||||
use base::warn;
|
||||
use base::Tube;
|
||||
use euclid::size2;
|
||||
use euclid::Size2D;
|
||||
use linux_input_sys::virtio_input_event;
|
||||
use metrics::sys::windows::Metrics;
|
||||
use win_util::keys_down;
|
||||
use winapi::shared::minwindef::HIWORD;
|
||||
use winapi::shared::minwindef::LOWORD;
|
||||
use winapi::shared::minwindef::LPARAM;
|
||||
use winapi::shared::minwindef::LRESULT;
|
||||
use winapi::shared::minwindef::TRUE;
|
||||
use winapi::shared::minwindef::WPARAM;
|
||||
use winapi::um::winuser::*;
|
||||
|
||||
use super::math_util::Size2DCheckedCast;
|
||||
use super::mouse_input_manager::NoopMouseInputManager as MouseInputManager;
|
||||
use super::virtual_display_manager::NoopVirtualDisplayManager as VirtualDisplayManager;
|
||||
use super::window::BasicWindow;
|
||||
use super::window::GuiWindow;
|
||||
use super::window_manager::NoopWindowManager as WindowManager;
|
||||
use super::window_message_processor::SurfaceResources;
|
||||
use super::window_message_processor::WindowMessage;
|
||||
use super::window_message_processor::WindowPosMessage;
|
||||
use super::window_message_processor::HANDLE_WINDOW_MESSAGE_TIMEOUT;
|
||||
use super::DisplayProperties;
|
||||
use super::HostWindowSpace;
|
||||
use super::VirtualDisplaySpace;
|
||||
use crate::EventDeviceKind;
|
||||
|
||||
pub struct NoopSurface {}
|
||||
pub struct Surface {
|
||||
mouse_input: MouseInputManager,
|
||||
window_manager: WindowManager,
|
||||
virtual_display_manager: VirtualDisplayManager,
|
||||
#[allow(dead_code)]
|
||||
gpu_main_display_tube: Option<Rc<Tube>>,
|
||||
}
|
||||
|
||||
impl NoopSurface {
|
||||
impl Surface {
|
||||
pub fn create(
|
||||
_window: &GuiWindow,
|
||||
_virtual_display_size: &Size2D<i32, VirtualDisplaySpace>,
|
||||
window: &GuiWindow,
|
||||
virtual_display_size: &Size2D<i32, VirtualDisplaySpace>,
|
||||
_metrics: Option<Weak<Metrics>>,
|
||||
_display_properties: &DisplayProperties,
|
||||
_resources: SurfaceResources,
|
||||
display_properties: &DisplayProperties,
|
||||
resources: SurfaceResources,
|
||||
) -> Result<Self> {
|
||||
Ok(Self {})
|
||||
static CONTEXT_MESSAGE: &str = "When creating Surface";
|
||||
info!("Creating Surface");
|
||||
|
||||
let initial_host_viewport_size = window.get_client_rect().context(CONTEXT_MESSAGE)?.size;
|
||||
let virtual_display_manager =
|
||||
VirtualDisplayManager::new(&initial_host_viewport_size, virtual_display_size);
|
||||
// This will make gfxstream initialize the child window to which it will render.
|
||||
window.update_virtual_display_projection(
|
||||
&virtual_display_manager.get_virtual_display_projection_box(),
|
||||
);
|
||||
|
||||
let SurfaceResources {
|
||||
display_event_dispatcher,
|
||||
gpu_main_display_tube,
|
||||
} = resources;
|
||||
|
||||
let mouse_input = match MouseInputManager::new(
|
||||
window,
|
||||
*virtual_display_manager.get_host_to_guest_transform(),
|
||||
virtual_display_size.checked_cast(),
|
||||
display_event_dispatcher,
|
||||
) {
|
||||
Ok(mouse_input) => mouse_input,
|
||||
Err(e) => bail!(
|
||||
"Failed to create MouseInputManager during Surface creation: {:?}",
|
||||
e
|
||||
),
|
||||
};
|
||||
|
||||
Ok(Surface {
|
||||
mouse_input,
|
||||
window_manager: WindowManager::new(
|
||||
window,
|
||||
display_properties,
|
||||
initial_host_viewport_size,
|
||||
gpu_main_display_tube.clone(),
|
||||
)
|
||||
.context(CONTEXT_MESSAGE)?,
|
||||
virtual_display_manager,
|
||||
gpu_main_display_tube,
|
||||
})
|
||||
}
|
||||
|
||||
fn handle_key_event(
|
||||
&mut self,
|
||||
window: &GuiWindow,
|
||||
_key_down: bool,
|
||||
w_param: WPARAM,
|
||||
_l_param: LPARAM,
|
||||
) {
|
||||
// Since we handle WM_SYSKEYDOWN we have to handle Alt-F4 ourselves.
|
||||
if (w_param == VK_MENU as usize || w_param == VK_F4 as usize)
|
||||
&& keys_down(&[VK_MENU, VK_F4])
|
||||
{
|
||||
info!("Got alt-F4 w_param={}, posting WM_CLOSE", w_param);
|
||||
if let Err(e) =
|
||||
window.post_message(WM_CLOSE, /* w_param */ 0, /* l_param */ 0)
|
||||
{
|
||||
error!("Failed to post WM_CLOSE: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update_host_viewport_size(
|
||||
&mut self,
|
||||
window: &GuiWindow,
|
||||
host_viewport_size: &Size2D<i32, HostWindowSpace>,
|
||||
) {
|
||||
info!("Updating host viewport size to {:?}", host_viewport_size);
|
||||
let start = Instant::now();
|
||||
|
||||
self.virtual_display_manager
|
||||
.update_host_guest_transforms(host_viewport_size);
|
||||
let virtual_display_projection_box = self
|
||||
.virtual_display_manager
|
||||
.get_virtual_display_projection_box();
|
||||
window.update_virtual_display_projection(&virtual_display_projection_box);
|
||||
self.mouse_input.update_host_to_guest_transform(
|
||||
*self.virtual_display_manager.get_host_to_guest_transform(),
|
||||
);
|
||||
|
||||
let elapsed = start.elapsed();
|
||||
let elapsed_millis = elapsed.as_millis();
|
||||
if elapsed < HANDLE_WINDOW_MESSAGE_TIMEOUT {
|
||||
info!(
|
||||
"Finished updating host viewport size in {}ms",
|
||||
elapsed_millis
|
||||
);
|
||||
} else {
|
||||
warn!(
|
||||
"Window might have been hung since updating host viewport size took \
|
||||
too long ({}ms)!",
|
||||
elapsed_millis
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Called once when it is safe to assume all future messages targeting `window` will be
|
||||
/// dispatched to this `Surface`.
|
||||
pub fn on_message_dispatcher_attached(&mut self, _window: &GuiWindow) {}
|
||||
pub fn on_message_dispatcher_attached(&mut self, window: &GuiWindow) {
|
||||
// `WindowManager` relies on window messages to properly set initial window pos.
|
||||
// We might see a suboptimal UI if any error occurs here, such as having black bars. Instead
|
||||
// of crashing the emulator, we would just log the error and still allow the user to
|
||||
// experience the app.
|
||||
if let Err(e) = self.window_manager.set_initial_window_pos(window) {
|
||||
error!("Failed to set initial window pos: {:#?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// Called whenever any window message is retrieved. Returns None if `DefWindowProcW()` should
|
||||
/// be called after our processing.
|
||||
pub fn handle_window_message(
|
||||
&mut self,
|
||||
_window: &GuiWindow,
|
||||
_message: WindowMessage,
|
||||
window: &GuiWindow,
|
||||
message: WindowMessage,
|
||||
) -> Option<LRESULT> {
|
||||
None
|
||||
if let ControlFlow::Break(ret) = self.mouse_input.handle_window_message(window, &message) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Just return 0 for most of the messages we processed.
|
||||
let mut ret: Option<LRESULT> = Some(0);
|
||||
match message {
|
||||
WindowMessage::Key {
|
||||
is_sys_key: _,
|
||||
is_down,
|
||||
w_param,
|
||||
l_param,
|
||||
} => self.handle_key_event(window, is_down, w_param, l_param),
|
||||
WindowMessage::WindowPos(window_pos_msg) => {
|
||||
ret = self.handle_window_pos_message(window, window_pos_msg)
|
||||
}
|
||||
WindowMessage::DisplayChange => self.window_manager.handle_display_change(window),
|
||||
WindowMessage::HostViewportChange { l_param } => {
|
||||
self.on_host_viewport_change(window, l_param)
|
||||
}
|
||||
WindowMessage::WindowClose => self.on_close(window),
|
||||
// The following messages are handled by other modules.
|
||||
WindowMessage::WindowActivate { .. }
|
||||
| WindowMessage::Mouse(_)
|
||||
| WindowMessage::KeyboardFocus => (),
|
||||
WindowMessage::Other(..) => {
|
||||
// Request default processing for messages that we don't explicitly handle.
|
||||
ret = None;
|
||||
}
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn handle_event_device(
|
||||
/// Returns None if `DefWindowProcW()` should be called after our processing.
|
||||
#[inline]
|
||||
fn handle_window_pos_message(
|
||||
&mut self,
|
||||
_window: &GuiWindow,
|
||||
_event_device_kind: EventDeviceKind,
|
||||
_event: virtio_input_event,
|
||||
) {
|
||||
window: &GuiWindow,
|
||||
message: WindowPosMessage,
|
||||
) -> Option<LRESULT> {
|
||||
self.window_manager
|
||||
.handle_window_pos_message(window, &message);
|
||||
match message {
|
||||
WindowPosMessage::WindowPosChanged { .. } => {
|
||||
// Request default processing, otherwise `WM_SIZE` and `WM_MOVE` won't be sent.
|
||||
// https://learn.microsoft.com/en-us/windows/win32/winmsg/wm-windowposchanged#remarks
|
||||
return None;
|
||||
}
|
||||
// "An application should return TRUE if it processes this message."
|
||||
WindowPosMessage::WindowSizeChanging { .. } => return Some(TRUE as LRESULT),
|
||||
_ => (),
|
||||
}
|
||||
Some(0)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn on_host_viewport_change(&mut self, window: &GuiWindow, l_param: LPARAM) {
|
||||
let new_size = size2(LOWORD(l_param as u32) as i32, HIWORD(l_param as u32) as i32);
|
||||
self.update_host_viewport_size(window, &new_size);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn on_close(&mut self, window: &GuiWindow) {
|
||||
if let Err(e) = window.destroy() {
|
||||
error!("Failed to destroy window on WM_CLOSE: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
41
gpu_display/src/gpu_display_win/virtual_display_manager.rs
Normal file
41
gpu_display/src/gpu_display_win/virtual_display_manager.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2023 The ChromiumOS Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use euclid::Box2D;
|
||||
use euclid::Size2D;
|
||||
use euclid::Transform2D;
|
||||
|
||||
use super::HostWindowSpace;
|
||||
use super::VirtualDisplaySpace;
|
||||
|
||||
type HostWindowSize = Size2D<i32, HostWindowSpace>;
|
||||
type VirtualDisplaySize = Size2D<i32, VirtualDisplaySpace>;
|
||||
type HostToGuestTransform = Transform2D<f64, HostWindowSpace, VirtualDisplaySpace>;
|
||||
|
||||
/// This struct is managing the host window to guest display coordinates transform.
|
||||
pub struct NoopVirtualDisplayManager {
|
||||
host_to_guest_transform: HostToGuestTransform,
|
||||
}
|
||||
|
||||
impl NoopVirtualDisplayManager {
|
||||
pub fn new(
|
||||
_host_viewport_size: &HostWindowSize,
|
||||
_virtual_display_size: &VirtualDisplaySize,
|
||||
) -> Self {
|
||||
Self {
|
||||
host_to_guest_transform: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the rectangle to show the virtual display in the host window coordinate.
|
||||
pub fn get_virtual_display_projection_box(&self) -> Box2D<i32, HostWindowSpace> {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub fn update_host_guest_transforms(&mut self, _host_viewport_size: &HostWindowSize) {}
|
||||
|
||||
pub fn get_host_to_guest_transform(&self) -> &HostToGuestTransform {
|
||||
&self.host_to_guest_transform
|
||||
}
|
||||
}
|
39
gpu_display/src/gpu_display_win/window_manager.rs
Normal file
39
gpu_display/src/gpu_display_win/window_manager.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2023 The ChromiumOS Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
use anyhow::Result;
|
||||
use base::Tube;
|
||||
|
||||
use super::math_util::Size;
|
||||
use super::window::GuiWindow;
|
||||
use super::window_message_processor::WindowPosMessage;
|
||||
use super::DisplayProperties;
|
||||
|
||||
pub(crate) struct NoopWindowManager {}
|
||||
|
||||
impl NoopWindowManager {
|
||||
/// If initialized in fullscreen mode, we would use 16:9 aspect ratio when switching to windowed
|
||||
/// mode. Note that the caller should call `set_initial_window_pos()` after window messages can
|
||||
/// be routed to `WindowManager`.
|
||||
pub fn new(
|
||||
_window: &GuiWindow,
|
||||
_display_properties: &DisplayProperties,
|
||||
_initial_host_viewport_size: Size,
|
||||
_gpu_main_display_tube: Option<Rc<Tube>>,
|
||||
) -> Result<Self> {
|
||||
Ok(Self {})
|
||||
}
|
||||
|
||||
/// This should be called only after window messages can be routed to `WindowManager`, since we
|
||||
/// rely on them to properly set the host viewport size after resizing the window.
|
||||
pub fn set_initial_window_pos(&mut self, _window: &GuiWindow) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn handle_display_change(&mut self, _window: &GuiWindow) {}
|
||||
|
||||
pub fn handle_window_pos_message(&mut self, _window: &GuiWindow, _message: &WindowPosMessage) {}
|
||||
}
|
|
@ -12,6 +12,9 @@ use base::error;
|
|||
use base::warn;
|
||||
use base::Tube;
|
||||
use cros_tracing::trace_event;
|
||||
use euclid::point2;
|
||||
use euclid::size2;
|
||||
use euclid::Rect;
|
||||
use linux_input_sys::virtio_input_event;
|
||||
#[cfg(feature = "kiwi")]
|
||||
use vm_control::ServiceSendToGpu;
|
||||
|
@ -25,6 +28,7 @@ use super::keyboard_input_manager::KeyboardInputManager;
|
|||
use super::window::GuiWindow;
|
||||
use super::window::MessagePacket;
|
||||
use super::window_message_dispatcher::DisplayEventDispatcher;
|
||||
use super::HostWindowSpace;
|
||||
use super::ObjectId;
|
||||
use super::Surface;
|
||||
use crate::EventDevice;
|
||||
|
@ -34,7 +38,6 @@ use crate::EventDeviceKind;
|
|||
// Windows will mark the application as "Not Responding", so we'd better finish processing any
|
||||
// message within this timeout and retrieve the next one.
|
||||
// https://docs.microsoft.com/en-us/windows/win32/win7appqual/preventing-hangs-in-windows-applications
|
||||
#[allow(dead_code)]
|
||||
pub(crate) const HANDLE_WINDOW_MESSAGE_TIMEOUT: Duration = Duration::from_secs(5);
|
||||
|
||||
/// Thread message for killing the window during a `WndProcThread` drop. This indicates an error
|
||||
|
@ -54,11 +57,6 @@ pub(crate) const WM_USER_HOST_VIEWPORT_CHANGE_INTERNAL: UINT = WM_USER + 1;
|
|||
/// destructing the message.
|
||||
pub(crate) const WM_USER_HANDLE_DISPLAY_MESSAGE_INTERNAL: UINT = WM_USER + 2;
|
||||
|
||||
/// Message for notifying the Surface (and subsequently, service) of changes to the keyboard layout.
|
||||
/// the lParam contains the keyboard layout id.
|
||||
#[cfg(feature = "kiwi")]
|
||||
pub(crate) const WM_USER_KEYBOARD_LAYOUT_UPDATED_INTERNAL: UINT = WM_USER + 4;
|
||||
|
||||
/// Struct for resources used for Surface creation.
|
||||
pub struct SurfaceResources {
|
||||
pub display_event_dispatcher: DisplayEventDispatcher,
|
||||
|
@ -182,31 +180,37 @@ impl WindowMessageProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
/// Indicates whether the window is getting shown or hidden when receiving `WM_WINDOWPOSCHANGED`.
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum WindowVisibilityChange {
|
||||
Unchanged,
|
||||
Shown,
|
||||
Hidden,
|
||||
}
|
||||
|
||||
impl From<UINT> for WindowVisibilityChange {
|
||||
fn from(flags: UINT) -> Self {
|
||||
if flags & SWP_SHOWWINDOW != 0 {
|
||||
Self::Shown
|
||||
} else if flags & SWP_HIDEWINDOW != 0 {
|
||||
Self::Hidden
|
||||
} else {
|
||||
Self::Unchanged
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// General window messages that multiple modules may want to process, such as the window manager,
|
||||
/// input manager, IME handler, etc.
|
||||
pub enum WindowMessage {
|
||||
/// `WM_ACTIVATE`, "sent to both the window being activated and the window being deactivated."
|
||||
WindowActivate { is_activated: bool },
|
||||
/// `WM_MOUSEACTIVATE`, "sent when the cursor is in an inactive window and the user presses a
|
||||
/// mouse button."
|
||||
MouseActivate { l_param: LPARAM },
|
||||
/// Window location and size related messages.
|
||||
WindowPos(WindowPosMessage),
|
||||
/// Mouse related messages.
|
||||
Mouse(MouseMessage),
|
||||
/// `WM_SETFOCUS`, "sent to a window after it has gained the keyboard focus."
|
||||
KeyboardFocus,
|
||||
/// `WM_INPUT`, "sent to the window that is getting raw input."
|
||||
RawInput { l_param: LPARAM },
|
||||
/// `WM_MOUSEMOVE`, "posted to a window when the cursor moves."
|
||||
MouseMove { w_param: WPARAM, l_param: LPARAM },
|
||||
/// `WM_LBUTTONDOWN` or `WM_LBUTTONUP`, "posted when the user presses/releases the left mouse
|
||||
/// button while the cursor is in the client area of a window."
|
||||
LeftMouseButton { is_down: bool, l_param: LPARAM },
|
||||
/// `WM_RBUTTONDOWN` or `WM_RBUTTONUP`, "posted when the user presses/releases the right mouse
|
||||
/// button while the cursor is in the client area of a window."
|
||||
RightMouseButton { is_down: bool },
|
||||
/// `WM_MOUSEWHEEL`, "sent to the focus window when the mouse wheel is rotated."
|
||||
MouseWheel { w_param: WPARAM, l_param: LPARAM },
|
||||
/// `WM_SETCURSOR`, "sent to a window if the mouse causes the cursor to move within a window and
|
||||
/// mouse input is not captured."
|
||||
SetCursor,
|
||||
/// `WM_KEYDOWN`, `WM_KEYUP`, `WM_SYSKEYDOWN` or `WM_SYSKEYUP`, "posted to the window with the
|
||||
/// keyboard focus when a nonsystem/system key is pressed/released."
|
||||
Key {
|
||||
|
@ -215,12 +219,27 @@ pub enum WindowMessage {
|
|||
w_param: WPARAM,
|
||||
l_param: LPARAM,
|
||||
},
|
||||
/// `WM_DISPLAYCHANGE`, "sent to all windows when the display resolution has changed."
|
||||
DisplayChange,
|
||||
/// `WM_USER_HOST_VIEWPORT_CHANGE_INTERNAL`.
|
||||
HostViewportChange { l_param: LPARAM },
|
||||
/// `WM_CLOSE`, "sent as a signal that a window or an application should terminate."
|
||||
WindowClose,
|
||||
/// Not one of the general window messages we care about.
|
||||
Other(MessagePacket),
|
||||
}
|
||||
|
||||
/// Window location and size related window messages.
|
||||
pub enum WindowPosMessage {
|
||||
/// `WM_WINDOWPOSCHANGING`, "sent to a window whose size, position, or place in the Z order is
|
||||
/// about to change."
|
||||
WindowPosChanging { l_param: LPARAM },
|
||||
/// `WM_WINDOWPOSCHANGED`, "sent to a window whose size, position, or place in the Z order has
|
||||
/// changed."
|
||||
WindowPosChanged { l_param: LPARAM },
|
||||
WindowPosChanged {
|
||||
visibility_change: WindowVisibilityChange,
|
||||
window_rect: Rect<i32, HostWindowSpace>,
|
||||
},
|
||||
/// `WM_SIZING`, "sent to a window that the user is resizing."
|
||||
WindowSizeChanging { w_param: WPARAM, l_param: LPARAM },
|
||||
/// `WM_SIZE`, "sent to a window after its size has changed."
|
||||
|
@ -231,20 +250,44 @@ pub enum WindowMessage {
|
|||
/// `WM_EXITSIZEMOVE`, "sent one time to a window, after it has exited the moving or sizing
|
||||
/// modal loop."
|
||||
ExitSizeMove,
|
||||
/// `WM_DISPLAYCHANGE`, "sent to all windows when the display resolution has changed."
|
||||
DisplayChange,
|
||||
/// `WM_USER_HOST_VIEWPORT_CHANGE_INTERNAL`.
|
||||
HostViewportChange { l_param: LPARAM },
|
||||
/// `WM_USER_KEYBOARD_LAYOUT_UPDATED_INTERNAL`.
|
||||
#[cfg(feature = "kiwi")]
|
||||
KeyboardLayoutChange { layout: isize },
|
||||
/// `WM_CLOSE`, "sent as a signal that a window or an application should terminate."
|
||||
WindowClose,
|
||||
/// `WM_DESTROY`, "sent when a window is being destroyed ... before the child windows are
|
||||
/// destroyed."
|
||||
WindowDestroy,
|
||||
/// Not one of the general window messages we care about.
|
||||
Other(MessagePacket),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for WindowPosMessage {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::WindowPosChanging { .. } => write!(f, "WindowPosChanging"),
|
||||
Self::WindowPosChanged { .. } => write!(f, "WindowPosChanged"),
|
||||
Self::WindowSizeChanging { .. } => write!(f, "WindowSizeChanging"),
|
||||
Self::WindowSizeChanged { .. } => write!(f, "WindowSizeChanged"),
|
||||
Self::EnterSizeMove => write!(f, "EnterSizeMove"),
|
||||
Self::ExitSizeMove => write!(f, "ExitSizeMove"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Mouse related window messages.
|
||||
pub enum MouseMessage {
|
||||
/// `WM_MOUSEACTIVATE`, "sent when the cursor is in an inactive window and the user presses a
|
||||
/// mouse button."
|
||||
MouseActivate { l_param: LPARAM },
|
||||
/// `WM_INPUT`, "sent to the window that is getting raw input."
|
||||
RawInput { l_param: LPARAM },
|
||||
/// `WM_MOUSEMOVE`, "posted to a window when the cursor moves."
|
||||
MouseMove { w_param: WPARAM, l_param: LPARAM },
|
||||
/// `WM_LBUTTONDOWN` or `WM_LBUTTONUP`, "posted when the user presses/releases the left mouse
|
||||
/// button while the cursor is in the client area of a window."
|
||||
LeftMouseButton { is_down: bool, l_param: LPARAM },
|
||||
/// `WM_RBUTTONDOWN` or `WM_RBUTTONUP`, "posted when the user presses/releases the right mouse
|
||||
/// button while the cursor is in the client area of a window."
|
||||
RightMouseButton { is_down: bool },
|
||||
/// `WM_MBUTTONDOWN` or `WM_MBUTTONUP`, "posted when the user presses/releases the middle mouse
|
||||
/// button while the cursor is in the client area of a window."
|
||||
MiddleMouseButton { is_down: bool },
|
||||
/// `WM_MOUSEWHEEL`, "sent to the focus window when the mouse wheel is rotated."
|
||||
MouseWheel { w_param: WPARAM, l_param: LPARAM },
|
||||
/// `WM_SETCURSOR`, "sent to a window if the mouse causes the cursor to move within a window and
|
||||
/// mouse input is not captured."
|
||||
SetCursor,
|
||||
}
|
||||
|
||||
impl From<&MessagePacket> for WindowMessage {
|
||||
|
@ -259,39 +302,50 @@ impl From<&MessagePacket> for WindowMessage {
|
|||
WM_ACTIVATE => Self::WindowActivate {
|
||||
is_activated: w_param != 0,
|
||||
},
|
||||
WM_MOUSEACTIVATE => Self::MouseActivate { l_param },
|
||||
WM_SETFOCUS => Self::KeyboardFocus,
|
||||
WM_INPUT => Self::RawInput { l_param },
|
||||
WM_MOUSEMOVE => Self::MouseMove { w_param, l_param },
|
||||
WM_LBUTTONDOWN | WM_LBUTTONUP => Self::LeftMouseButton {
|
||||
WM_WINDOWPOSCHANGING => {
|
||||
Self::WindowPos(WindowPosMessage::WindowPosChanging { l_param })
|
||||
}
|
||||
WM_WINDOWPOSCHANGED => {
|
||||
// Safe because it will live at least until we finish handling
|
||||
// `WM_WINDOWPOSCHANGED`.
|
||||
let window_pos: WINDOWPOS = unsafe { *(l_param as *mut WINDOWPOS) };
|
||||
Self::WindowPos(WindowPosMessage::WindowPosChanged {
|
||||
visibility_change: window_pos.flags.into(),
|
||||
window_rect: Rect::new(
|
||||
point2(window_pos.x, window_pos.y),
|
||||
size2(window_pos.cx, window_pos.cy),
|
||||
),
|
||||
})
|
||||
}
|
||||
WM_SIZING => Self::WindowPos(WindowPosMessage::WindowSizeChanging { w_param, l_param }),
|
||||
WM_SIZE => Self::WindowPos(WindowPosMessage::WindowSizeChanged { w_param, l_param }),
|
||||
WM_ENTERSIZEMOVE => Self::WindowPos(WindowPosMessage::EnterSizeMove),
|
||||
WM_EXITSIZEMOVE => Self::WindowPos(WindowPosMessage::ExitSizeMove),
|
||||
WM_MOUSEACTIVATE => Self::Mouse(MouseMessage::MouseActivate { l_param }),
|
||||
WM_INPUT => Self::Mouse(MouseMessage::RawInput { l_param }),
|
||||
WM_MOUSEMOVE => Self::Mouse(MouseMessage::MouseMove { w_param, l_param }),
|
||||
WM_LBUTTONDOWN | WM_LBUTTONUP => Self::Mouse(MouseMessage::LeftMouseButton {
|
||||
is_down: msg == WM_LBUTTONDOWN,
|
||||
l_param,
|
||||
},
|
||||
WM_RBUTTONDOWN | WM_RBUTTONUP => Self::RightMouseButton {
|
||||
}),
|
||||
WM_RBUTTONDOWN | WM_RBUTTONUP => Self::Mouse(MouseMessage::RightMouseButton {
|
||||
is_down: msg == WM_RBUTTONDOWN,
|
||||
},
|
||||
WM_MOUSEWHEEL => Self::MouseWheel { w_param, l_param },
|
||||
WM_SETCURSOR => Self::SetCursor,
|
||||
}),
|
||||
WM_MBUTTONDOWN | WM_MBUTTONUP => Self::Mouse(MouseMessage::MiddleMouseButton {
|
||||
is_down: msg == WM_MBUTTONDOWN,
|
||||
}),
|
||||
WM_MOUSEWHEEL => Self::Mouse(MouseMessage::MouseWheel { w_param, l_param }),
|
||||
WM_SETCURSOR => Self::Mouse(MouseMessage::SetCursor),
|
||||
WM_SETFOCUS => Self::KeyboardFocus,
|
||||
WM_KEYDOWN | WM_KEYUP | WM_SYSKEYDOWN | WM_SYSKEYUP => Self::Key {
|
||||
is_sys_key: msg == WM_SYSKEYDOWN || msg == WM_SYSKEYUP,
|
||||
is_down: msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN,
|
||||
w_param,
|
||||
l_param,
|
||||
},
|
||||
WM_WINDOWPOSCHANGING => Self::WindowPosChanging { l_param },
|
||||
WM_WINDOWPOSCHANGED => Self::WindowPosChanged { l_param },
|
||||
WM_SIZING => Self::WindowSizeChanging { w_param, l_param },
|
||||
WM_SIZE => Self::WindowSizeChanged { w_param, l_param },
|
||||
WM_ENTERSIZEMOVE => Self::EnterSizeMove,
|
||||
WM_EXITSIZEMOVE => Self::ExitSizeMove,
|
||||
WM_DISPLAYCHANGE => Self::DisplayChange,
|
||||
WM_USER_HOST_VIEWPORT_CHANGE_INTERNAL => Self::HostViewportChange { l_param },
|
||||
#[cfg(feature = "kiwi")]
|
||||
WM_USER_KEYBOARD_LAYOUT_UPDATED_INTERNAL => {
|
||||
Self::KeyboardLayoutChange { layout: l_param }
|
||||
}
|
||||
WM_CLOSE => Self::WindowClose,
|
||||
WM_DESTROY => Self::WindowDestroy,
|
||||
_ => Self::Other(*packet),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue