1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9#[repr(u8)]
10pub enum Button {
11 Left = 0,
12 Right = 1,
13 Up = 2,
14 Down = 3,
15 O = 4,
17 X = 5,
19}
20
21pub const BUTTON_COUNT: usize = 6;
22
23const REPEAT_DELAY: u32 = 15;
25const REPEAT_EVERY: u32 = 4;
27
28#[derive(Default)]
30pub struct InputState {
31 held: [bool; BUTTON_COUNT],
32 frames_held: [u32; BUTTON_COUNT],
33}
34
35impl InputState {
36 pub fn set_button(&mut self, b: usize, down: bool) {
38 if b < BUTTON_COUNT {
39 self.held[b] = down;
40 }
41 }
42
43 pub fn tick(&mut self) {
45 for i in 0..BUTTON_COUNT {
46 if self.held[i] {
47 self.frames_held[i] = self.frames_held[i].saturating_add(1);
48 } else {
49 self.frames_held[i] = 0;
50 }
51 }
52 }
53
54 pub fn btn(&self, b: u32) -> bool {
56 (b as usize) < BUTTON_COUNT && self.held[b as usize]
57 }
58
59 pub fn btnp(&self, b: u32) -> bool {
62 let i = b as usize;
63 if i >= BUTTON_COUNT {
64 return false;
65 }
66 let f = self.frames_held[i];
67 f == 1 || (f > REPEAT_DELAY && (f - REPEAT_DELAY) % REPEAT_EVERY == 1)
68 }
69
70 pub fn btn_mask(&self) -> u32 {
72 let mut mask = 0;
73 for i in 0..BUTTON_COUNT {
74 if self.held[i] {
75 mask |= 1 << i;
76 }
77 }
78 mask
79 }
80
81 pub fn btnp_mask(&self) -> u32 {
84 let mut mask = 0;
85 for i in 0..BUTTON_COUNT {
86 if self.btnp(i as u32) {
87 mask |= 1 << i;
88 }
89 }
90 mask
91 }
92
93 pub fn clear(&mut self) {
95 self.held = [false; BUTTON_COUNT];
96 self.frames_held = [0; BUTTON_COUNT];
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103
104 #[test]
105 fn btn_reflects_held_state() {
106 let mut s = InputState::default();
107 s.set_button(Button::Right as usize, true);
108 s.tick();
109 assert!(s.btn(1));
110 assert!(!s.btn(0));
111 }
112
113 #[test]
114 fn btnp_fires_once_then_repeats() {
115 let mut s = InputState::default();
116 s.set_button(0, true);
117 s.tick();
118 assert!(s.btnp(0), "fires on first frame");
119 s.tick();
120 assert!(!s.btnp(0), "does not fire on second frame");
121 for _ in 0..(REPEAT_DELAY - 1) {
123 s.tick();
124 }
125 assert!(s.btnp(0), "repeats after delay");
126 s.tick();
127 assert!(!s.btnp(0));
128 }
129
130 #[test]
131 fn release_resets_press() {
132 let mut s = InputState::default();
133 s.set_button(0, true);
134 s.tick();
135 s.set_button(0, false);
136 s.tick();
137 s.set_button(0, true);
138 s.tick();
139 assert!(s.btnp(0), "fires again after release");
140 }
141
142 #[test]
143 fn btn_mask_sets_held_bits() {
144 let mut s = InputState::default();
145 s.set_button(Button::Left as usize, true);
146 s.set_button(Button::X as usize, true);
147 s.tick();
148 assert_eq!(s.btn_mask(), 0b10_0001); }
150
151 #[test]
152 fn btnp_mask_fires_then_clears() {
153 let mut s = InputState::default();
154 s.set_button(2, true); s.tick();
156 assert_eq!(s.btnp_mask(), 1 << 2);
157 s.tick();
158 assert_eq!(s.btnp_mask(), 0);
159 }
160}