2021-06-07 22:23:48 +00:00
|
|
|
use gilrs::{Button, Event as GamepadEvent, EventType as GamepadEventType};
|
2021-07-10 00:19:52 +00:00
|
|
|
use winit_input_helper::WinitInputHelper;
|
2021-03-21 02:11:45 +00:00
|
|
|
|
2021-07-28 04:24:10 +00:00
|
|
|
#[derive(Debug)]
|
2021-03-21 02:11:45 +00:00
|
|
|
pub struct Joypad {
|
2021-06-09 18:43:46 +00:00
|
|
|
/// 0xFF00 | P1/JOYP - Player 1 Joypad
|
|
|
|
pub(crate) p1: u8,
|
2021-06-07 22:23:48 +00:00
|
|
|
ext: JoypadState,
|
|
|
|
interrupt: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for Joypad {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
2021-06-09 18:43:46 +00:00
|
|
|
p1: 0xFF,
|
2021-06-07 22:23:48 +00:00
|
|
|
ext: Default::default(),
|
|
|
|
interrupt: Default::default(),
|
|
|
|
}
|
|
|
|
}
|
2021-03-21 02:21:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Joypad {
|
2021-06-07 00:14:28 +00:00
|
|
|
pub(crate) fn interrupt(&self) -> bool {
|
2021-03-21 02:21:39 +00:00
|
|
|
self.interrupt
|
|
|
|
}
|
|
|
|
|
2021-06-07 00:14:28 +00:00
|
|
|
pub(crate) fn set_interrupt(&mut self, value: bool) {
|
2021-03-21 02:21:39 +00:00
|
|
|
self.interrupt = value;
|
|
|
|
}
|
2021-03-21 02:11:45 +00:00
|
|
|
|
2021-05-04 04:37:30 +00:00
|
|
|
pub(crate) fn update(&mut self, byte: u8) {
|
2021-06-07 22:23:48 +00:00
|
|
|
let direction_row = (byte >> 4) & 0x01 == 0x00;
|
|
|
|
let action_row = (byte >> 5) & 0x01 == 0x00;
|
2021-05-04 04:11:39 +00:00
|
|
|
|
2021-06-07 22:23:48 +00:00
|
|
|
let updated = match (direction_row, action_row) {
|
|
|
|
(true, false) => (byte & 0x30) | self.ext.as_direction_bits(),
|
|
|
|
(false, true) => (byte & 0x30) | self.ext.as_action_bits(),
|
|
|
|
_ => {
|
|
|
|
// TODO: What if both or no rows are selected?
|
2021-05-04 04:11:39 +00:00
|
|
|
|
2021-06-07 22:23:48 +00:00
|
|
|
let merge = self.ext.as_action_bits() | self.ext.as_action_bits();
|
2021-05-04 04:11:39 +00:00
|
|
|
|
2021-06-07 22:23:48 +00:00
|
|
|
(byte & 0x30) | merge
|
|
|
|
}
|
|
|
|
};
|
2021-05-04 04:11:39 +00:00
|
|
|
|
2021-06-09 18:43:46 +00:00
|
|
|
self.p1 = updated
|
2021-05-04 04:11:39 +00:00
|
|
|
}
|
2021-05-03 08:27:23 +00:00
|
|
|
}
|
|
|
|
|
2021-07-28 04:24:10 +00:00
|
|
|
#[derive(Debug, Default)]
|
2021-06-07 22:23:48 +00:00
|
|
|
struct JoypadState {
|
|
|
|
// Direction Row
|
|
|
|
dpad_down: ButtonEvent,
|
|
|
|
dpad_up: ButtonEvent,
|
|
|
|
dpad_left: ButtonEvent,
|
|
|
|
dpad_right: ButtonEvent,
|
|
|
|
// Action Row
|
|
|
|
start: ButtonEvent,
|
|
|
|
select: ButtonEvent,
|
|
|
|
south: ButtonEvent,
|
|
|
|
east: ButtonEvent,
|
2021-03-21 02:11:45 +00:00
|
|
|
}
|
|
|
|
|
2021-06-07 22:23:48 +00:00
|
|
|
impl JoypadState {
|
|
|
|
fn as_direction_bits(&self) -> u8 {
|
|
|
|
(self.dpad_down as u8) << 3
|
|
|
|
| (self.dpad_up as u8) << 2
|
|
|
|
| (self.dpad_left as u8) << 1
|
|
|
|
| self.dpad_right as u8
|
2021-03-21 02:11:45 +00:00
|
|
|
}
|
|
|
|
|
2021-06-07 22:23:48 +00:00
|
|
|
fn as_action_bits(&self) -> u8 {
|
|
|
|
(self.start as u8) << 3
|
|
|
|
| (self.select as u8) << 2
|
|
|
|
| (self.south as u8) << 1
|
|
|
|
| self.east as u8
|
2021-03-21 02:11:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-04 04:11:39 +00:00
|
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
2021-06-07 22:23:48 +00:00
|
|
|
enum ButtonEvent {
|
2021-05-03 08:27:23 +00:00
|
|
|
Pressed = 0,
|
2021-06-07 22:23:48 +00:00
|
|
|
Standby = 1,
|
2021-05-03 08:27:23 +00:00
|
|
|
}
|
2021-03-21 02:11:45 +00:00
|
|
|
|
2021-06-07 22:23:48 +00:00
|
|
|
// used in the context of is_pressed: bool
|
|
|
|
impl From<bool> for ButtonEvent {
|
2021-05-03 08:27:23 +00:00
|
|
|
fn from(value: bool) -> Self {
|
|
|
|
match value {
|
|
|
|
true => Self::Pressed,
|
2021-06-07 22:23:48 +00:00
|
|
|
false => Self::Standby,
|
2021-03-21 02:11:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-07 22:23:48 +00:00
|
|
|
impl Default for ButtonEvent {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::Standby
|
|
|
|
}
|
2021-03-21 02:11:45 +00:00
|
|
|
}
|
|
|
|
|
2021-06-07 22:23:48 +00:00
|
|
|
impl ButtonEvent {
|
|
|
|
fn update(&mut self, is_pressed: bool, irq: &mut bool) {
|
|
|
|
*self = is_pressed.into();
|
|
|
|
|
|
|
|
if let ButtonEvent::Pressed = *self {
|
|
|
|
*irq = true;
|
2021-03-21 02:11:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-20 04:31:03 +00:00
|
|
|
#[inline]
|
2021-07-10 00:19:52 +00:00
|
|
|
pub fn handle_keyboard_input(pad: &mut Joypad, input: &WinitInputHelper) {
|
|
|
|
use winit::event::VirtualKeyCode;
|
|
|
|
|
|
|
|
// TODO: What do I have to do to get a match statement here?
|
|
|
|
|
|
|
|
let state = &mut pad.ext;
|
|
|
|
let irq = &mut pad.interrupt;
|
|
|
|
|
|
|
|
if input.key_pressed(VirtualKeyCode::Down) {
|
|
|
|
state.dpad_down.update(true, irq);
|
2021-08-04 01:23:43 +00:00
|
|
|
}
|
|
|
|
if input.key_released(VirtualKeyCode::Down) {
|
2021-07-10 00:19:52 +00:00
|
|
|
state.dpad_down.update(false, irq);
|
|
|
|
}
|
|
|
|
|
|
|
|
if input.key_pressed(VirtualKeyCode::Up) {
|
|
|
|
state.dpad_up.update(true, irq);
|
2021-08-04 01:23:43 +00:00
|
|
|
}
|
|
|
|
if input.key_released(VirtualKeyCode::Up) {
|
2021-07-10 00:19:52 +00:00
|
|
|
state.dpad_up.update(false, irq);
|
|
|
|
}
|
|
|
|
|
|
|
|
if input.key_pressed(VirtualKeyCode::Left) {
|
|
|
|
state.dpad_left.update(true, irq);
|
2021-08-04 01:23:43 +00:00
|
|
|
}
|
|
|
|
if input.key_released(VirtualKeyCode::Left) {
|
2021-07-10 00:19:52 +00:00
|
|
|
state.dpad_left.update(false, irq);
|
|
|
|
}
|
|
|
|
|
|
|
|
if input.key_pressed(VirtualKeyCode::Right) {
|
|
|
|
state.dpad_right.update(true, irq);
|
2021-08-04 01:23:43 +00:00
|
|
|
}
|
|
|
|
if input.key_released(VirtualKeyCode::Right) {
|
2021-07-10 00:19:52 +00:00
|
|
|
state.dpad_right.update(false, irq);
|
|
|
|
}
|
|
|
|
|
|
|
|
if input.key_pressed(VirtualKeyCode::T) {
|
|
|
|
state.start.update(true, irq);
|
2021-08-04 01:23:43 +00:00
|
|
|
}
|
|
|
|
if input.key_released(VirtualKeyCode::T) {
|
2021-07-10 00:19:52 +00:00
|
|
|
state.start.update(false, irq);
|
|
|
|
}
|
|
|
|
|
|
|
|
if input.key_pressed(VirtualKeyCode::Y) {
|
|
|
|
state.select.update(true, irq);
|
2021-08-04 01:23:43 +00:00
|
|
|
}
|
|
|
|
if input.key_released(VirtualKeyCode::Y) {
|
2021-07-10 00:19:52 +00:00
|
|
|
state.select.update(false, irq);
|
|
|
|
}
|
|
|
|
|
|
|
|
if input.key_pressed(VirtualKeyCode::Z) {
|
|
|
|
state.south.update(true, irq);
|
2021-08-04 01:23:43 +00:00
|
|
|
}
|
|
|
|
if input.key_released(VirtualKeyCode::Z) {
|
2021-07-10 00:19:52 +00:00
|
|
|
state.south.update(false, irq);
|
|
|
|
}
|
|
|
|
|
|
|
|
if input.key_pressed(VirtualKeyCode::X) {
|
|
|
|
state.east.update(true, irq);
|
2021-08-04 01:23:43 +00:00
|
|
|
}
|
|
|
|
if input.key_released(VirtualKeyCode::X) {
|
2021-07-10 00:19:52 +00:00
|
|
|
state.east.update(false, irq);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-20 04:31:03 +00:00
|
|
|
#[inline]
|
2021-06-07 22:23:48 +00:00
|
|
|
pub fn handle_gamepad_input(pad: &mut Joypad, event: GamepadEvent) {
|
|
|
|
use Button::*;
|
|
|
|
use GamepadEventType::*;
|
|
|
|
|
|
|
|
let state = &mut pad.ext;
|
|
|
|
let irq = &mut pad.interrupt;
|
|
|
|
|
|
|
|
match event.event {
|
|
|
|
ButtonPressed(btn, _) => match btn {
|
|
|
|
DPadDown => state.dpad_down.update(true, irq),
|
|
|
|
DPadUp => state.dpad_up.update(true, irq),
|
|
|
|
DPadLeft => state.dpad_left.update(true, irq),
|
|
|
|
DPadRight => state.dpad_right.update(true, irq),
|
|
|
|
Start => state.start.update(true, irq),
|
|
|
|
Select => state.select.update(true, irq),
|
|
|
|
South => state.south.update(true, irq),
|
|
|
|
East => state.east.update(true, irq),
|
|
|
|
_ => {}
|
|
|
|
},
|
|
|
|
ButtonReleased(btn, _) => match btn {
|
|
|
|
DPadDown => state.dpad_down.update(false, irq),
|
|
|
|
DPadUp => state.dpad_up.update(false, irq),
|
|
|
|
DPadLeft => state.dpad_left.update(false, irq),
|
|
|
|
DPadRight => state.dpad_right.update(false, irq),
|
|
|
|
Start => state.start.update(false, irq),
|
|
|
|
Select => state.select.update(false, irq),
|
|
|
|
South => state.south.update(false, irq),
|
|
|
|
East => state.east.update(false, irq),
|
|
|
|
_ => {}
|
|
|
|
},
|
|
|
|
_ => {}
|
2021-03-21 02:11:45 +00:00
|
|
|
}
|
|
|
|
}
|