y_engine/util/
input.rs

1use std::{collections::VecDeque, time::Instant};
2
3use rustc_hash::FxHashSet;
4use winit::{
5    dpi::PhysicalPosition,
6    event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase},
7    keyboard::Key,
8};
9
10#[derive(Debug, Clone)]
11pub enum InputEvent {
12    MousePressed(MouseButton),
13    MouseReleased(MouseButton),
14    MouseWheel(MouseScrollDelta, TouchPhase),
15    CursorMoved(PhysicalPosition<f64>),
16    KeyPressed(Key),
17    KeyReleased(Key),
18    CursorLeftWindow,
19    CursorEnteredWindow,
20}
21
22#[derive(Debug)]
23pub struct InputManager {
24    events: VecDeque<(Instant, InputEvent)>,
25    max_events: usize,
26    prune_cursor_moved_events: bool,
27
28    pressed_keys: FxHashSet<Key>,
29    pressed_mouse_buttons: FxHashSet<MouseButton>,
30    cursor_position: PhysicalPosition<f64>,
31    // This holds the position the cursor was at when the last
32    // cursor_delta() call was made.
33    cursor_position_for_delta: PhysicalPosition<f64>,
34}
35
36impl Default for InputManager {
37    fn default() -> Self {
38        Self {
39            events: VecDeque::new(),
40            max_events: 32,
41            prune_cursor_moved_events: true,
42
43            pressed_keys: FxHashSet::default(),
44            pressed_mouse_buttons: FxHashSet::default(),
45            cursor_position: PhysicalPosition::new(0.0, 0.0),
46            cursor_position_for_delta: PhysicalPosition::new(0.0, 0.0),
47        }
48    }
49}
50
51impl InputManager {
52    pub fn new(max_events: usize, prune_cursor_moved_events: bool) -> Self {
53        Self {
54            events: VecDeque::new(),
55            max_events,
56            prune_cursor_moved_events,
57
58            pressed_keys: FxHashSet::default(),
59            pressed_mouse_buttons: FxHashSet::default(),
60            cursor_position: PhysicalPosition::new(0.0, 0.0),
61            cursor_position_for_delta: PhysicalPosition::new(0.0, 0.0),
62        }
63    }
64
65    pub fn handle_mouse_button_input(&mut self, button: MouseButton, state: ElementState) {
66        let event = match state {
67            ElementState::Pressed => {
68                self.pressed_mouse_buttons.insert(button);
69                InputEvent::MousePressed(button)
70            }
71            ElementState::Released => {
72                self.pressed_mouse_buttons.remove(&button);
73                InputEvent::MouseReleased(button)
74            }
75        };
76        self.push_event(event);
77    }
78
79    pub fn handle_mouse_wheel_input(&mut self, delta: MouseScrollDelta, phase: TouchPhase) {
80        self.push_event(InputEvent::MouseWheel(delta, phase));
81    }
82
83    pub fn handle_cursor_moved(&mut self, position: PhysicalPosition<f64>) {
84        self.cursor_position = position;
85        if self.prune_cursor_moved_events {
86            if let Some((_, InputEvent::CursorMoved(_))) = self.events.back() {
87                self.events.pop_back();
88            }
89        }
90        self.push_event(InputEvent::CursorMoved(position));
91    }
92
93    pub fn handle_keyboard_button_input(&mut self, key: Key, state: ElementState) {
94        let event = match state {
95            ElementState::Pressed => {
96                self.pressed_keys.insert(key.clone());
97                InputEvent::KeyPressed(key)
98            }
99            ElementState::Released => {
100                self.pressed_keys.remove(&key);
101                InputEvent::KeyReleased(key)
102            }
103        };
104        self.push_event(event);
105    }
106
107    pub fn handle_cursor_left_window(&mut self) {
108        self.push_event(InputEvent::CursorLeftWindow);
109    }
110
111    pub fn handle_cursor_entered_window(&mut self) {
112        self.push_event(InputEvent::CursorEnteredWindow);
113    }
114
115    pub fn pop_event(&mut self) -> Option<(Instant, InputEvent)> {
116        self.events.pop_front()
117    }
118
119    fn push_event(&mut self, event: InputEvent) {
120        if self.events.len() >= self.max_events {
121            return;
122        }
123        self.events.push_back((Instant::now(), event));
124    }
125
126    pub fn is_key_pressed(&self, key: &Key) -> bool {
127        self.pressed_keys.contains(key)
128    }
129
130    pub fn set_key_pressed(&mut self, key: Key, pressed: bool) {
131        if pressed {
132            self.pressed_keys.insert(key);
133        } else {
134            self.pressed_keys.remove(&key);
135        }
136    }
137
138    pub fn is_mouse_button_pressed(&self, button: &MouseButton) -> bool {
139        self.pressed_mouse_buttons.contains(button)
140    }
141
142    pub fn set_mouse_button_pressed(&mut self, button: MouseButton, pressed: bool) {
143        if pressed {
144            self.pressed_mouse_buttons.insert(button);
145        } else {
146            self.pressed_mouse_buttons.remove(&button);
147        }
148    }
149
150    pub fn cursor_position(&self) -> PhysicalPosition<f64> {
151        self.cursor_position
152    }
153
154    /// Returns the delta of the cursor position since the last call to this function.
155    ///
156    /// The delta is calculated as the difference between the current cursor position
157    /// and the cursor position at the last call to this function.
158    pub fn cursor_delta(&mut self) -> PhysicalPosition<f64> {
159        let delta = PhysicalPosition::new(
160            self.cursor_position.x - self.cursor_position_for_delta.x,
161            self.cursor_position.y - self.cursor_position_for_delta.y,
162        );
163        self.cursor_position_for_delta = self.cursor_position;
164        delta
165    }
166}