Skip to main content

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}