kozan_core/input/mouse.rs
1//! Mouse event types — dedicated structs per event kind.
2//!
3//! Like Chrome's `WebMouseEvent` — each mouse event is a standalone struct
4//! carrying all the context needed for dispatch (position, button, modifiers,
5//! timestamp).
6//!
7//! Chrome equivalent files:
8//! - `third_party/blink/public/common/input/web_mouse_event.h`
9//! - `ui/events/event.h` (`ui::MouseEvent`)
10
11use std::time::Instant;
12
13use super::modifiers::Modifiers;
14
15/// Mouse cursor moved within the view.
16///
17/// Chrome equivalent: `WebMouseEvent` with type `kMouseMove`.
18///
19/// Position is in physical pixels (f64) relative to the view's top-left corner.
20/// Use `ViewContext::scale_factor()` to convert to logical pixels.
21#[derive(Debug, Clone, Copy)]
22pub struct MouseMoveEvent {
23 /// Cursor X position in physical pixels, relative to view origin.
24 pub x: f64,
25 /// Cursor Y position in physical pixels, relative to view origin.
26 pub y: f64,
27 /// Modifier keys and mouse button state at the time of this event.
28 pub modifiers: Modifiers,
29 /// When this event was received from the OS.
30 /// Chrome equivalent: `WebInputEvent::time_stamp_`.
31 pub timestamp: Instant,
32}
33
34/// Mouse button pressed or released.
35///
36/// Chrome equivalent: `WebMouseEvent` with type `kMouseDown` / `kMouseUp`.
37///
38/// Always carries the correct cursor position — the `AppHandler` tracks
39/// cursor position and attaches it (like Chrome's `InputRouterImpl`).
40#[derive(Debug, Clone, Copy)]
41pub struct MouseButtonEvent {
42 /// Cursor X position in physical pixels.
43 pub x: f64,
44 /// Cursor Y position in physical pixels.
45 pub y: f64,
46 /// Which button was pressed or released.
47 pub button: MouseButton,
48 /// Whether the button was pressed or released.
49 pub state: ButtonState,
50 /// Modifier keys and mouse button state at the time of this event.
51 pub modifiers: Modifiers,
52 /// Number of rapid clicks (1 = single click, 2 = double click, etc.).
53 /// Chrome tracks this in `WebMouseEvent::click_count`.
54 pub click_count: u8,
55 /// When this event was received from the OS.
56 pub timestamp: Instant,
57}
58
59/// Mouse cursor entered the view area.
60///
61/// Chrome equivalent: `WebMouseEvent` with type `kMouseEnter`.
62#[derive(Debug, Clone, Copy)]
63pub struct MouseEnterEvent {
64 pub x: f64,
65 pub y: f64,
66 pub modifiers: Modifiers,
67 pub timestamp: Instant,
68}
69
70/// Mouse cursor left the view area.
71///
72/// Chrome equivalent: `WebMouseEvent` with type `kMouseLeave`.
73#[derive(Debug, Clone, Copy)]
74pub struct MouseLeaveEvent {
75 pub modifiers: Modifiers,
76 pub timestamp: Instant,
77}
78
79/// Mouse button identifier.
80///
81/// Chrome equivalent: `WebPointerProperties::Button`.
82#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
83pub enum MouseButton {
84 Left,
85 Right,
86 Middle,
87 Back,
88 Forward,
89 Other(u16),
90}
91
92/// Button press/release state.
93///
94/// Used by both mouse and keyboard events.
95/// Chrome equivalent: part of the event type (`kMouseDown` vs `kMouseUp`).
96#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
97pub enum ButtonState {
98 Pressed,
99 Released,
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 #[test]
107 fn mouse_move_event_carries_modifiers_and_timestamp() {
108 let evt = MouseMoveEvent {
109 x: 100.0,
110 y: 200.0,
111 modifiers: Modifiers::EMPTY.with_ctrl(),
112 timestamp: Instant::now(),
113 };
114 assert!(evt.modifiers.ctrl());
115 assert!(!evt.modifiers.shift());
116 }
117
118 #[test]
119 fn mouse_button_event_has_click_count() {
120 let evt = MouseButtonEvent {
121 x: 50.0,
122 y: 75.0,
123 button: MouseButton::Left,
124 state: ButtonState::Pressed,
125 modifiers: Modifiers::EMPTY,
126 click_count: 2,
127 timestamp: Instant::now(),
128 };
129 assert_eq!(evt.click_count, 2);
130 assert_eq!(evt.button, MouseButton::Left);
131 }
132
133 #[test]
134 fn mouse_button_equality() {
135 assert_eq!(MouseButton::Left, MouseButton::Left);
136 assert_ne!(MouseButton::Left, MouseButton::Right);
137 assert_eq!(MouseButton::Other(4), MouseButton::Other(4));
138 assert_ne!(MouseButton::Other(4), MouseButton::Other(5));
139 }
140
141 #[test]
142 fn positions_are_f64() {
143 let evt = MouseMoveEvent {
144 x: 1920.123456789,
145 y: 1080.987654321,
146 modifiers: Modifiers::EMPTY,
147 timestamp: Instant::now(),
148 };
149 // f64 preserves this precision, f32 would not.
150 assert!((evt.x - 1920.123456789).abs() < 1e-9);
151 assert!((evt.y - 1080.987654321).abs() < 1e-9);
152 }
153}