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
use gilrs::{Button, Event, EventType, Gilrs};

pub use gilrs::Error;

///
/// ```
/// # use simple_game_utils::controller::GameController;
/// let mut controller = GameController::new().expect("Unable to init controller");
///
/// loop {
///     controller.update();
///     if controller.action.north {
///         println!("Triangle pressed");
///     }
/// }
/// ```
#[derive(Debug)]
pub struct GameController {
    gilrs: Gilrs,
    pub direction: DirectionState,
    pub action: ActionState,
    pub menu: MenuState,
}

impl GameController {
    pub fn new() -> Result<Self, Error> {
        Ok(GameController {
            gilrs: Gilrs::new()?,
            direction: DirectionState::default(),
            action: ActionState::default(),
            menu: MenuState::default(),
        })
    }

    pub fn new_unchecked() -> Self {
        Self::new().expect("Failed to init controller")
    }

    pub fn from_state(
        direction: DirectionState,
        action: ActionState,
        menu: MenuState,
    ) -> Result<Self, Error> {
        Ok(GameController {
            gilrs: Gilrs::new()?,
            direction,
            action,
            menu,
        })
    }

    pub fn from_state_unchecked(
        direction: DirectionState,
        action: ActionState,
        menu: MenuState,
    ) -> Self {
        Self::from_state(direction, action, menu).expect("Failed to init controller")
    }
}

impl GameController {
    pub fn any_connected(&self) -> bool {
        self.gilrs.gamepads().any(|(_, pad)| pad.is_connected())
    }

    pub fn to_state(&self) -> (DirectionState, ActionState, MenuState) {
        (
            self.direction.clone(),
            self.action.clone(),
            self.menu.clone(),
        )
    }

    pub fn mask(&self) -> u16 {
        self.menu.to_mask() | self.action.to_mask() | self.direction.to_mask()
    }

    pub fn update(&mut self) {
        while let Some(Event {
            id: _,
            event,
            time: _,
        }) = self.gilrs.next_event()
        {
            match event {
                EventType::ButtonPressed(button, _code) => self.set_state(button, true),
                EventType::ButtonRepeated(_, _) => {}
                EventType::ButtonReleased(button, _code) => self.set_state(button, false),
                EventType::ButtonChanged(_, _, _) => {}
                EventType::AxisChanged(_, _, _) => {}
                EventType::Connected => {}
                EventType::Disconnected => {}
                EventType::Dropped => {}
            }
        }
    }

    fn set_state(&mut self, button: Button, pressed: bool) {
        match button {
            Button::South => self.action.south = pressed,
            Button::East => self.action.east = pressed,
            Button::North => self.action.north = pressed,
            Button::West => self.action.west = pressed,
            Button::C => {}
            Button::Z => {}
            Button::LeftTrigger => {}
            Button::LeftTrigger2 => {}
            Button::RightTrigger => {}
            Button::RightTrigger2 => {}
            Button::Select => {}
            Button::Start => self.menu.start = pressed,
            Button::Mode => {}
            Button::LeftThumb => {}
            Button::RightThumb => {}
            Button::DPadUp => self.direction.up = pressed,
            Button::DPadDown => self.direction.down = pressed,
            Button::DPadLeft => self.direction.left = pressed,
            Button::DPadRight => self.direction.right = pressed,
            Button::Unknown => {}
        }
    }
}

#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
#[derive(Debug, Default, Clone)]
pub struct DirectionState {
    pub up: bool,
    pub down: bool,
    pub left: bool,
    pub right: bool,
}

impl DirectionState {
    pub fn to_mask(&self) -> u16 {
        (if self.up { CNTR_MASK_UP } else { 0 })
            | (if self.down { CNTR_MASK_DOWN } else { 0 })
            | (if self.left { CNTR_MASK_LEFT } else { 0 })
            | (if self.right { CNTR_MASK_RIGHT } else { 0 })
    }
}

#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
#[derive(Debug, Default, Clone)]
pub struct MenuState {
    pub start: bool,
}

impl MenuState {
    pub fn to_mask(&self) -> u16 {
        if self.start {
            CNTR_MASK_START
        } else {
            0
        }
    }
}

#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
#[derive(Debug, Default, Clone)]
pub struct ActionState {
    pub north: bool,
    pub south: bool,
    pub west: bool,
    pub east: bool,
}

impl ActionState {
    pub fn to_mask(&self) -> u16 {
        (if self.north { CNTR_MASK_NORTH } else { 0 })
            | (if self.south { CNTR_MASK_SOUTH } else { 0 })
            | (if self.west { CNTR_MASK_WEST } else { 0 })
            | (if self.east { CNTR_MASK_EAST } else { 0 })
    }
}

pub const CNTR_MASK_UP: u16 = 0b10000000_00000000;
pub const CNTR_MASK_DOWN: u16 = 0b01000000_00000000;
pub const CNTR_MASK_LEFT: u16 = 0b00100000_00000000;
pub const CNTR_MASK_RIGHT: u16 = 0b00010000_00000000;
pub const CNTR_MASK_START: u16 = 0b00000001_00000000;
pub const CNTR_MASK_NORTH: u16 = 0b00000000_00001000;
pub const CNTR_MASK_SOUTH: u16 = 0b00000000_00000100;
pub const CNTR_MASK_EAST: u16 = 0b00000000_00000010;
pub const CNTR_MASK_WEST: u16 = 0b00000000_00000001;