Skip to main content

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}