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:
Pujun Lun 2023-11-22 16:16:06 -08:00 committed by crosvm LUCI
parent cc6191d72c
commit 165acb2e03
6 changed files with 454 additions and 79 deletions

View file

@ -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;

View 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(())
}
}

View file

@ -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);
}
}
}

View 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
}
}

View 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) {}
}

View file

@ -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),
}
}