1use std::collections::HashMap;
2
3use glam::Vec2;
4use repame_input::GamepadState;
5use repose_core::input::{GamepadAxis, GamepadButton, GamepadEvent, GamepadId};
6
7pub const TRIGGER_HELD: f32 = 0.5;
8
9#[derive(Default)]
10pub struct PadBridge {
11 lx: f32,
12 ly: f32,
13 rx: f32,
14 ry: f32,
15 lt_held: bool,
16 rt_held: bool,
17 south: bool,
18 east: bool,
19 dpad_l: bool,
20 dpad_u: bool,
21 dpad_r: bool,
22 north: bool,
23 lt_edge: bool,
24 rt_edge: bool,
25 south_edge: bool,
26 east_edge: bool,
27 dpad_l_edge: bool,
28 dpad_u_edge: bool,
29 dpad_r_edge: bool,
30 north_edge: bool,
31}
32
33impl PadBridge {
34 pub fn button(&mut self, button: GamepadButton, pressed: bool) {
35 let (held, edge) = match button {
36 GamepadButton::South => (&mut self.south, &mut self.south_edge),
37 GamepadButton::East => (&mut self.east, &mut self.east_edge),
38 GamepadButton::North => (&mut self.north, &mut self.north_edge),
39 GamepadButton::DPadLeft => (&mut self.dpad_l, &mut self.dpad_l_edge),
40 GamepadButton::DPadUp => (&mut self.dpad_u, &mut self.dpad_u_edge),
41 GamepadButton::DPadRight => (&mut self.dpad_r, &mut self.dpad_r_edge),
42 _ => return,
43 };
44 if pressed && !*held {
45 *edge = true;
46 }
47 *held = pressed;
48 }
49
50 pub fn axis(&mut self, axis: GamepadAxis, value: f32) {
51 match axis {
52 GamepadAxis::LeftStickX => self.lx = value,
53 GamepadAxis::LeftStickY => self.ly = value,
54 GamepadAxis::RightStickX => self.rx = value,
55 GamepadAxis::RightStickY => self.ry = value,
56 GamepadAxis::LeftTrigger => {
57 let held = value > TRIGGER_HELD;
58 if held && !self.lt_held {
59 self.lt_edge = true;
60 }
61 self.lt_held = held;
62 }
63 GamepadAxis::RightTrigger => {
64 let held = value > TRIGGER_HELD;
65 if held && !self.rt_held {
66 self.rt_edge = true;
67 }
68 self.rt_held = held;
69 }
70 }
71 }
72
73 pub fn snapshot(&self) -> GamepadState {
74 GamepadState {
75 left_stick: Vec2::new(self.lx, self.ly),
76 right_stick: Vec2::new(self.rx, self.ry),
77 right_trigger_held: self.rt_held,
78 right_trigger_pressed: self.rt_edge,
79 left_trigger_held: self.lt_held,
80 left_trigger_pressed: self.lt_edge,
81 south_pressed: self.south_edge,
82 east_pressed: self.east_edge,
83 dpad_left_pressed: self.dpad_l_edge,
84 dpad_up_pressed: self.dpad_u_edge,
85 dpad_right_pressed: self.dpad_r_edge,
86 north_pressed: self.north_edge,
87 }
88 }
89
90 pub fn clear_edges(&mut self) {
91 self.lt_edge = false;
92 self.rt_edge = false;
93 self.south_edge = false;
94 self.east_edge = false;
95 self.dpad_l_edge = false;
96 self.dpad_u_edge = false;
97 self.dpad_r_edge = false;
98 self.north_edge = false;
99 }
100}
101
102#[derive(Default)]
103pub struct PadBank {
104 pads: HashMap<GamepadId, PadBridge>,
105}
106
107impl PadBank {
108 pub fn feed(&mut self, events: Vec<GamepadEvent>) {
109 for ev in events {
110 match ev {
111 GamepadEvent::Connected { .. } => {}
112 GamepadEvent::Disconnected { id } => {
113 self.pads.remove(&id);
118 }
119 GamepadEvent::Button { id, button, pressed } => {
120 self.pads.entry(id).or_default().button(button, pressed);
121 }
122 GamepadEvent::Axis { id, axis, value } => {
123 self.pads.entry(id).or_default().axis(axis, value);
124 }
125 }
126 }
127 }
128
129 pub fn drain(&mut self) -> Vec<GamepadState> {
130 let mut ids: Vec<GamepadId> = self.pads.keys().copied().collect();
131 ids.sort_by_key(|id| id.0);
132 let mut out = Vec::with_capacity(ids.len());
133 for id in ids {
134 if let Some(bridge) = self.pads.get_mut(&id) {
135 out.push(bridge.snapshot());
136 bridge.clear_edges();
137 }
138 }
139 out
140 }
141
142 pub fn live(&self) -> bool {
143 !self.pads.is_empty()
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150
151 #[test]
152 fn rising_edge_fires_once() {
153 let mut b = PadBridge::default();
154 b.button(GamepadButton::South, true);
155 assert!(b.snapshot().south_pressed);
156 b.clear_edges();
157 b.button(GamepadButton::South, true);
158 assert!(!b.snapshot().south_pressed);
159 }
160
161 #[test]
162 fn trigger_threshold_edges() {
163 let mut b = PadBridge::default();
164 b.axis(GamepadAxis::RightTrigger, 0.8);
165 let s = b.snapshot();
166 assert!(s.right_trigger_held && s.right_trigger_pressed);
167 }
168}