1use crate::input::backends::{ControllerType, RawInput};
3use crate::input::controller::{GameCubeButtons, GameCubeInput};
4
5#[derive(Debug, Clone)]
6pub struct GameCubeMapping {
7 pub controller_type: ControllerType,
8 pub button_mappings: ButtonMappings,
9 pub stick_mappings: StickMappings,
10 pub trigger_mappings: TriggerMappings,
11 pub dead_zones: DeadZones,
12 pub sensitivity: Sensitivity,
13}
14
15#[derive(Debug, Clone)]
16pub struct ButtonMappings {
17 pub a: ButtonMapping,
18 pub b: ButtonMapping,
19 pub x: ButtonMapping,
20 pub y: ButtonMapping,
21 pub start: ButtonMapping,
22 pub d_up: ButtonMapping,
23 pub d_down: ButtonMapping,
24 pub d_left: ButtonMapping,
25 pub d_right: ButtonMapping,
26 pub l: ButtonMapping,
27 pub r: ButtonMapping,
28 pub z: ButtonMapping,
29}
30
31#[derive(Debug, Clone)]
32pub enum ButtonMapping {
33 Button(usize),
34 AxisPositive(usize),
35 AxisNegative(usize),
36 Trigger(usize, f32), None,
38}
39
40#[derive(Debug, Clone)]
41pub struct StickMappings {
42 pub left_stick: AxisMapping,
43 pub right_stick: AxisMapping,
44}
45
46#[derive(Debug, Clone)]
47pub struct AxisMapping {
48 pub x_axis: usize,
49 pub y_axis: usize,
50 pub invert_x: bool,
51 pub invert_y: bool,
52}
53
54#[derive(Debug, Clone)]
55pub struct TriggerMappings {
56 pub left_trigger: usize,
57 pub right_trigger: usize,
58}
59
60#[derive(Debug, Clone)]
61pub struct DeadZones {
62 pub left_stick: f32,
63 pub right_stick: f32,
64 pub left_trigger: f32,
65 pub right_trigger: f32,
66}
67
68#[derive(Debug, Clone)]
69pub struct Sensitivity {
70 pub left_stick: f32,
71 pub right_stick: f32,
72}
73
74impl GameCubeMapping {
75 pub fn default_for_controller(
76 controller_info: &crate::input::backends::ControllerInfo,
77 ) -> Result<Self> {
78 match controller_info.controller_type {
79 ControllerType::Xbox => Ok(Self::xbox_default()),
80 ControllerType::PlayStation => Ok(Self::playstation_default()),
81 ControllerType::SwitchPro => Ok(Self::switch_pro_default()),
82 _ => Ok(Self::generic_default()),
83 }
84 }
85
86 pub fn xbox_default() -> Self {
87 Self {
88 controller_type: ControllerType::Xbox,
89 button_mappings: ButtonMappings {
90 a: ButtonMapping::Button(0), b: ButtonMapping::Button(1), x: ButtonMapping::Button(2), y: ButtonMapping::Button(3), start: ButtonMapping::Button(6), d_up: ButtonMapping::Button(11), d_down: ButtonMapping::Button(12), d_left: ButtonMapping::Button(13), d_right: ButtonMapping::Button(14), l: ButtonMapping::Trigger(4, 0.3), r: ButtonMapping::Trigger(5, 0.3), z: ButtonMapping::Button(4), },
103 stick_mappings: StickMappings {
104 left_stick: AxisMapping {
105 x_axis: 0,
106 y_axis: 1,
107 invert_x: false,
108 invert_y: true, },
110 right_stick: AxisMapping {
111 x_axis: 2,
112 y_axis: 3,
113 invert_x: false,
114 invert_y: true,
115 },
116 },
117 trigger_mappings: TriggerMappings {
118 left_trigger: 4,
119 right_trigger: 5,
120 },
121 dead_zones: DeadZones {
122 left_stick: 0.15,
123 right_stick: 0.15,
124 left_trigger: 0.1,
125 right_trigger: 0.1,
126 },
127 sensitivity: Sensitivity {
128 left_stick: 1.0,
129 right_stick: 1.0,
130 },
131 }
132 }
133
134 pub fn playstation_default() -> Self {
135 let mut xbox = Self::xbox_default();
137 xbox.controller_type = ControllerType::PlayStation;
138 xbox.button_mappings.start = ButtonMapping::Button(9); xbox
140 }
141
142 pub fn switch_pro_default() -> Self {
143 let mut xbox = Self::xbox_default();
144 xbox.controller_type = ControllerType::SwitchPro;
145 xbox
147 }
148
149 pub fn generic_default() -> Self {
150 Self::xbox_default()
151 }
152
153 pub fn map_to_gamecube(&self, input: &RawInput) -> GameCubeInput {
154 let mut buttons = GameCubeButtons::default();
155
156 buttons.a = self.get_button_state(&self.button_mappings.a, input);
158 buttons.b = self.get_button_state(&self.button_mappings.b, input);
159 buttons.x = self.get_button_state(&self.button_mappings.x, input);
160 buttons.y = self.get_button_state(&self.button_mappings.y, input);
161 buttons.start = self.get_button_state(&self.button_mappings.start, input);
162 buttons.d_up = self.get_button_state(&self.button_mappings.d_up, input);
163 buttons.d_down = self.get_button_state(&self.button_mappings.d_down, input);
164 buttons.d_left = self.get_button_state(&self.button_mappings.d_left, input);
165 buttons.d_right = self.get_button_state(&self.button_mappings.d_right, input);
166 buttons.l = self.get_button_state(&self.button_mappings.l, input);
167 buttons.r = self.get_button_state(&self.button_mappings.r, input);
168 buttons.z = self.get_button_state(&self.button_mappings.z, input);
169
170 let left_stick = self.map_stick(
172 &self.stick_mappings.left_stick,
173 &self.dead_zones.left_stick,
174 self.sensitivity.left_stick,
175 input,
176 );
177
178 let right_stick = self.map_stick(
179 &self.stick_mappings.right_stick,
180 &self.dead_zones.right_stick,
181 self.sensitivity.right_stick,
182 input,
183 );
184
185 let left_trigger = self.map_trigger(
187 self.trigger_mappings.left_trigger,
188 self.dead_zones.left_trigger,
189 input,
190 );
191
192 let right_trigger = self.map_trigger(
193 self.trigger_mappings.right_trigger,
194 self.dead_zones.right_trigger,
195 input,
196 );
197
198 GameCubeInput {
199 buttons,
200 left_stick,
201 right_stick,
202 left_trigger,
203 right_trigger,
204 }
205 }
206
207 fn get_button_state(&self, mapping: &ButtonMapping, input: &RawInput) -> bool {
208 match mapping {
209 ButtonMapping::Button(idx) => input.buttons.get(*idx).copied().unwrap_or(false),
210 ButtonMapping::AxisPositive(idx) => {
211 input.axes.get(*idx).map(|&v| v > 0.5).unwrap_or(false)
212 }
213 ButtonMapping::AxisNegative(idx) => {
214 input.axes.get(*idx).map(|&v| v < -0.5).unwrap_or(false)
215 }
216 ButtonMapping::Trigger(idx, threshold) => input
217 .triggers
218 .get(*idx)
219 .map(|&v| v > *threshold)
220 .unwrap_or(false),
221 ButtonMapping::None => false,
222 }
223 }
224
225 fn map_stick(
226 &self,
227 axis_mapping: &AxisMapping,
228 dead_zone: &f32,
229 sensitivity: f32,
230 input: &RawInput,
231 ) -> (f32, f32) {
232 let x = input.axes.get(axis_mapping.x_axis).copied().unwrap_or(0.0);
233 let y = input.axes.get(axis_mapping.y_axis).copied().unwrap_or(0.0);
234
235 let mut x = if axis_mapping.invert_x { -x } else { x };
236 let mut y = if axis_mapping.invert_y { -y } else { y };
237
238 let magnitude = (x * x + y * y).sqrt();
240 if magnitude < *dead_zone {
241 return (0.0, 0.0);
242 }
243
244 if magnitude > 1.0 {
246 x /= magnitude;
247 y /= magnitude;
248 }
249
250 x *= sensitivity;
252 y *= sensitivity;
253
254 (x, y)
255 }
256
257 fn map_trigger(&self, trigger_idx: usize, dead_zone: f32, input: &RawInput) -> f32 {
258 let value = input.triggers.get(trigger_idx).copied().unwrap_or(0.0);
259 if value < dead_zone {
260 0.0
261 } else {
262 (value - dead_zone) / (1.0 - dead_zone)
264 }
265 }
266}
267
268use anyhow::Result;