1#[cfg(feature = "bit-ops")]
11use crate::bit_ops::{hiword, loword, make_long};
12
13#[cfg(target_pointer_width = "32")]
15pub type WPARAM = u32;
16
17#[cfg(target_pointer_width = "64")]
19pub type WPARAM = u64;
20
21#[cfg(target_pointer_width = "32")]
23pub type LPARAM = i32;
24
25#[cfg(target_pointer_width = "64")]
27pub type LPARAM = i64;
28
29#[cfg(target_pointer_width = "32")]
31pub type LRESULT = i32;
32
33#[cfg(target_pointer_width = "64")]
35pub type LRESULT = i64;
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
40pub struct WParam(WPARAM);
41
42impl WParam {
43 pub const fn new(value: WPARAM) -> Self {
45 Self(value)
46 }
47
48 pub const fn raw(&self) -> WPARAM {
50 self.0
51 }
52
53 pub fn as_u32(&self) -> u32 {
55 self.0 as u32
56 }
57
58 pub fn as_i32(&self) -> i32 {
60 self.0 as i32
61 }
62}
63
64impl From<WPARAM> for WParam {
65 fn from(value: WPARAM) -> Self {
66 Self::new(value)
67 }
68}
69
70impl From<WParam> for WPARAM {
71 fn from(wparam: WParam) -> Self {
72 wparam.raw()
73 }
74}
75
76#[derive(Debug, Clone, Copy, PartialEq, Eq)]
78#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
79pub struct LParam(LPARAM);
80
81impl LParam {
82 pub const fn new(value: LPARAM) -> Self {
84 Self(value)
85 }
86
87 pub const fn raw(&self) -> LPARAM {
89 self.0
90 }
91
92 pub fn as_u32(&self) -> u32 {
94 self.0 as u32
95 }
96
97 pub fn as_i32(&self) -> i32 {
99 self.0 as i32
100 }
101
102 pub fn as_point(&self) -> (i16, i16) {
104 let value = self.as_u32();
105 #[cfg(feature = "bit-ops")]
107 {
108 (loword(value) as i16, hiword(value) as i16)
109 }
110 #[cfg(not(feature = "bit-ops"))]
112 {
113 ((value & 0xFFFF) as i16, ((value >> 16) & 0xFFFF) as i16)
114 }
115 }
116
117 pub fn from_point(x: i16, y: i16) -> Self {
119 #[cfg(feature = "bit-ops")]
120 {
121 Self::new(make_long(y as u16, x as u16) as LPARAM)
122 }
123 #[cfg(not(feature = "bit-ops"))]
124 {
125 let value = ((y as u32) << 16) | (x as u32);
126 Self::new(value as LPARAM)
127 }
128 }
129}
130
131impl From<LPARAM> for LParam {
132 fn from(value: LPARAM) -> Self {
133 Self::new(value)
134 }
135}
136
137impl From<LParam> for LPARAM {
138 fn from(lparam: LParam) -> Self {
139 lparam.raw()
140 }
141}
142
143#[derive(Debug, Clone, Copy, PartialEq, Eq)]
145#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
146pub enum MouseButton {
147 Left,
149 Right,
151 Middle,
153 X1,
155 X2,
157}
158
159#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
161#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
162pub struct KeyModifiers {
163 pub shift: bool,
165 pub ctrl: bool,
167 pub alt: bool,
169}
170
171#[derive(Debug, Clone, Copy, PartialEq)]
173#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
174pub struct MouseEvent {
175 pub x: i32,
177 pub y: i32,
179 pub button: Option<MouseButton>,
181 pub modifiers: KeyModifiers,
183}
184
185#[derive(Debug, Clone, Copy, PartialEq, Eq)]
187#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
188pub struct KeyEvent {
189 pub virtual_key: u16,
191 pub scan_code: u16,
193 pub modifiers: KeyModifiers,
195 pub repeat_count: u16,
197}
198
199#[derive(Debug, Clone, Copy)]
201#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
202pub struct WindowMessage {
203 pub msg: u32,
205 pub wparam: WParam,
207 pub lparam: LParam,
209}
210
211impl WindowMessage {
212 pub const fn new(msg: u32, wparam: WParam, lparam: LParam) -> Self {
214 Self {
215 msg,
216 wparam,
217 lparam,
218 }
219 }
220
221 pub fn mouse_move(x: i16, y: i16, modifiers: KeyModifiers) -> Self {
223 let wparam = Self::make_mouse_wparam(modifiers, None);
224 let lparam = LParam::from_point(x, y);
225 Self::new(windows_messages::WM_MOUSEMOVE, wparam, lparam)
226 }
227
228 pub fn mouse_button(
230 button: MouseButton,
231 pressed: bool,
232 x: i16,
233 y: i16,
234 modifiers: KeyModifiers,
235 ) -> Self {
236 let msg = match (button, pressed) {
237 (MouseButton::Left, true) => windows_messages::WM_LBUTTONDOWN,
238 (MouseButton::Left, false) => windows_messages::WM_LBUTTONUP,
239 (MouseButton::Right, true) => windows_messages::WM_RBUTTONDOWN,
240 (MouseButton::Right, false) => windows_messages::WM_RBUTTONUP,
241 (MouseButton::Middle, true) => windows_messages::WM_MBUTTONDOWN,
242 (MouseButton::Middle, false) => windows_messages::WM_MBUTTONUP,
243 _ => windows_messages::WM_MOUSEMOVE,
244 };
245
246 let wparam = Self::make_mouse_wparam(modifiers, Some(button));
247 let lparam = LParam::from_point(x, y);
248 Self::new(msg, wparam, lparam)
249 }
250
251 pub fn key_event(msg: u32, virtual_key: u16, scan_code: u16, repeat_count: u16) -> Self {
253 let wparam = WParam::new(virtual_key as WPARAM);
254 #[cfg(feature = "bit-ops")]
255 let lparam_value = {
256 let high = ((scan_code as u32) << 16 | (repeat_count as u32)) >> 16;
257 let low = (repeat_count as u32) & 0xFFFF;
258 make_long(high as u16, low as u16) as LPARAM
259 };
260 #[cfg(not(feature = "bit-ops"))]
261 let lparam_value = (((scan_code as u32) << 16) | (repeat_count as u32)) as LPARAM;
262 Self::new(msg, wparam, LParam::new(lparam_value))
263 }
264
265 fn make_mouse_wparam(modifiers: KeyModifiers, button: Option<MouseButton>) -> WParam {
266 let mut wparam = 0u32;
267
268 if modifiers.shift {
269 wparam |= 0x0004; }
271 if modifiers.ctrl {
272 wparam |= 0x0008; }
274
275 if let Some(button) = button {
276 match button {
277 MouseButton::Left => wparam |= 0x0001, MouseButton::Right => wparam |= 0x0002, MouseButton::Middle => wparam |= 0x0010, MouseButton::X1 => wparam |= 0x0020, MouseButton::X2 => wparam |= 0x0040, }
283 }
284
285 WParam::new(wparam as WPARAM)
286 }
287}
288
289pub struct MessageParser;
291
292impl MessageParser {
293 pub fn parse_mouse_message(message: WindowMessage) -> Option<MouseEvent> {
295 match message.msg {
296 windows_messages::WM_MOUSEMOVE
297 | windows_messages::WM_LBUTTONDOWN
298 | windows_messages::WM_LBUTTONUP
299 | windows_messages::WM_RBUTTONDOWN
300 | windows_messages::WM_RBUTTONUP
301 | windows_messages::WM_MBUTTONDOWN
302 | windows_messages::WM_MBUTTONUP => {
303 let (x, y) = message.lparam.as_point();
304 let wparam = message.wparam.as_u32();
305
306 let modifiers = KeyModifiers {
307 shift: (wparam & 0x0004) != 0,
308 ctrl: (wparam & 0x0008) != 0,
309 alt: false, };
311
312 let button = match message.msg {
313 windows_messages::WM_LBUTTONDOWN | windows_messages::WM_LBUTTONUP => {
314 Some(MouseButton::Left)
315 }
316 windows_messages::WM_RBUTTONDOWN | windows_messages::WM_RBUTTONUP => {
317 Some(MouseButton::Right)
318 }
319 windows_messages::WM_MBUTTONDOWN | windows_messages::WM_MBUTTONUP => {
320 Some(MouseButton::Middle)
321 }
322 _ => None,
323 };
324
325 Some(MouseEvent {
326 x: x as i32,
327 y: y as i32,
328 button,
329 modifiers,
330 })
331 }
332 _ => None,
333 }
334 }
335
336 pub fn parse_key_message(message: WindowMessage) -> Option<KeyEvent> {
338 match message.msg {
339 windows_messages::WM_KEYDOWN
340 | windows_messages::WM_KEYUP
341 | windows_messages::WM_SYSKEYDOWN
342 | windows_messages::WM_SYSKEYUP => {
343 let virtual_key = message.wparam.as_u32() as u16;
344 let lparam = message.lparam.as_u32();
345
346 let scan_code = ((lparam >> 16) & 0xFF) as u16;
347 let repeat_count = (lparam & 0xFFFF) as u16;
348
349 let modifiers = KeyModifiers::default();
351
352 Some(KeyEvent {
353 virtual_key,
354 scan_code,
355 modifiers,
356 repeat_count,
357 })
358 }
359 _ => None,
360 }
361 }
362
363 pub fn parse_size_message(message: WindowMessage) -> Option<(i32, i32)> {
365 if message.msg == windows_messages::WM_SIZE {
366 let (width, height) = message.lparam.as_point();
367 Some((width as i32, height as i32))
368 } else {
369 None
370 }
371 }
372}
373
374pub mod windows_messages {
378 pub const WM_NULL: u32 = 0x0000;
380 pub const WM_CREATE: u32 = 0x0001;
382 pub const WM_DESTROY: u32 = 0x0002;
384 pub const WM_MOVE: u32 = 0x0003;
386 pub const WM_SIZE: u32 = 0x0005;
388 pub const WM_PAINT: u32 = 0x000F;
390 pub const WM_CLOSE: u32 = 0x0010;
392 pub const WM_QUIT: u32 = 0x0012;
394
395 pub const WM_KEYDOWN: u32 = 0x0100;
397 pub const WM_KEYUP: u32 = 0x0101;
399 pub const WM_SYSKEYDOWN: u32 = 0x0104;
401 pub const WM_SYSKEYUP: u32 = 0x0105;
403
404 pub const WM_MOUSEMOVE: u32 = 0x0200;
406 pub const WM_LBUTTONDOWN: u32 = 0x0201;
408 pub const WM_LBUTTONUP: u32 = 0x0202;
410 pub const WM_RBUTTONDOWN: u32 = 0x0204;
412 pub const WM_RBUTTONUP: u32 = 0x0205;
414 pub const WM_MBUTTONDOWN: u32 = 0x0207;
416 pub const WM_MBUTTONUP: u32 = 0x0208;
418}
419
420#[cfg(test)]
421mod tests {
422 use super::*;
423
424 #[test]
425 fn test_message_creation() {
426 let msg = WindowMessage::mouse_move(100, 200, KeyModifiers::default());
427 assert_eq!(msg.msg, windows_messages::WM_MOUSEMOVE);
428
429 if let Some(mouse_event) = MessageParser::parse_mouse_message(msg) {
430 assert_eq!(mouse_event.x, 100);
431 assert_eq!(mouse_event.y, 200);
432 }
433 }
434
435 #[test]
436 fn test_lparam_point_conversion() {
437 let lparam = LParam::from_point(100, 200);
438 let (x, y) = lparam.as_point();
439 assert_eq!(x, 100);
440 assert_eq!(y, 200);
441 }
442}