1use glam::Vec2;
21use std::cell::{Cell, RefCell, RefMut};
22use std::collections::HashSet;
23
24macro_rules! keys {
25 ($($k:ident),+ $(,)?) => {
26 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
28 pub enum Key { $(#[doc = stringify!($k)] $k),+ }
29 impl Key {
30 pub fn from_name(name: &str) -> Option<Key> {
32 match name { $(stringify!($k) => Some(Key::$k),)+ _ => None }
33 }
34 pub fn name(self) -> &'static str {
36 match self { $(Key::$k => stringify!($k),)+ }
37 }
38 }
39 };
40}
41
42keys!(
43 A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, Num0, Num1, Num2, Num3, Num4, Num5, Num6, Num7, Num8,
44 Num9, Space, Enter, Escape, Tab, ArrowLeft, ArrowRight, ArrowUp, ArrowDown, Shift, Ctrl, Alt
45);
46
47#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
49pub enum MouseButton {
50 Left,
52 Right,
54 Middle,
56}
57
58#[derive(Clone, Copy, PartialEq, Eq, Debug)]
60pub enum Source {
61 Key(Key),
63 Mouse(MouseButton),
65}
66
67impl Source {
68 pub fn parse(name: &str) -> Option<Source> {
70 match name {
71 "MouseLeft" => Some(Source::Mouse(MouseButton::Left)),
72 "MouseRight" => Some(Source::Mouse(MouseButton::Right)),
73 "MouseMiddle" => Some(Source::Mouse(MouseButton::Middle)),
74 _ => Key::from_name(name).map(Source::Key),
75 }
76 }
77
78 pub fn name(self) -> &'static str {
80 match self {
81 Source::Key(k) => k.name(),
82 Source::Mouse(MouseButton::Left) => "MouseLeft",
83 Source::Mouse(MouseButton::Right) => "MouseRight",
84 Source::Mouse(MouseButton::Middle) => "MouseMiddle",
85 }
86 }
87}
88
89#[derive(Clone, Debug)]
91pub struct Binding {
92 pub name: String,
94 pub sources: Vec<Source>,
96}
97
98#[derive(Clone, Default, Debug)]
100pub struct Hud {
101 pub crosshair: bool,
103 pub prompt: String,
105 pub message: String,
107 pub message_time: f32,
109 pub objective: String,
111}
112
113#[derive(Default, Clone)]
118pub struct Input {
119 down: HashSet<Key>,
120 pressed: HashSet<Key>,
121 released: HashSet<Key>,
122 mouse_down: HashSet<MouseButton>,
123 mouse_pressed: HashSet<MouseButton>,
124 mouse_released: HashSet<MouseButton>,
125 pub mouse_delta: Vec2,
127 pub scroll: f32,
129 bindings: RefCell<Vec<Binding>>,
131 cursor_lock: Cell<bool>,
132 hud: RefCell<Hud>,
133 scene_request: RefCell<Option<SceneRequest>>,
135 scene_path: RefCell<String>,
137 pub canvas: crate::canvas::Canvas,
139 storage: RefCell<crate::storage::Storage>,
141 quit: Cell<bool>,
143 fullscreen: Cell<Option<bool>>,
144}
145
146#[derive(Clone, Debug, PartialEq)]
148pub enum SceneRequest {
149 Load(String),
151 Add(String),
153 Reload,
155}
156
157impl Input {
158 pub fn key_down(&self, k: Key) -> bool {
160 self.down.contains(&k)
161 }
162 pub fn key_pressed(&self, k: Key) -> bool {
164 self.pressed.contains(&k)
165 }
166 pub fn key_released(&self, k: Key) -> bool {
168 self.released.contains(&k)
169 }
170
171 pub fn mouse_down(&self, b: MouseButton) -> bool {
173 self.mouse_down.contains(&b)
174 }
175 pub fn mouse_pressed(&self, b: MouseButton) -> bool {
177 self.mouse_pressed.contains(&b)
178 }
179
180 pub fn mouse_released(&self, b: MouseButton) -> bool {
182 self.mouse_released.contains(&b)
183 }
184
185 pub fn lock_cursor(&self, lock: bool) {
187 self.cursor_lock.set(lock);
188 }
189 pub fn cursor_locked(&self) -> bool {
191 self.cursor_lock.get()
192 }
193 pub fn request_scene(&self, request: SceneRequest) {
195 *self.scene_request.borrow_mut() = Some(request);
196 }
197 pub fn take_scene_request(&self) -> Option<SceneRequest> {
199 self.scene_request.borrow_mut().take()
200 }
201 pub fn scene_path(&self) -> String {
203 self.scene_path.borrow().clone()
204 }
205 pub fn set_scene_path(&self, path: &str) {
207 *self.scene_path.borrow_mut() = path.to_string();
208 self.storage.borrow_mut().set_scene(path);
209 }
210 pub fn set_storage(&self, storage: crate::storage::Storage) {
212 let scene = self.scene_path();
213 *self.storage.borrow_mut() = storage;
214 self.storage.borrow_mut().set_scene(&scene);
215 }
216 pub fn storage(&self) -> crate::storage::Storage {
218 self.storage.borrow().clone()
219 }
220 pub fn request_quit(&self) {
222 self.quit.set(true);
223 }
224 pub fn quit_requested(&self) -> bool {
226 self.quit.get()
227 }
228 pub fn request_fullscreen(&self, on: bool) {
230 self.fullscreen.set(Some(on));
231 }
232 pub fn take_fullscreen_request(&self) -> Option<bool> {
234 self.fullscreen.take()
235 }
236 pub fn hud(&self) -> RefMut<'_, Hud> {
241 self.hud.borrow_mut()
242 }
243 pub fn begin_frame(&self, dt: f32) {
245 let mut h = self.hud.borrow_mut();
246 h.prompt.clear();
247 let dt = if dt.is_finite() { dt.max(0.0) } else { 0.0 };
248 h.message_time = (h.message_time - dt).max(0.0);
249 }
250
251 pub fn axis(&self, minus: Key, plus: Key) -> f32 {
253 self.key_down(plus) as i32 as f32 - self.key_down(minus) as i32 as f32
254 }
255
256 fn source_down(&self, s: Source) -> bool {
257 match s {
258 Source::Key(k) => self.key_down(k),
259 Source::Mouse(b) => self.mouse_down(b),
260 }
261 }
262
263 fn source_pressed(&self, s: Source) -> bool {
264 match s {
265 Source::Key(k) => self.key_pressed(k),
266 Source::Mouse(b) => self.mouse_pressed(b),
267 }
268 }
269
270 fn with_action<R>(&self, name: &str, f: impl Fn(&Binding) -> R, default: R) -> R {
271 self.bindings.borrow().iter().find(|b| b.name == name).map_or(default, f)
272 }
273
274 pub fn action_down(&self, name: &str) -> bool {
276 self.with_action(name, |b| b.sources.iter().any(|&s| self.source_down(s)), false)
277 }
278
279 pub fn action_pressed(&self, name: &str) -> bool {
281 self.with_action(name, |b| b.sources.iter().any(|&s| self.source_pressed(s)), false)
282 }
283
284 pub fn action_released(&self, name: &str) -> bool {
288 self.with_action(
289 name,
290 |b| {
291 !b.sources.iter().any(|&s| self.source_down(s))
292 && b.sources.iter().any(|&s| match s {
293 Source::Key(k) => self.key_released(k),
294 Source::Mouse(button) => self.mouse_released(button),
295 })
296 },
297 false,
298 )
299 }
300
301 pub fn action_vector(&self, left: &str, right: &str, down: &str, up: &str) -> Vec2 {
304 Vec2::new(self.action_axis(left, right), self.action_axis(down, up)).clamp_length_max(1.0)
305 }
306
307 pub fn has_action(&self, name: &str) -> bool {
309 self.with_action(name, |_| true, false)
310 }
311
312 pub fn remove_action(&self, name: &str) -> bool {
314 let mut bindings = self.bindings.borrow_mut();
315 let before = bindings.len();
316 bindings.retain(|b| b.name != name);
317 before != bindings.len()
318 }
319
320 pub fn try_rebind(&self, name: &str, sources: &[&str]) -> Result<(), String> {
325 for source in sources {
326 if Source::parse(source).is_none() {
327 return Err(format!("unknown input source '{source}'"));
328 }
329 }
330 self.rebind(name, sources);
331 Ok(())
332 }
333
334 pub fn action_axis(&self, negative: &str, positive: &str) -> f32 {
336 self.action_down(positive) as i32 as f32 - self.action_down(negative) as i32 as f32
337 }
338
339 pub fn rebind(&self, name: &str, sources: &[&str]) {
341 let sources: Vec<Source> = sources.iter().filter_map(|s| Source::parse(s)).collect();
342 let mut all = self.bindings.borrow_mut();
343 match all.iter_mut().find(|b| b.name == name) {
344 Some(b) => b.sources = sources,
345 None => all.push(Binding { name: name.to_string(), sources }),
346 }
347 }
348
349 pub fn bindings(&self) -> Vec<(String, Vec<&'static str>)> {
351 self.bindings.borrow().iter().map(|b| (b.name.clone(), b.sources.iter().map(|s| s.name()).collect())).collect()
352 }
353
354 pub fn set_bindings<S: AsRef<str>>(&self, defs: &[(String, Vec<S>)]) {
357 self.bindings.borrow_mut().clear();
358 for (name, sources) in defs {
359 let names: Vec<&str> = sources.iter().map(|s| s.as_ref()).collect();
360 self.rebind(name, &names);
361 }
362 }
363
364 pub fn update(&mut self, keys: HashSet<Key>, buttons: HashSet<MouseButton>, mouse_delta: Vec2, scroll: f32) {
366 self.pressed = keys.difference(&self.down).copied().collect();
367 self.released = self.down.difference(&keys).copied().collect();
368 self.down = keys;
369 self.mouse_pressed = buttons.difference(&self.mouse_down).copied().collect();
370 self.mouse_released = self.mouse_down.difference(&buttons).copied().collect();
371 self.mouse_down = buttons;
372 self.mouse_delta = mouse_delta;
373 self.scroll = scroll;
374 }
375
376 pub fn reset(&mut self) {
379 self.down.clear();
380 self.pressed.clear();
381 self.released.clear();
382 self.mouse_down.clear();
383 self.mouse_pressed.clear();
384 self.mouse_released.clear();
385 self.mouse_delta = Vec2::ZERO;
386 self.scroll = 0.0;
387 self.cursor_lock.set(false);
388 }
389}