agb/input.rs
1use core::ops::BitOr;
2
3use crate::fixnum::Vector2D;
4
5/// Tri-state enum. Allows for -1, 0 and +1.
6/// Useful if checking if the D-Pad is pointing left, right, or unpressed.
7///
8/// Note that [Tri] can be converted directly to a signed integer, so can easily be used to update positions of things in games
9///
10/// # Examples
11/// ```rust
12/// # #![no_std]
13/// # #![no_main]
14/// use agb::input::Tri;
15///
16/// # #[agb::doctest]
17/// # fn test(_: agb::Gba) {
18/// let x = 5;
19/// let tri = Tri::Positive; // e.g. from button_controller.x_tri()
20///
21/// assert_eq!(x + tri as i32, 6);
22/// # }
23/// ```
24#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
25pub enum Tri {
26 /// Right or down
27 Positive = 1,
28 /// Unpressed
29 Zero = 0,
30 /// Left or up
31 Negative = -1,
32}
33
34impl From<(bool, bool)> for Tri {
35 fn from(a: (bool, bool)) -> Tri {
36 let b1 = i8::from(a.0);
37 let b2 = i8::from(a.1);
38 unsafe { core::mem::transmute(b2 - b1) }
39 }
40}
41
42/// Represents a button on the GBA
43///
44/// ```rust
45/// # #![no_main]
46/// # #![no_std]
47/// # #[agb::doctest]
48/// # fn test(_gba: agb::Gba) {
49/// # use agb::input::{Button, ButtonController};
50/// # let mut button_controller = ButtonController::new();
51/// // Check if A is pressed
52/// if button_controller.is_pressed(Button::A) {
53/// // ...
54/// }
55/// # }
56/// ```
57#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
58#[repr(u16)]
59pub enum Button {
60 /// The A button
61 A = 1 << 0,
62 /// The B button
63 B = 1 << 1,
64 /// The SELECT button
65 Select = 1 << 2,
66 /// The START button
67 Start = 1 << 3,
68 /// The RIGHT button on the D-Pad
69 Right = 1 << 4,
70 /// The LEFT button on the D-Pad
71 Left = 1 << 5,
72 /// The UP button on the D-Pad
73 Up = 1 << 6,
74 /// The DOWN button on the D-Pad
75 Down = 1 << 7,
76 /// The R shoulder button on the D-Pad
77 R = 1 << 8,
78 /// The L shoulder button on the D-Pad
79 L = 1 << 9,
80}
81
82const BUTTON_INPUT: *mut u16 = (0x04000130) as *mut u16;
83
84// const BUTTON_INTERRUPT: *mut u16 = (0x04000132) as *mut u16;
85
86/// Helper to make it easy to get the current state of the GBA's buttons.
87///
88/// # Example
89///
90/// ```rust
91/// # #![no_std]
92/// # #![no_main]
93/// use agb::input::{ButtonController, Tri};
94///
95/// # #[agb::doctest]
96/// # fn test(_gba: agb::Gba) {
97/// let mut input = ButtonController::new();
98///
99/// loop {
100/// input.update(); // call update every loop
101///
102/// match input.x_tri() {
103/// Tri::Negative => { /* left is being pressed */ }
104/// Tri::Positive => { /* right is being pressed */ }
105/// Tri::Zero => { /* Neither left nor right (or both) are pressed */ }
106/// }
107/// # break;
108/// }
109/// # }
110/// ```
111#[derive(Clone, Debug)]
112pub struct ButtonController {
113 previous: ButtonState,
114 current: ButtonState,
115}
116
117impl Default for ButtonController {
118 fn default() -> Self {
119 ButtonController::new()
120 }
121}
122
123impl ButtonController {
124 /// Create a new ButtonController.
125 /// This is the preferred way to create it.
126 #[must_use]
127 pub fn new() -> Self {
128 let pressed = ButtonState::current();
129 ButtonController {
130 previous: pressed,
131 current: pressed,
132 }
133 }
134
135 /// Updates the state of the button controller.
136 /// You should call this every frame (either at the start or the end) to ensure that you have the latest state of each button press.
137 /// Calls to any method won't change until you call this.
138 pub fn update(&mut self) {
139 self.update_with_state(ButtonState::current());
140 }
141
142 /// Updates the state of the button controller with a given input.
143 /// This is mainly useful for unit tests where you want to control what input is set. Is equivalent to
144 /// `update()` assuming that the given buttons in `state` are the new ones being pressed
145 pub fn update_with_state(&mut self, state: impl Into<ButtonState>) {
146 self.previous = self.current;
147 self.current = state.into();
148 }
149
150 /// Returns [Tri::Positive] if right is pressed, [Tri::Negative] if left is pressed and [Tri::Zero] if neither or both are pressed.
151 /// This is the normal behaviour you'll want if you're using orthogonal inputs.
152 #[must_use]
153 pub fn x_tri(&self) -> Tri {
154 let left = self.is_pressed(Button::Left);
155 let right = self.is_pressed(Button::Right);
156
157 (left, right).into()
158 }
159
160 /// Returns [Tri::Positive] if down is pressed, [Tri::Negative] if up is pressed and [Tri::Zero] if neither or both are pressed.
161 /// This is the normal behaviour you'll want if you're using orthogonal inputs.
162 #[must_use]
163 pub fn y_tri(&self) -> Tri {
164 let up = self.is_pressed(Button::Up);
165 let down = self.is_pressed(Button::Down);
166
167 (up, down).into()
168 }
169
170 /// Returns [Tri::Positive] if R is pressed, [Tri::Negative] if L is pressed and [Tri::Zero] if neither or both are pressed.
171 #[must_use]
172 pub fn lr_tri(&self) -> Tri {
173 let l = self.is_pressed(Button::L);
174 let r = self.is_pressed(Button::R);
175
176 (l, r).into()
177 }
178
179 /// Returns a vector which represents the current direction being pressed.
180 ///
181 /// ```rust
182 /// # #![no_main]
183 /// # #![no_std]
184 /// # #[agb::doctest]
185 /// # fn test(_gba: agb::Gba) {
186 /// use agb::{
187 /// input::ButtonController,
188 /// fixnum::{Vector2D, Num, vec2, num},
189 /// };
190 ///
191 /// let mut player_position: Vector2D<Num<i32, 8>> = vec2(num!(10), num!(20));
192 /// let mut button_controller = ButtonController::new();
193 ///
194 /// loop {
195 /// button_controller.update();
196 ///
197 /// player_position += button_controller.vector();
198 /// # break;
199 /// }
200 /// # }
201 /// ```
202 #[must_use]
203 pub fn vector<T>(&self) -> Vector2D<T>
204 where
205 T: From<i32> + crate::fixnum::Number,
206 {
207 (self.x_tri() as i32, self.y_tri() as i32).into()
208 }
209
210 #[must_use]
211 /// Returns [Tri::Positive] if right was just pressed, [Tri::Negative] if left was just pressed and [Tri::Zero] if neither or both are just pressed.
212 ///
213 /// Also returns [Tri::Zero] after the call to [`update()`](ButtonController::update()) if the button is still held.
214 pub fn just_pressed_x_tri(&self) -> Tri {
215 let left = self.is_just_pressed(Button::Left);
216 let right = self.is_just_pressed(Button::Right);
217
218 (left, right).into()
219 }
220
221 #[must_use]
222 /// Returns [Tri::Positive] if down was just pressed, [Tri::Negative] if up was just pressed and [Tri::Zero] if neither or both are just pressed.
223 ///
224 /// Also returns [Tri::Zero] after the call to [`update()`](ButtonController::update()) if the button is still held.
225 pub fn just_pressed_y_tri(&self) -> Tri {
226 let up = self.is_just_pressed(Button::Up);
227 let down = self.is_just_pressed(Button::Down);
228
229 (up, down).into()
230 }
231
232 #[must_use]
233 /// Returns [Tri::Positive] if `R` was just pressed, [Tri::Negative] if `L` was just pressed and [Tri::Zero] if neither or both are just pressed.
234 ///
235 /// Also returns [Tri::Zero] after the call to [`update()`](ButtonController::update()) if the button is still held.
236 pub fn just_pressed_lr_tri(&self) -> Tri {
237 let l = self.is_just_pressed(Button::L);
238 let r = self.is_just_pressed(Button::R);
239
240 (l, r).into()
241 }
242
243 #[must_use]
244 /// Returns a vector which represents the direction the button was just pressed in.
245 pub fn just_pressed_vector<T>(&self) -> Vector2D<T>
246 where
247 T: From<i32> + crate::fixnum::Number,
248 {
249 (
250 self.just_pressed_x_tri() as i32,
251 self.just_pressed_y_tri() as i32,
252 )
253 .into()
254 }
255
256 #[must_use]
257 /// Returns `true` if any of the provided buttons are pressed.
258 pub fn is_pressed(&self, buttons: impl Into<ButtonState>) -> bool {
259 self.current.any_pressed(buttons.into())
260 }
261
262 /// Returns `true` if any of the provided buttons are not pressed.
263 #[must_use]
264 pub fn is_released(&self, buttons: impl Into<ButtonState>) -> bool {
265 !self.current.all_pressed(buttons.into())
266 }
267
268 /// Returns true the button specified in `button` went from not pressed to pressed in the last frame.
269 /// Very useful for menu navigation or selection if you want the players actions to only happen for one frame.
270 ///
271 /// If you pass multiple buttons (via [`ButtonState`]), then this will return true if _any_ of the provided
272 /// buttons transitioned from not pressed to pressed
273 ///
274 /// # Example
275 /// ```rust
276 /// # #![no_std]
277 /// # #![no_main]
278 /// use agb::input::{Button, ButtonController};
279 ///
280 /// # #[agb::doctest]
281 /// # fn main(_gba: agb::Gba) {
282 /// let mut button_controller = ButtonController::new();
283 ///
284 /// loop {
285 /// button_controller.update();
286 ///
287 /// if button_controller.is_just_pressed(Button::A) {
288 /// // A button was just pressed, maybe select the currently selected item
289 /// }
290 /// # break;
291 /// }
292 ///
293 /// button_controller.update_with_state(Button::A);
294 /// button_controller.update_with_state(Button::A | Button::B);
295 ///
296 /// assert!(button_controller.is_just_pressed(Button::B));
297 /// // even though A is pressed, it isn't just pressed
298 /// assert!(!button_controller.is_just_pressed(Button::A));
299 /// assert!(button_controller.is_just_pressed(Button::A | Button::B));
300 /// # }
301 /// ```
302 #[must_use]
303 pub fn is_just_pressed(&self, buttons: impl Into<ButtonState>) -> bool {
304 let buttons = buttons.into();
305 ButtonState(self.current.0 & !self.previous.0).any_pressed(buttons)
306 }
307
308 /// Returns true if the button specified in `key` went from pressed to not pressed in the last frame.
309 /// Very useful for menu navigation or selection if you want players actions to only happen for one frame.
310 ///
311 /// If you pass multiple buttons (via [`ButtonState`]), then this will return true if _any_ of the provided
312 /// buttons transitioned from pressed to not pressed.
313 #[must_use]
314 pub fn is_just_released(&self, buttons: impl Into<ButtonState>) -> bool {
315 let buttons = buttons.into();
316 ButtonState(!self.current.0 & self.previous.0).any_pressed(buttons)
317 }
318}
319
320/// Represents the state of potentially multiple buttons being pressed at once
321#[derive(Clone, Copy, PartialEq, Eq)]
322pub struct ButtonState(u16);
323
324impl From<Button> for ButtonState {
325 fn from(value: Button) -> Self {
326 Self::single(value)
327 }
328}
329
330impl BitOr for Button {
331 type Output = ButtonState;
332
333 fn bitor(self, rhs: Self) -> Self::Output {
334 ButtonState(self as u16 | rhs as u16)
335 }
336}
337
338impl BitOr for ButtonState {
339 type Output = Self;
340
341 fn bitor(self, rhs: Self) -> Self::Output {
342 Self(self.0 | rhs.0)
343 }
344}
345
346impl BitOr<Button> for ButtonState {
347 type Output = Self;
348
349 fn bitor(self, rhs: Button) -> Self::Output {
350 Self(self.0 | rhs as u16)
351 }
352}
353
354impl core::fmt::Debug for ButtonState {
355 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
356 write!(f, "ButtonState[")?;
357
358 let mut is_first = true;
359 for b in [
360 Button::A,
361 Button::B,
362 Button::Start,
363 Button::Select,
364 Button::Up,
365 Button::Down,
366 Button::Left,
367 Button::Right,
368 Button::L,
369 Button::R,
370 ] {
371 if self.is_pressed(b) {
372 let maybe_space = if is_first { "" } else { " " };
373 write!(f, "{maybe_space}{b:?}")?;
374
375 is_first = false;
376 }
377 }
378
379 write!(f, "]")
380 }
381}
382
383impl ButtonState {
384 /// Creates a new ButtonState with just a single button pressed (equivalent to `ButtonState::from(...)`)
385 #[must_use]
386 pub const fn single(button: Button) -> Self {
387 Self(button as u16)
388 }
389
390 /// Returns the current button state based on which buttons are being pressed right now
391 #[must_use]
392 pub fn current() -> Self {
393 Self(!unsafe { BUTTON_INPUT.read_volatile() })
394 }
395
396 /// Returns a `ButtonState` where everything is being pressed
397 #[must_use]
398 pub const fn all() -> Self {
399 Self(0b0000_0011_1111_1111)
400 }
401
402 /// Returns a `ButtonState` where nothing is being pressed
403 #[must_use]
404 pub const fn empty() -> Self {
405 Self(0)
406 }
407
408 /// Returns true if the button `button` is pressed in this state
409 #[must_use]
410 pub const fn is_pressed(self, button: Button) -> bool {
411 self.any_pressed(Self::single(button))
412 }
413
414 /// Returns true if the button `button` is released in this state
415 #[must_use]
416 pub const fn is_released(self, button: Button) -> bool {
417 !self.is_pressed(button)
418 }
419
420 /// Returns true if any of the buttons in the button state `state` are pressed in self
421 #[must_use]
422 pub const fn any_pressed(self, state: ButtonState) -> bool {
423 self.0 & state.0 != 0
424 }
425
426 /// Returns true if all of the buttons in the button state `state` are pressed in self
427 #[must_use]
428 pub const fn all_pressed(self, state: ButtonState) -> bool {
429 self.0 & state.0 == state.0
430 }
431}
432
433#[cfg(test)]
434mod test {
435 use crate::Gba;
436
437 use super::*;
438
439 #[test_case]
440 fn test_tri_bool_tuple_from_impl(_gba: &mut Gba) {
441 assert_eq!(Tri::from((true, false)), Tri::Negative);
442 assert_eq!(Tri::from((false, true)), Tri::Positive);
443 assert_eq!(Tri::from((false, false)), Tri::Zero);
444 assert_eq!(Tri::from((true, true)), Tri::Zero);
445 }
446
447 #[test_case]
448 fn test_button_state_is_pressed(_: &mut Gba) {
449 assert!(ButtonState::from(Button::A).is_pressed(Button::A));
450 assert!((Button::A | Button::B).is_pressed(Button::A));
451 assert!(!(Button::A | Button::B).is_pressed(Button::Start));
452 }
453
454 #[test_case]
455 fn test_button_state_is_released(_: &mut Gba) {
456 assert!(ButtonState::from(Button::A).is_released(Button::B));
457 assert!(!ButtonState::from(Button::B).is_released(Button::B));
458 }
459
460 #[test_case]
461 fn test_button_controller_is_just_pressed(_: &mut Gba) {
462 let mut controller = ButtonController::new();
463
464 controller.update_with_state(Button::B);
465 controller.update_with_state(Button::A);
466
467 assert!(controller.is_just_pressed(Button::A));
468 assert!(controller.is_just_released(Button::B));
469 assert!(!controller.is_just_pressed(Button::Start));
470 assert!(!controller.is_just_released(Button::Select));
471 }
472
473 #[test_case]
474 fn test_button_controller_tri(_: &mut Gba) {
475 let mut controller = ButtonController::new();
476
477 controller.update_with_state(Button::L | Button::Right);
478
479 assert_eq!(controller.lr_tri(), Tri::Negative);
480 assert_eq!(controller.x_tri(), Tri::Positive);
481 assert_eq!(controller.y_tri(), Tri::Zero);
482 }
483
484 #[test_case]
485 fn test_button_state_all(_: &mut Gba) {
486 assert!(ButtonState::all().is_pressed(Button::A));
487 assert!(ButtonState::all().is_pressed(Button::L));
488 }
489
490 #[test_case]
491 fn test_just_pressed_multiple(_: &mut Gba) {
492 let mut controller = ButtonController::new();
493
494 controller.update_with_state(ButtonState::empty());
495 controller.update_with_state(Button::A | Button::B);
496
497 assert!(controller.is_just_pressed(Button::A | Button::Start));
498
499 controller.update_with_state(Button::A);
500
501 assert!(!controller.is_just_pressed(Button::A | Button::Start));
502 assert!(controller.is_just_released(Button::B | Button::Select));
503 }
504
505 #[test_case]
506 fn test_can_or_mulitple_buttons(_: &mut Gba) {
507 assert_eq!(
508 Button::A | Button::B | Button::L | Button::R,
509 (Button::A | Button::B) | (Button::L | Button::R)
510 );
511 }
512
513 #[test_case]
514 fn test_debug_format_for_button_state(_: &mut Gba) {
515 let input = Button::A | Button::Up | Button::Select;
516 assert_eq!(alloc::format!("{input:?}"), "ButtonState[A Select Up]");
517 }
518}