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 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 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}