spectrusty_peripherals/
joystick.rs

1/*
2    Copyright (C) 2020-2022  Rafal Michalski
3
4    This file is part of SPECTRUSTY, a Rust library for building emulators.
5
6    For the full copyright notice, see the lib.rs file.
7*/
8//! A joystick communication interface and emulators of various joysticks.
9use core::fmt::Debug;
10
11pub mod cursor;
12pub mod fuller;
13pub mod kempston;
14pub mod sinclair;
15
16bitflags! {
17    /// Flags for reading and writing the current stick direction.
18    /// * Bit = 1 a direction is active.
19    /// * Bit = 0 a direction is inactive.
20    #[derive(Default)]
21    pub struct Directions: u8 {
22        const UP    = 0b0000_0001;
23        const RIGHT = 0b0000_0010;
24        const DOWN  = 0b0000_0100;
25        const LEFT  = 0b0000_1000;
26    }
27}
28
29/// An enum for specifying one of 8 possible joystick's directional positions and a center (neutral) state.
30pub enum JoyDirection {
31    Center,
32    Up,
33    UpRight,
34    Right,
35    DownRight,
36    Down,
37    DownLeft,
38    Left,
39    UpLeft
40}
41
42/// An interface for providing user input data for a [JoystickDevice] implementation.
43pub trait JoystickInterface {
44    /// Press or release a "fire" button. `btn` is the button number for cases when the joystick have more
45    /// than one button.
46    ///
47    /// Currently, `btn` is not being used by any of the implemented devices.
48    fn fire(&mut self, btn: u8, pressed: bool);
49    /// Returns `true` if an indicated "fire" button is being pressed, otherwise returns `false`.
50    fn get_fire(&self, btn: u8) -> bool;
51    /// Changes the stick direction using provided flags.
52    fn set_directions(&mut self, dir: Directions);
53    /// Returns the current stick direction.
54    fn get_directions(&self) -> Directions;
55    /// Changes the stick direction using an enum.
56    #[inline]
57    fn direction(&mut self, dir: JoyDirection) {
58        self.set_directions(match dir {
59            JoyDirection::Center => Directions::empty(),
60            JoyDirection::Up => Directions::UP,
61            JoyDirection::UpRight => Directions::UP|Directions::RIGHT,
62            JoyDirection::Right => Directions::RIGHT,
63            JoyDirection::DownRight => Directions::DOWN|Directions::RIGHT,
64            JoyDirection::Down => Directions::DOWN,
65            JoyDirection::DownLeft => Directions::DOWN|Directions::LEFT,
66            JoyDirection::Left => Directions::LEFT,
67            JoyDirection::UpLeft => Directions::UP|Directions::LEFT,
68        })
69    }
70    /// Resets a joystick to a central (neutral) position.
71    #[inline]
72    fn center(&mut self) {
73        self.set_directions(Directions::empty());
74    }
75    /// Returns `true` if a joystick is in the up (forward) position.
76    #[inline]
77    fn is_up(&self) -> bool {
78        self.get_directions().intersects(Directions::UP)
79    }
80    /// Returns `true` if a joystick is in the right position.
81    #[inline]
82    fn is_right(&self) -> bool {
83        self.get_directions().intersects(Directions::RIGHT)
84    }
85    /// Returns `true` if a joystick is in the left position.
86    #[inline]
87    fn is_left(&self) -> bool {
88        self.get_directions().intersects(Directions::LEFT)
89    }
90    /// Returns `true` if a joystick is in the down (backward) position.
91    #[inline]
92    fn is_down(&self) -> bool {
93        self.get_directions().intersects(Directions::DOWN)
94    }
95    /// Returns `true` if a joystick is in the center (neutral) position.
96    #[inline]
97    fn is_center(&self) -> bool {
98        self.get_directions().intersects(Directions::empty())
99    }
100}
101
102/// A joystick device interface for the joystick [bus][crate::bus::joystick] device implementations.
103pub trait JoystickDevice: Debug {
104    /// Should return the joystick state.
105    fn port_read(&self, port: u16) -> u8;
106    /// Writes data to a joystick device.
107    ///
108    /// If a device does not support writes, this method should return `false`.
109    /// The default implementation does exactly just that.
110    fn port_write(&mut self, _port: u16, _data: u8) -> bool { false }
111}
112
113/// The joystick device that can be used as a placeholder type.
114#[derive(Clone, Copy, Default, Debug)]
115pub struct NullJoystickDevice;
116
117impl JoystickDevice for NullJoystickDevice {
118    fn port_read(&self, _port: u16) -> u8 {
119        u8::max_value()
120    }
121}
122
123impl JoystickInterface for NullJoystickDevice {
124    fn fire(&mut self, _btn: u8, _pressed: bool) {}
125    fn get_fire(&self, _btn: u8) -> bool { false }
126    fn set_directions(&mut self, _dir: Directions) {}
127    fn get_directions(&self) -> Directions {
128        Directions::empty()
129    }
130}