1use serde::{Deserialize, Serialize};
2use std::collections::HashSet;
3
4#[derive(Clone, Serialize, Deserialize)]
15pub struct Input {
16 keys_pressed: HashSet<u32>, keys_just_pressed: HashSet<u32>, keys_just_released: HashSet<u32>, mouse_buttons_pressed: HashSet<u32>,
23 mouse_buttons_just_pressed: HashSet<u32>,
24 mouse_buttons_just_released: HashSet<u32>,
25
26 mouse_position: (f32, f32),
28 mouse_delta: (f32, f32),
29
30 mouse_scroll_delta: f32,
32}
33
34impl Input {
35 pub fn new() -> Self {
36 Self {
37 keys_pressed: HashSet::new(),
38 keys_just_pressed: HashSet::new(),
39 keys_just_released: HashSet::new(),
40 mouse_buttons_pressed: HashSet::new(),
41 mouse_buttons_just_pressed: HashSet::new(),
42 mouse_buttons_just_released: HashSet::new(),
43 mouse_position: (0.0, 0.0),
44 mouse_delta: (0.0, 0.0),
45 mouse_scroll_delta: 0.0,
46 }
47 }
48
49 pub fn begin_frame(&mut self) {
59 for k in &self.keys_just_released {
61 self.keys_pressed.remove(k);
62 }
63 for b in &self.mouse_buttons_just_released {
64 self.mouse_buttons_pressed.remove(b);
65 }
66
67 self.keys_just_pressed.clear();
68 self.keys_just_released.clear();
69 self.mouse_buttons_just_pressed.clear();
70 self.mouse_buttons_just_released.clear();
71 self.mouse_delta = (0.0, 0.0);
72 self.mouse_scroll_delta = 0.0;
73 }
74
75 pub fn pressed_keys(&self) -> Vec<u32> {
79 self.keys_pressed.iter().copied().collect()
80 }
81
82 pub fn on_key_pressed(&mut self, key: u32) {
84 if self.keys_pressed.insert(key) {
85 self.keys_just_pressed.insert(key);
86 }
87 }
88
89 pub fn on_key_released(&mut self, key: u32) {
95 self.keys_just_released.insert(key);
96 if !self.keys_just_pressed.contains(&key) {
97 self.keys_pressed.remove(&key);
99 }
100 }
102
103 #[inline]
105 pub fn is_key_pressed(&self, key: u32) -> bool {
106 self.keys_pressed.contains(&key)
107 }
108
109 #[inline]
111 pub fn is_key_just_pressed(&self, key: u32) -> bool {
112 self.keys_just_pressed.contains(&key)
113 }
114
115 #[inline]
117 pub fn is_key_just_released(&self, key: u32) -> bool {
118 self.keys_just_released.contains(&key)
119 }
120
121 pub fn on_mouse_button_pressed(&mut self, button: u32) {
125 if self.mouse_buttons_pressed.insert(button) {
126 self.mouse_buttons_just_pressed.insert(button);
127 }
128 }
129
130 pub fn on_mouse_button_released(&mut self, button: u32) {
132 self.mouse_buttons_just_released.insert(button);
133 if !self.mouse_buttons_just_pressed.contains(&button) {
134 self.mouse_buttons_pressed.remove(&button);
135 }
136 }
137
138 #[inline]
140 pub fn is_mouse_button_pressed(&self, button: u32) -> bool {
141 self.mouse_buttons_pressed.contains(&button)
142 }
143
144 #[inline]
146 pub fn is_mouse_button_just_pressed(&self, button: u32) -> bool {
147 self.mouse_buttons_just_pressed.contains(&button)
148 }
149
150 #[inline]
152 pub fn is_mouse_button_just_released(&self, button: u32) -> bool {
153 self.mouse_buttons_just_released.contains(&button)
154 }
155
156 pub fn on_mouse_moved(&mut self, x: f32, y: f32) {
162 self.mouse_delta.0 += x - self.mouse_position.0;
163 self.mouse_delta.1 += y - self.mouse_position.1;
164 self.mouse_position = (x, y);
165 }
166
167 pub fn on_mouse_delta(&mut self, dx: f32, dy: f32) {
172 self.mouse_delta.0 += dx;
173 self.mouse_delta.1 += dy;
174 }
175
176 #[inline]
178 pub fn mouse_position(&self) -> (f32, f32) {
179 self.mouse_position
180 }
181
182 #[inline]
184 pub fn mouse_delta(&self) -> (f32, f32) {
185 self.mouse_delta
186 }
187
188 pub fn on_mouse_scroll(&mut self, delta: f32) {
193 self.mouse_scroll_delta += delta;
194 }
195
196 #[inline]
199 pub fn mouse_scroll(&self) -> f32 {
200 self.mouse_scroll_delta
201 }
202}
203
204impl Default for Input {
205 fn default() -> Self {
206 Self::new()
207 }
208}
209
210pub mod mouse {
212 pub const LEFT: u32 = 0;
213 pub const RIGHT: u32 = 1;
214 pub const MIDDLE: u32 = 2;
215}
216
217use std::collections::HashMap;
220
221#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
223pub enum InputBinding {
224 Key(u32),
226 MouseButton(u32),
228}
229
230#[derive(Clone)]
244pub struct ActionMap {
245 bindings: HashMap<String, Vec<InputBinding>>,
246}
247
248impl ActionMap {
249 pub fn new() -> Self {
250 Self {
251 bindings: HashMap::new(),
252 }
253 }
254
255 pub fn bind_key(&mut self, action_name: &str, keycode: u32) {
257 self.bindings
258 .entry(action_name.to_string())
259 .or_default()
260 .push(InputBinding::Key(keycode));
261 }
262
263 pub fn bind_mouse_button(&mut self, action_name: &str, button: u32) {
265 self.bindings
266 .entry(action_name.to_string())
267 .or_default()
268 .push(InputBinding::MouseButton(button));
269 }
270
271 pub fn bind_action(&mut self, action_name: &str, keycode: u32) {
273 self.bind_key(action_name, keycode);
274 }
275
276 pub fn is_action_pressed(&self, input: &Input, action_name: &str) -> bool {
278 if let Some(bindings) = self.bindings.get(action_name) {
279 for binding in bindings {
280 match binding {
281 InputBinding::Key(k) => {
282 if input.is_key_pressed(*k) {
283 return true;
284 }
285 }
286 InputBinding::MouseButton(b) => {
287 if input.is_mouse_button_pressed(*b) {
288 return true;
289 }
290 }
291 }
292 }
293 }
294 false
295 }
296
297 pub fn is_action_just_pressed(&self, input: &Input, action_name: &str) -> bool {
299 if let Some(bindings) = self.bindings.get(action_name) {
300 for binding in bindings {
301 match binding {
302 InputBinding::Key(k) => {
303 if input.is_key_just_pressed(*k) {
304 return true;
305 }
306 }
307 InputBinding::MouseButton(b) => {
308 if input.is_mouse_button_just_pressed(*b) {
309 return true;
310 }
311 }
312 }
313 }
314 }
315 false
316 }
317
318 pub fn is_action_just_released(&self, input: &Input, action_name: &str) -> bool {
320 if let Some(bindings) = self.bindings.get(action_name) {
321 for binding in bindings {
322 match binding {
323 InputBinding::Key(k) => {
324 if input.is_key_just_released(*k) {
325 return true;
326 }
327 }
328 InputBinding::MouseButton(b) => {
329 if input.is_mouse_button_just_released(*b) {
330 return true;
331 }
332 }
333 }
334 }
335 }
336 false
337 }
338}
339
340impl Default for ActionMap {
341 fn default() -> Self {
342 Self::new()
343 }
344}
345
346#[cfg(test)]
347mod tests {
348 use super::*;
349
350 #[test]
353 fn test_fast_tap_preserves_pressed_for_one_frame() {
354 let mut input = Input::new();
355
356 input.on_key_pressed(42);
358 input.on_key_released(42);
359
360 assert!(input.is_key_pressed(42), "fast-tap: tuş pressed olmalı");
362 assert!(
363 input.is_key_just_pressed(42),
364 "fast-tap: tuş just_pressed olmalı"
365 );
366 assert!(
367 input.is_key_just_released(42),
368 "fast-tap: tuş just_released olmalı"
369 );
370
371 input.begin_frame();
373
374 assert!(
376 !input.is_key_pressed(42),
377 "sonraki frame: pressed false olmalı"
378 );
379 assert!(
380 !input.is_key_just_pressed(42),
381 "sonraki frame: just_pressed false olmalı"
382 );
383 assert!(
384 !input.is_key_just_released(42),
385 "sonraki frame: just_released false olmalı"
386 );
387 }
388
389 #[test]
390 fn test_normal_press_release_across_frames() {
391 let mut input = Input::new();
392
393 input.on_key_pressed(10);
395 assert!(input.is_key_pressed(10));
396 assert!(input.is_key_just_pressed(10));
397
398 input.begin_frame();
400 assert!(input.is_key_pressed(10));
401 assert!(!input.is_key_just_pressed(10));
402
403 input.on_key_released(10);
405 assert!(!input.is_key_pressed(10)); assert!(input.is_key_just_released(10));
407
408 input.begin_frame();
410 assert!(!input.is_key_pressed(10));
411 assert!(!input.is_key_just_released(10));
412 }
413
414 #[test]
415 fn test_fast_tap_mouse_button() {
416 let mut input = Input::new();
417
418 input.on_mouse_button_pressed(mouse::LEFT);
419 input.on_mouse_button_released(mouse::LEFT);
420
421 assert!(input.is_mouse_button_pressed(mouse::LEFT));
422 assert!(input.is_mouse_button_just_pressed(mouse::LEFT));
423 assert!(input.is_mouse_button_just_released(mouse::LEFT));
424
425 input.begin_frame();
426
427 assert!(!input.is_mouse_button_pressed(mouse::LEFT));
428 assert!(!input.is_mouse_button_just_pressed(mouse::LEFT));
429 assert!(!input.is_mouse_button_just_released(mouse::LEFT));
430 }
431
432 #[test]
435 fn test_mouse_moved_accumulates_delta() {
436 let mut input = Input::new();
437
438 input.on_mouse_moved(100.0, 200.0);
439 assert_eq!(input.mouse_delta(), (100.0, 200.0));
441
442 input.on_mouse_moved(150.0, 250.0);
443 assert_eq!(input.mouse_delta(), (150.0, 250.0));
445
446 assert_eq!(input.mouse_position(), (150.0, 250.0));
447 }
448
449 #[test]
450 fn test_mouse_delta_resets_on_begin_frame() {
451 let mut input = Input::new();
452
453 input.on_mouse_moved(100.0, 200.0);
454 assert_ne!(input.mouse_delta(), (0.0, 0.0));
455
456 input.begin_frame();
457 assert_eq!(input.mouse_delta(), (0.0, 0.0));
458 assert_eq!(input.mouse_position(), (100.0, 200.0));
460 }
461
462 #[test]
465 fn test_scroll_accumulates_and_resets() {
466 let mut input = Input::new();
467
468 input.on_mouse_scroll(3.0);
469 input.on_mouse_scroll(-1.0);
470 assert_eq!(input.mouse_scroll(), 2.0);
471
472 input.begin_frame();
473 assert_eq!(input.mouse_scroll(), 0.0);
474 }
475
476 #[test]
479 fn test_pressed_keys() {
480 let mut input = Input::new();
481 input.on_key_pressed(1);
482 input.on_key_pressed(2);
483 input.on_key_pressed(3);
484
485 let mut keys = input.pressed_keys();
486 keys.sort();
487 assert_eq!(keys, vec![1, 2, 3]);
488 }
489
490 #[test]
493 fn test_action_map_key_binding() {
494 let mut input = Input::new();
495 let mut actions = ActionMap::new();
496 actions.bind_key("Jump", 42);
497
498 input.on_key_pressed(42);
499 assert!(actions.is_action_pressed(&input, "Jump"));
500 assert!(actions.is_action_just_pressed(&input, "Jump"));
501 }
502
503 #[test]
504 fn test_action_map_mouse_binding() {
505 let mut input = Input::new();
506 let mut actions = ActionMap::new();
507 actions.bind_mouse_button("Attack", mouse::LEFT);
508
509 input.on_mouse_button_pressed(mouse::LEFT);
510 assert!(actions.is_action_pressed(&input, "Attack"));
511 assert!(actions.is_action_just_pressed(&input, "Attack"));
512
513 input.begin_frame();
514 input.on_mouse_button_released(mouse::LEFT);
515 assert!(actions.is_action_just_released(&input, "Attack"));
516 }
517
518 #[test]
519 fn test_action_map_mixed_bindings() {
520 let mut input = Input::new();
521 let mut actions = ActionMap::new();
522 actions.bind_key("Fire", 42);
523 actions.bind_mouse_button("Fire", mouse::LEFT);
524
525 assert!(!actions.is_action_pressed(&input, "Fire"));
527
528 input.on_mouse_button_pressed(mouse::LEFT);
530 assert!(actions.is_action_pressed(&input, "Fire"));
531
532 input.begin_frame();
533 input.on_mouse_button_released(mouse::LEFT);
534
535 input.on_key_pressed(42);
537 assert!(actions.is_action_pressed(&input, "Fire"));
538 }
539
540 #[test]
541 fn test_action_map_just_released() {
542 let mut input = Input::new();
543 let mut actions = ActionMap::new();
544 actions.bind_key("Charge", 99);
545
546 input.on_key_pressed(99);
547 input.begin_frame();
548 input.on_key_released(99);
549
550 assert!(actions.is_action_just_released(&input, "Charge"));
551 assert!(!actions.is_action_pressed(&input, "Charge"));
552 }
553
554 #[test]
555 fn test_bind_action_backward_compat() {
556 let mut actions = ActionMap::new();
557 actions.bind_action("Jump", 42); assert!(matches!(
559 actions.bindings.get("Jump").unwrap()[0],
560 InputBinding::Key(42)
561 ));
562 }
563}
564
565#[derive(Serialize, Deserialize, Clone)]
566pub struct FrameRecord {
567 pub dt: f32,
568 pub input: Input,
569}
570
571#[derive(Serialize, Deserialize, Clone)]
572pub struct PlaybackData {
573 pub frames: Vec<FrameRecord>,
574}
575
576impl PlaybackData {
577 pub fn save(&self, path: &str) -> Result<(), String> {
578 let string_data = ron::ser::to_string_pretty(self, ron::ser::PrettyConfig::default())
579 .map_err(|e| format!("Serilestirme hatasi: {}", e))?;
580 std::fs::write(path, string_data).map_err(|e| format!("Dosya yazma hatasi: {}", e))?;
581 Ok(())
582 }
583
584 pub fn load(path: &str) -> Result<Self, String> {
585 let string_data =
586 std::fs::read_to_string(path).map_err(|e| format!("Dosya okuma hatasi: {}", e))?;
587 ron::from_str(&string_data).map_err(|e| format!("Deserilestirme hatasi: {}", e))
588 }
589}