1use std::collections::HashSet;
2
3use crate::types::KeyCode;
4
5pub struct InputState {
6 keys_held: HashSet<KeyCode>,
7 keys_pressed: HashSet<KeyCode>,
8}
9
10impl InputState {
11 pub fn new() -> Self {
12 Self {
13 keys_held: HashSet::new(),
14 keys_pressed: HashSet::new(),
15 }
16 }
17
18 pub fn handle_event(&mut self, event: &winit::event::KeyEvent) {
19 if let winit::keyboard::PhysicalKey::Code(keycode) = event.physical_key {
20 let native_keycode = match KeyCode::from_winit_keycode(keycode) {
21 Some(keycode) => keycode,
22 None => todo!("Handle unmapped keycode: {:?}", keycode),
23 };
24 if event.state.is_pressed() {
25 if !self.keys_held.contains(&native_keycode) {
26 self.keys_pressed.insert(native_keycode);
27 }
28 self.keys_held.insert(native_keycode);
29 } else {
30 self.keys_held.remove(&native_keycode);
31 }
32 }
33 }
34
35 pub fn clear_frame_states(&mut self) {
36 self.keys_pressed.clear();
37 }
38
39 pub fn is_key_held(&self, keycode: KeyCode) -> bool {
40 self.keys_held.contains(&keycode)
41 }
42
43 pub fn is_key_pressed(&self, keycode: KeyCode) -> bool {
44 self.keys_pressed.contains(&keycode)
45 }
46
47 pub fn keys_pressed(&self) -> impl Iterator<Item = KeyCode> + '_ {
48 self.keys_pressed.iter().copied()
49 }
50
51 pub fn keys_held(&self) -> impl Iterator<Item = KeyCode> + '_ {
52 self.keys_held.iter().copied()
53 }
54
55 #[cfg(test)]
61 pub(crate) fn for_test(held: impl IntoIterator<Item = KeyCode>, pressed: impl IntoIterator<Item = KeyCode>) -> Self {
62 Self { keys_held: held.into_iter().collect(), keys_pressed: pressed.into_iter().collect() }
63 }
64}
65
66pub struct MouseState {
71 position: (f32, f32),
72 buttons_held: HashSet<winit::event::MouseButton>,
73 buttons_pressed: HashSet<winit::event::MouseButton>,
74 wheel_delta: f32,
75}
76
77impl MouseState {
78 pub fn new() -> Self {
79 Self {
80 position: (0.0, 0.0),
81 buttons_held: HashSet::new(),
82 buttons_pressed: HashSet::new(),
83 wheel_delta: 0.0,
84 }
85 }
86
87 pub fn set_position(&mut self, x: f32, y: f32) {
88 self.position = (x, y);
89 }
90
91 pub fn handle_button(&mut self, button: winit::event::MouseButton, state: winit::event::ElementState) {
92 if state.is_pressed() {
93 if !self.buttons_held.contains(&button) {
94 self.buttons_pressed.insert(button);
95 }
96 self.buttons_held.insert(button);
97 } else {
98 self.buttons_held.remove(&button);
99 }
100 }
101
102 pub fn handle_wheel(&mut self, delta: winit::event::MouseScrollDelta) {
103 self.wheel_delta += match delta {
104 winit::event::MouseScrollDelta::LineDelta(_, y) => y,
105 winit::event::MouseScrollDelta::PixelDelta(pos) => pos.y as f32 / 120.0,
106 };
107 }
108
109 pub fn clear_frame_states(&mut self) {
110 self.buttons_pressed.clear();
111 self.wheel_delta = 0.0;
112 }
113
114 pub fn position(&self) -> (f32, f32) {
115 self.position
116 }
117
118 pub fn is_button_held(&self, button: winit::event::MouseButton) -> bool {
119 self.buttons_held.contains(&button)
120 }
121
122 pub fn is_button_pressed(&self, button: winit::event::MouseButton) -> bool {
123 self.buttons_pressed.contains(&button)
124 }
125
126 pub fn buttons_held(&self) -> impl Iterator<Item = winit::event::MouseButton> + '_ {
127 self.buttons_held.iter().copied()
128 }
129
130 pub fn buttons_pressed(&self) -> impl Iterator<Item = winit::event::MouseButton> + '_ {
131 self.buttons_pressed.iter().copied()
132 }
133
134 pub fn wheel_delta(&self) -> f32 {
135 self.wheel_delta
136 }
137
138 #[cfg(test)]
142 pub(crate) fn for_test(
143 position: (f32, f32),
144 held: impl IntoIterator<Item = winit::event::MouseButton>,
145 pressed: impl IntoIterator<Item = winit::event::MouseButton>,
146 wheel_delta: f32,
147 ) -> Self {
148 Self { position, buttons_held: held.into_iter().collect(), buttons_pressed: pressed.into_iter().collect(), wheel_delta }
149 }
150}