1use core::fmt;
9
10#[repr(transparent)]
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14pub struct WPARAM(pub usize);
15
16#[repr(transparent)]
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash)]
19#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20pub struct LPARAM(pub isize);
21
22#[repr(transparent)]
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash)]
25#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26pub struct LRESULT(pub isize);
27
28#[repr(transparent)]
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash)]
31#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
32pub struct WParam(pub WPARAM);
33
34impl WParam {
35 pub const fn new(value: usize) -> Self {
37 Self(WPARAM(value))
38 }
39
40 pub const fn raw(&self) -> WPARAM {
42 self.0
43 }
44
45 pub const fn as_usize(&self) -> usize {
47 self.0 .0
48 }
49
50 pub fn as_u32(&self) -> u32 {
52 self.0 .0 as u32
53 }
54
55 pub fn as_i32(&self) -> i32 {
57 self.0 .0 as i32
58 }
59}
60
61impl From<usize> for WParam {
62 fn from(value: usize) -> Self {
63 Self::new(value)
64 }
65}
66
67impl From<WParam> for usize {
68 fn from(wparam: WParam) -> Self {
69 wparam.as_usize()
70 }
71}
72
73impl fmt::Display for WParam {
74 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
75 write!(f, "WPARAM(0x{:X})", self.0 .0)
76 }
77}
78
79#[repr(transparent)]
81#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash)]
82#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
83pub struct LParam(pub LPARAM);
84
85impl LParam {
86 pub const fn new(value: isize) -> Self {
88 Self(LPARAM(value))
89 }
90
91 pub const fn raw(&self) -> LPARAM {
93 self.0
94 }
95
96 pub const fn as_isize(&self) -> isize {
98 self.0 .0
99 }
100
101 pub fn as_u32(&self) -> u32 {
103 self.0 .0 as u32
104 }
105
106 pub fn as_i32(&self) -> i32 {
108 self.0 .0 as i32
109 }
110
111 pub fn as_point(&self) -> (i16, i16) {
113 let value = self.as_u32();
114 ((value & 0xFFFF) as i16, ((value >> 16) & 0xFFFF) as i16)
115 }
116
117 pub fn from_point(x: i16, y: i16) -> Self {
119 let value = ((y as u32) << 16) | (x as u32 & 0xFFFF);
120 Self::new(value as isize)
121 }
122}
123
124impl From<isize> for LParam {
125 fn from(value: isize) -> Self {
126 Self::new(value)
127 }
128}
129
130impl From<LParam> for isize {
131 fn from(lparam: LParam) -> Self {
132 lparam.as_isize()
133 }
134}
135
136impl fmt::Display for LParam {
137 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
138 write!(f, "LPARAM(0x{:X})", self.0 .0)
139 }
140}
141
142#[derive(Debug, Clone, Copy, PartialEq, Eq)]
144#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
145pub enum MouseButton {
146 Left,
148 Right,
150 Middle,
152 X1,
154 X2,
156}
157
158#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
160#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
161pub struct KeyModifiers {
162 pub shift: bool,
164 pub ctrl: bool,
166 pub alt: bool,
168}
169
170#[derive(Debug, Clone, Copy, PartialEq)]
172#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
173pub struct MouseEvent {
174 pub x: i32,
176 pub y: i32,
178 pub button: Option<MouseButton>,
180 pub modifiers: KeyModifiers,
182}
183
184#[derive(Debug, Clone, Copy, PartialEq, Eq)]
186#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
187pub struct KeyEvent {
188 pub virtual_key: u16,
190 pub scan_code: u16,
192 pub modifiers: KeyModifiers,
194 pub repeat_count: u16,
196}
197
198#[derive(Debug, Clone, Copy)]
200#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
201pub struct WindowMessage {
202 pub msg: u32,
204 pub wparam: WParam,
206 pub lparam: LParam,
208}
209
210impl WindowMessage {
211 pub const fn new(msg: u32, wparam: WParam, lparam: LParam) -> Self {
213 Self {
214 msg,
215 wparam,
216 lparam,
217 }
218 }
219
220 pub fn mouse_move(x: i16, y: i16, modifiers: KeyModifiers) -> Self {
222 let wparam = Self::make_mouse_wparam(modifiers, None);
223 let lparam = LParam::from_point(x, y);
224 Self::new(windows_messages::WM_MOUSEMOVE, wparam, lparam)
225 }
226
227 pub fn mouse_button(
229 button: MouseButton,
230 pressed: bool,
231 x: i16,
232 y: i16,
233 modifiers: KeyModifiers,
234 ) -> Self {
235 let msg = match (button, pressed) {
236 (MouseButton::Left, true) => windows_messages::WM_LBUTTONDOWN,
237 (MouseButton::Left, false) => windows_messages::WM_LBUTTONUP,
238 (MouseButton::Right, true) => windows_messages::WM_RBUTTONDOWN,
239 (MouseButton::Right, false) => windows_messages::WM_RBUTTONUP,
240 (MouseButton::Middle, true) => windows_messages::WM_MBUTTONDOWN,
241 (MouseButton::Middle, false) => windows_messages::WM_MBUTTONUP,
242 _ => windows_messages::WM_MOUSEMOVE,
243 };
244
245 let wparam = Self::make_mouse_wparam(modifiers, Some(button));
246 let lparam = LParam::from_point(x, y);
247 Self::new(msg, wparam, lparam)
248 }
249
250 pub fn key_event(msg: u32, virtual_key: u16, scan_code: u16, repeat_count: u16) -> Self {
252 let wparam = WParam::new(virtual_key as usize);
253 let lparam_value = (((scan_code as u32) << 16) | (repeat_count as u32)) as isize;
254 Self::new(msg, wparam, LParam::new(lparam_value))
255 }
256
257 fn make_mouse_wparam(modifiers: KeyModifiers, button: Option<MouseButton>) -> WParam {
258 let mut wparam = 0u32;
259
260 if modifiers.shift {
261 wparam |= 0x0004; }
263 if modifiers.ctrl {
264 wparam |= 0x0008; }
266
267 if let Some(button) = button {
268 match button {
269 MouseButton::Left => wparam |= 0x0001, MouseButton::Right => wparam |= 0x0002, MouseButton::Middle => wparam |= 0x0010, MouseButton::X1 => wparam |= 0x0020, MouseButton::X2 => wparam |= 0x0040, }
275 }
276
277 WParam::new(wparam as usize)
278 }
279}
280
281pub struct MessageParser;
283
284impl MessageParser {
285 pub fn parse_mouse_message(message: WindowMessage) -> Option<MouseEvent> {
287 match message.msg {
288 windows_messages::WM_MOUSEMOVE
289 | windows_messages::WM_LBUTTONDOWN
290 | windows_messages::WM_LBUTTONUP
291 | windows_messages::WM_RBUTTONDOWN
292 | windows_messages::WM_RBUTTONUP
293 | windows_messages::WM_MBUTTONDOWN
294 | windows_messages::WM_MBUTTONUP => {
295 let (x, y) = message.lparam.as_point();
296 let wparam = message.wparam.as_u32();
297
298 let modifiers = KeyModifiers {
299 shift: (wparam & 0x0004) != 0,
300 ctrl: (wparam & 0x0008) != 0,
301 alt: false, };
303
304 let button = match message.msg {
305 windows_messages::WM_LBUTTONDOWN | windows_messages::WM_LBUTTONUP => {
306 Some(MouseButton::Left)
307 }
308 windows_messages::WM_RBUTTONDOWN | windows_messages::WM_RBUTTONUP => {
309 Some(MouseButton::Right)
310 }
311 windows_messages::WM_MBUTTONDOWN | windows_messages::WM_MBUTTONUP => {
312 Some(MouseButton::Middle)
313 }
314 _ => None,
315 };
316
317 Some(MouseEvent {
318 x: x as i32,
319 y: y as i32,
320 button,
321 modifiers,
322 })
323 }
324 _ => None,
325 }
326 }
327
328 pub fn parse_key_message(message: WindowMessage) -> Option<KeyEvent> {
330 match message.msg {
331 windows_messages::WM_KEYDOWN
332 | windows_messages::WM_KEYUP
333 | windows_messages::WM_SYSKEYDOWN
334 | windows_messages::WM_SYSKEYUP => {
335 let virtual_key = message.wparam.as_u32() as u16;
336 let lparam = message.lparam.as_u32();
337
338 let scan_code = ((lparam >> 16) & 0xFF) as u16;
339 let repeat_count = (lparam & 0xFFFF) as u16;
340
341 let modifiers = KeyModifiers::default();
343
344 Some(KeyEvent {
345 virtual_key,
346 scan_code,
347 modifiers,
348 repeat_count,
349 })
350 }
351 _ => None,
352 }
353 }
354
355 pub fn parse_size_message(message: WindowMessage) -> Option<(i32, i32)> {
357 if message.msg == windows_messages::WM_SIZE {
358 let (width, height) = message.lparam.as_point();
359 Some((width as i32, height as i32))
360 } else {
361 None
362 }
363 }
364}
365
366pub mod windows_messages {
370 pub const WM_NULL: u32 = 0x0000;
372 pub const WM_CREATE: u32 = 0x0001;
374 pub const WM_DESTROY: u32 = 0x0002;
376 pub const WM_MOVE: u32 = 0x0003;
378 pub const WM_SIZE: u32 = 0x0005;
380 pub const WM_PAINT: u32 = 0x000F;
382 pub const WM_CLOSE: u32 = 0x0010;
384 pub const WM_QUIT: u32 = 0x0012;
386
387 pub const WM_KEYDOWN: u32 = 0x0100;
389 pub const WM_KEYUP: u32 = 0x0101;
391 pub const WM_SYSKEYDOWN: u32 = 0x0104;
393 pub const WM_SYSKEYUP: u32 = 0x0105;
395
396 pub const WM_MOUSEMOVE: u32 = 0x0200;
398 pub const WM_LBUTTONDOWN: u32 = 0x0201;
400 pub const WM_LBUTTONUP: u32 = 0x0202;
402 pub const WM_RBUTTONDOWN: u32 = 0x0204;
404 pub const WM_RBUTTONUP: u32 = 0x0205;
406 pub const WM_MBUTTONDOWN: u32 = 0x0207;
408 pub const WM_MBUTTONUP: u32 = 0x0208;
410}
411
412#[cfg(feature = "windows-interop")]
414pub mod windows_interop {
441 use super::*;
442
443 impl From<WParam> for windows::Win32::Foundation::WPARAM {
444 fn from(wparam: WParam) -> Self {
445 windows::Win32::Foundation::WPARAM(wparam.as_usize())
446 }
447 }
448
449 impl From<windows::Win32::Foundation::WPARAM> for WParam {
450 fn from(wparam: windows::Win32::Foundation::WPARAM) -> Self {
451 WParam::new(wparam.0)
452 }
453 }
454
455 impl From<LParam> for windows::Win32::Foundation::LPARAM {
456 fn from(lparam: LParam) -> Self {
457 windows::Win32::Foundation::LPARAM(lparam.as_isize())
458 }
459 }
460
461 impl From<windows::Win32::Foundation::LPARAM> for LParam {
462 fn from(lparam: windows::Win32::Foundation::LPARAM) -> Self {
463 LParam::new(lparam.0)
464 }
465 }
466
467 impl From<LRESULT> for windows::Win32::Foundation::LRESULT {
468 fn from(result: LRESULT) -> Self {
469 windows::Win32::Foundation::LRESULT(result.0)
470 }
471 }
472
473 impl From<windows::Win32::Foundation::LRESULT> for LRESULT {
474 fn from(result: windows::Win32::Foundation::LRESULT) -> Self {
475 LRESULT(result.0)
476 }
477 }
478}
479
480#[cfg(test)]
481mod tests {
482 use super::*;
483
484 #[test]
485 fn test_message_creation() {
486 let msg = WindowMessage::mouse_move(100, 200, KeyModifiers::default());
487 assert_eq!(msg.msg, windows_messages::WM_MOUSEMOVE);
488
489 if let Some(mouse_event) = MessageParser::parse_mouse_message(msg) {
490 assert_eq!(mouse_event.x, 100);
491 assert_eq!(mouse_event.y, 200);
492 }
493 }
494
495 #[test]
496 fn test_lparam_point_conversion() {
497 let lparam = LParam::from_point(100, 200);
498 let (x, y) = lparam.as_point();
499 assert_eq!(x, 100);
500 assert_eq!(y, 200);
501 }
502
503 #[test]
504 fn test_type_compatibility() {
505 let our_wparam = WParam::new(0x12345678);
507 let our_lparam = LParam::new(0x87654321);
508
509 assert_eq!(our_wparam.as_usize(), 0x12345678);
511 assert_eq!(our_lparam.as_isize(), 0x87654321);
512 }
513}