1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
#![deny(missing_docs)]
use crate::fixnum::Vector2D;
use bitflags::bitflags;
use core::convert::From;
/// Tri-state enum. Allows for -1, 0 and +1.
/// Useful if checking if the D-Pad is pointing left, right, or unpressed.
///
/// Note that [Tri] can be converted directly to a signed integer, so can easily be used to update positions of things in games
///
/// # Examples
/// ```rust,no_run
/// # #![no_std]
/// use agb::input::Tri;
///
/// # fn main() {
/// let x = 5;
/// let tri = Tri::Positive; // e.g. from button_controller.x_tri()
///
/// assert_eq!(x + tri as i32, 6);
/// # }
/// ```
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub enum Tri {
/// Right or down
Positive = 1,
/// Unpressed
Zero = 0,
/// Left or up
Negative = -1,
}
impl From<(bool, bool)> for Tri {
fn from(a: (bool, bool)) -> Tri {
let b1 = i8::from(a.0);
let b2 = i8::from(a.1);
unsafe { core::mem::transmute(b2 - b1) }
}
}
bitflags! {
/// Represents a button on the GBA
#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
pub struct Button: u32 {
/// The A button
const A = 1 << 0;
/// The B button
const B = 1 << 1;
/// The SELECT button
const SELECT = 1 << 2;
/// The START button
const START = 1 << 3;
/// The RIGHT button on the D-Pad
const RIGHT = 1 << 4;
/// The LEFT button on the D-Pad
const LEFT = 1 << 5;
/// The UP button on the D-Pad
const UP = 1 << 6;
/// The DOWN button on the D-Pad
const DOWN = 1 << 7;
/// The R button on the D-Pad
const R = 1 << 8;
/// The L button on the D-Pad
const L = 1 << 9;
}
}
const BUTTON_INPUT: *mut u16 = (0x04000130) as *mut u16;
// const BUTTON_INTERRUPT: *mut u16 = (0x04000132) as *mut u16;
/// Helper to make it easy to get the current state of the GBA's buttons.
///
/// # Example
///
/// ```rust,no_run
/// # #![no_std]
/// use agb::input::{ButtonController, Tri};
///
/// # fn main() {
/// let mut input = ButtonController::new();
///
/// loop {
/// input.update(); // call update every loop
///
/// match input.x_tri() {
/// Tri::Negative => { /* left is being pressed */ }
/// Tri::Positive => { /* right is being pressed */ }
/// Tri::Zero => { /* Neither left nor right (or both) are pressed */ }
/// }
/// }
/// # }
/// ```
pub struct ButtonController {
previous: u16,
current: u16,
}
impl Default for ButtonController {
fn default() -> Self {
ButtonController::new()
}
}
impl ButtonController {
/// Create a new ButtonController.
/// This is the preferred way to create it.
#[must_use]
pub fn new() -> Self {
let pressed = !unsafe { BUTTON_INPUT.read_volatile() };
ButtonController {
previous: pressed,
current: pressed,
}
}
/// Updates the state of the button controller.
/// 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.
/// Calls to any method won't change until you call this.
pub fn update(&mut self) {
self.previous = self.current;
self.current = !unsafe { BUTTON_INPUT.read_volatile() };
}
/// Returns [Tri::Positive] if right is pressed, [Tri::Negative] if left is pressed and [Tri::Zero] if neither or both are pressed.
/// This is the normal behaviour you'll want if you're using orthogonal inputs.
#[must_use]
pub fn x_tri(&self) -> Tri {
let left = self.is_pressed(Button::LEFT);
let right = self.is_pressed(Button::RIGHT);
(left, right).into()
}
/// Returns [Tri::Positive] if down is pressed, [Tri::Negative] if up is pressed and [Tri::Zero] if neither or both are pressed.
/// This is the normal behaviour you'll want if you're using orthogonal inputs.
#[must_use]
pub fn y_tri(&self) -> Tri {
let up = self.is_pressed(Button::UP);
let down = self.is_pressed(Button::DOWN);
(up, down).into()
}
/// Returns true if all the buttons specified in `keys` are pressed.
#[must_use]
pub fn vector<T>(&self) -> Vector2D<T>
where
T: From<i32> + crate::fixnum::FixedWidthUnsignedInteger,
{
(self.x_tri() as i32, self.y_tri() as i32).into()
}
#[must_use]
/// Returns [Tri::Positive] if left was just pressed, [Tri::Negative] if right was just pressed and [Tri::Zero] if neither or both are just pressed.
///
/// Also returns [Tri::Zero] after the call to [`update()`](ButtonController::update()) if the button is still held.
pub fn just_pressed_x_tri(&self) -> Tri {
let left = self.is_just_pressed(Button::LEFT);
let right = self.is_just_pressed(Button::RIGHT);
(left, right).into()
}
#[must_use]
/// 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.
///
/// Also returns [Tri::Zero] after the call to [`update()`](ButtonController::update()) if the button is still held.
pub fn just_pressed_y_tri(&self) -> Tri {
let up = self.is_just_pressed(Button::UP);
let down = self.is_just_pressed(Button::DOWN);
(up, down).into()
}
#[must_use]
/// Returns a vector which represents the direction the button was just pressed in.
pub fn just_pressed_vector<T>(&self) -> Vector2D<T>
where
T: From<i32> + crate::fixnum::FixedWidthUnsignedInteger,
{
(
self.just_pressed_x_tri() as i32,
self.just_pressed_y_tri() as i32,
)
.into()
}
#[must_use]
/// Returns `true` if the provided keys are all pressed, and `false` if not.
pub fn is_pressed(&self, keys: Button) -> bool {
let currently_pressed = u32::from(self.current);
let keys = keys.bits();
(currently_pressed & keys) != 0
}
/// Returns true if all the buttons specified in `keys` are not pressed. Equivalent to `!is_pressed(keys)`.
#[must_use]
pub fn is_released(&self, keys: Button) -> bool {
!self.is_pressed(keys)
}
/// Returns true if all the buttons specified in `keys` went from not pressed to pressed in the last frame.
/// Very useful for menu navigation or selection if you want the players actions to only happen for one frame.
///
/// # Example
/// ```no_run,rust
/// # #![no_std]
/// use agb::input::{Button, ButtonController};
///
/// # fn main() {
/// let mut button_controller = ButtonController::new();
///
/// loop {
/// button_controller.update();
///
/// if button_controller.is_just_pressed(Button::A) {
/// // A button was just pressed, maybe select the currently selected item
/// }
/// }
/// # }
/// ```
#[must_use]
pub fn is_just_pressed(&self, keys: Button) -> bool {
let current = u32::from(self.current);
let previous = u32::from(self.previous);
let keys = keys.bits();
((current & keys) != 0) && ((previous & keys) == 0)
}
/// Returns true if all the buttons specified in `keys` went from pressed to not pressed in the last frame.
/// Very useful for menu navigation or selection if you want players actions to only happen for one frame.
#[must_use]
pub fn is_just_released(&self, keys: Button) -> bool {
let current = u32::from(self.current);
let previous = u32::from(self.previous);
let keys = keys.bits();
((current & keys) == 0) && ((previous & keys) != 0)
}
}