use super::gamepad::GamepadState;
use crate::input::host_input::HostInput;
use crate::ConnectedSocket;
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum InputDeviceState {
Gamepad(GamepadState),
Disconnected,
}
impl Default for InputDeviceState {
fn default() -> Self {
Self::Disconnected
}
}
#[derive(Default)]
struct InputRegister {
cached_state: InputDeviceState,
gamepad_bits_shift: u8,
connected_socket: ConnectedSocket,
strobe_mode_on: bool,
}
pub struct InputRegisters {
player1: InputRegister,
player2: InputRegister,
}
impl Default for InputRegisters {
fn default() -> Self {
Self::new()
}
}
impl InputRegisters {
pub fn new() -> Self {
Self {
player1: InputRegister::new(ConnectedSocket::Player1),
player2: InputRegister::new(ConnectedSocket::Player2),
}
}
pub fn set_strobe_mode_on(&mut self) {
self.player1.set_strobe_mode_on();
self.player2.set_strobe_mode_on();
}
pub fn set_strobe_mode_off(&mut self, host_input: &mut impl HostInput) {
self.player1.set_strobe_mode_off(host_input);
self.player2.set_strobe_mode_off(host_input);
}
pub fn read_register(
&mut self,
host_input: &mut impl HostInput,
player: ConnectedSocket,
) -> u8 {
match player {
ConnectedSocket::Player1 => self.player1.read_register(host_input),
ConnectedSocket::Player2 => self.player2.read_register(host_input),
}
}
}
impl InputRegister {
fn new(connected_socket: ConnectedSocket) -> Self {
Self {
connected_socket,
..Default::default()
}
}
fn set_strobe_mode_on(&mut self) {
self.strobe_mode_on = true;
}
fn set_strobe_mode_off(&mut self, host_input: &mut impl HostInput) {
if self.strobe_mode_on == true {
self.strobe_mode_on = false;
self.cached_state = host_input.input_device_state(self.connected_socket);
if let InputDeviceState::Gamepad(state) = self.cached_state {
self.gamepad_bits_shift = state.buttons_pressed.bits();
}
}
}
fn read_register(&mut self, host_input: &mut impl HostInput) -> u8 {
if self.strobe_mode_on == true {
self.cached_state = host_input.input_device_state(self.connected_socket);
if let InputDeviceState::Gamepad(state) = self.cached_state {
self.gamepad_bits_shift = state.buttons_pressed.bits();
}
}
let result;
match self.cached_state {
InputDeviceState::Gamepad(_) => {
result = self.gamepad_bits_shift & 1;
}
InputDeviceState::Disconnected => result = 0,
}
if self.strobe_mode_on == false {
self.gamepad_bits_shift = (self.gamepad_bits_shift >> 1) | (1 << 7);
}
result
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::input::gamepad::GamepadButtonsPressedFlags;
struct MockHostInput {
inner: InputDeviceState,
}
impl HostInput for MockHostInput {
fn input_device_state(&mut self, _player: ConnectedSocket) -> InputDeviceState {
self.inner
}
}
#[test]
fn inputreg_querystatestrobeon_alwaysreturnfirstbutton() {
let mut input = InputRegister::new(ConnectedSocket::Player1);
let state_flags = GamepadButtonsPressedFlags::A;
let device_state = InputDeviceState::Gamepad(GamepadState::new(state_flags));
let mut host_input = MockHostInput {
inner: device_state,
};
input.set_strobe_mode_on();
for _ in 0..16 {
assert_eq!(input.read_register(&mut host_input), 1);
}
let device_state = InputDeviceState::Gamepad(GamepadState::new(state_flags.complement()));
let mut host_input = MockHostInput {
inner: device_state,
};
for _ in 0..16 {
assert_eq!(input.read_register(&mut host_input), 0);
}
}
#[test]
fn inputreg_querystate_statechangesafterstrobe() {
let mut input = InputRegister::new(ConnectedSocket::Player1);
let device_state =
InputDeviceState::Gamepad(GamepadState::new(GamepadButtonsPressedFlags::A));
let mut host_input = MockHostInput {
inner: device_state,
};
assert_eq!(input.read_register(&mut host_input), 0);
input.set_strobe_mode_on();
assert_eq!(input.read_register(&mut host_input), 1);
}
#[test]
fn inputreg_querystate_buttonsshiftcorrect() {
let buttons = [
GamepadButtonsPressedFlags::A,
GamepadButtonsPressedFlags::B,
GamepadButtonsPressedFlags::SELECT,
GamepadButtonsPressedFlags::START,
GamepadButtonsPressedFlags::UP,
GamepadButtonsPressedFlags::DOWN,
GamepadButtonsPressedFlags::LEFT,
GamepadButtonsPressedFlags::RIGHT,
];
let mut input = InputRegister::new(ConnectedSocket::Player1);
for state_bits in 0..u8::MAX {
let state_flags = GamepadButtonsPressedFlags::from_bits(state_bits)
.expect("Invalid bits for gamepad flags (all combinations should be valid!!)");
let device_state = InputDeviceState::Gamepad(GamepadState::new(state_flags));
let mut host_input = MockHostInput {
inner: device_state,
};
input.set_strobe_mode_on();
input.set_strobe_mode_off(&mut host_input);
for &button_flag in buttons.iter() {
if input.read_register(&mut host_input) == 0 {
assert!(!state_flags.contains(button_flag));
} else {
assert!(state_flags.contains(button_flag));
}
}
for _ in 0..16 {
assert_eq!(input.read_register(&mut host_input), 1)
}
}
}
}