bones_framework/input/
gamepad.rs

1//! Gamepad input resource.
2use std::collections::VecDeque;
3
4use crate::prelude::*;
5
6/// Resource containing the gamepad input events detected this frame.
7#[derive(HasSchema, Clone, Default, Debug)]
8pub struct GamepadInputs {
9    /// The gampad events.
10    pub gamepad_events: SVec<GamepadEvent>,
11}
12
13/// A gamepad event.
14#[derive(HasSchema, Clone, Copy, Debug)]
15#[repr(C, u8)]
16pub enum GamepadEvent {
17    /// A connection event.
18    Connection(GamepadConnectionEvent),
19    /// A button event.
20    Button(GamepadButtonEvent),
21    /// An axis event.
22    Axis(GamepadAxisEvent),
23}
24
25impl Default for GamepadEvent {
26    fn default() -> Self {
27        Self::Connection(default())
28    }
29}
30
31/// A gamepad connection event.
32#[derive(HasSchema, Clone, Copy, Debug, Default)]
33#[repr(C)]
34pub struct GamepadConnectionEvent {
35    /// The ID of the gamepad.
36    pub gamepad: u32,
37    /// The type of connection event.
38    pub event: GamepadConnectionEventKind,
39}
40
41/// The kind of gamepad connection event.
42#[derive(HasSchema, Clone, Copy, Debug, Default)]
43#[repr(u8)]
44pub enum GamepadConnectionEventKind {
45    #[default]
46    /// The gamepad was connected.
47    Connected,
48    /// The gamepad was disconnected.
49    Disconnected,
50}
51
52/// A gamepad button event.
53#[derive(HasSchema, Clone, Copy, Debug, Default)]
54#[repr(C)]
55pub struct GamepadButtonEvent {
56    /// The ID of the gamepad.
57    pub gamepad: u32,
58    /// The gamepad button.
59    pub button: GamepadButton,
60    /// The value of the button, for example, this will be `1.0` when presssed and `0.0` when
61    /// released if this is a normal button.
62    pub value: f32,
63}
64
65/// A specific button on a gamepad.
66#[allow(missing_docs)]
67#[derive(HasSchema, Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
68#[repr(C, u8)]
69pub enum GamepadButton {
70    #[default]
71    South,
72    East,
73    North,
74    West,
75    C,
76    Z,
77    LeftTrigger,
78    LeftTrigger2,
79    RightTrigger,
80    RightTrigger2,
81    Select,
82    Start,
83    Mode,
84    LeftThumb,
85    RightThumb,
86    DPadUp,
87    DPadDown,
88    DPadLeft,
89    DPadRight,
90    Other(u8),
91}
92
93impl std::fmt::Display for GamepadButton {
94    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95        write!(
96            f,
97            "{}",
98            match self {
99                GamepadButton::South => "South",
100                GamepadButton::East => "East",
101                GamepadButton::North => "North",
102                GamepadButton::West => "West",
103                GamepadButton::C => "C",
104                GamepadButton::Z => "Z",
105                GamepadButton::LeftTrigger => "Left Trigger",
106                GamepadButton::LeftTrigger2 => "Left Trigger 2",
107                GamepadButton::RightTrigger => "Right Trigger",
108                GamepadButton::RightTrigger2 => "Right Trigger 2",
109                GamepadButton::Select => "Select",
110                GamepadButton::Start => "Start",
111                GamepadButton::Mode => "Mode",
112                GamepadButton::LeftThumb => "Left Thumb",
113                GamepadButton::RightThumb => "Right Thumb",
114                GamepadButton::DPadUp => "DPad Up",
115                GamepadButton::DPadDown => "DPad Down",
116                GamepadButton::DPadLeft => "DPad Left",
117                GamepadButton::DPadRight => "DPad Right",
118                GamepadButton::Other(n) => return write!(f, "Button {n}"),
119            }
120        )
121    }
122}
123
124/// A gamepad axis event.
125#[derive(HasSchema, Clone, Copy, Debug)]
126#[schema(no_default)]
127#[repr(C)]
128pub struct GamepadAxisEvent {
129    /// The ID of the gamepad.
130    pub gamepad: u32,
131    /// The axis that has changed.
132    pub axis: GamepadAxis,
133    /// The value of the axis.
134    pub value: f32,
135}
136
137/// A specific gamepad axis that may have changed.
138#[derive(HasSchema, Clone, Copy, Debug, PartialEq, Eq, Hash)]
139#[schema(no_default)]
140#[allow(missing_docs)]
141#[repr(C, u8)]
142pub enum GamepadAxis {
143    LeftStickX,
144    LeftStickY,
145    LeftZ,
146    RightStickX,
147    RightStickY,
148    RightZ,
149    Other(u8),
150}
151
152impl std::fmt::Display for GamepadAxis {
153    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
154        write!(
155            f,
156            "{}",
157            match self {
158                GamepadAxis::LeftStickX => "Left Stick X",
159                GamepadAxis::LeftStickY => "Left Stick Y",
160                GamepadAxis::LeftZ => "Left Z",
161                GamepadAxis::RightStickX => "Right Stick X",
162                GamepadAxis::RightStickY => "Right Stick Y",
163                GamepadAxis::RightZ => "Right Z",
164                GamepadAxis::Other(n) => return write!(f, "Axis {n}"),
165            }
166        )
167    }
168}
169
170/// Struct that represents intensity of a rumble
171#[derive(HasSchema, Default, Clone, Copy, Debug)]
172pub struct GamepadRumbleIntensity {
173    /// The intensity of the strong motor, between 0.0 - 1.0.
174    strong_motor: f32,
175    /// The intensity of the weak motor, between 0.0 - 1.0.
176    weak_motor: f32,
177}
178
179impl GamepadRumbleIntensity {
180    /// Represents no rumble intensity.
181    pub const ZERO: Self = Self {
182        strong_motor: 0.0,
183        weak_motor: 0.0,
184    };
185    /// Represents maximum rumble intensity for both motors.
186    pub const MAX_BOTH: Self = Self {
187        strong_motor: 1.0,
188        weak_motor: 1.0,
189    };
190    /// Represents maximum rumble intensity for the strong motor only.
191    pub const MAX_STRONG: Self = Self {
192        strong_motor: 1.0,
193        weak_motor: 0.0,
194    };
195    /// Represents maximum rumble intensity for the weak motor only.
196    pub const MAX_WEAK: Self = Self {
197        strong_motor: 0.0,
198        weak_motor: 1.0,
199    };
200    /// Represents medium rumble intensity for both motors.
201    pub const MEDIUM_BOTH: Self = Self {
202        strong_motor: 0.5,
203        weak_motor: 0.5,
204    };
205    /// Represents medium rumble intensity for the strong motor only.
206    pub const MEDIUM_STRONG: Self = Self {
207        strong_motor: 0.5,
208        weak_motor: 0.0,
209    };
210    /// Represents medium rumble intensity for the weak motor only.
211    pub const MEDIUM_WEAK: Self = Self {
212        strong_motor: 0.0,
213        weak_motor: 0.5,
214    };
215    /// Represents light rumble intensity for both motors.
216    pub const LIGHT_BOTH: Self = Self {
217        strong_motor: 0.25,
218        weak_motor: 0.25,
219    };
220    /// Represents light rumble intensity for the strong motor only.
221    pub const LIGHT_STRONG: Self = Self {
222        strong_motor: 0.25,
223        weak_motor: 0.0,
224    };
225    /// Represents light rumble intensity for the weak motor only.
226    pub const LIGHT_WEAK: Self = Self {
227        strong_motor: 0.0,
228        weak_motor: 0.25,
229    };
230    /// Represents very light rumble intensity for both motors.
231    pub const VERY_LIGHT_BOTH: Self = Self {
232        strong_motor: 0.1,
233        weak_motor: 0.1,
234    };
235    /// Represents very light rumble intensity for the strong motor only.
236    pub const VERY_LIGHT_STRONG: Self = Self {
237        strong_motor: 0.1,
238        weak_motor: 0.0,
239    };
240    /// Represents very light rumble intensity for the weak motor only.
241    pub const VERY_LIGHT_WEAK: Self = Self {
242        strong_motor: 0.0,
243        weak_motor: 0.1,
244    };
245
246    /// Get the intensity of the strong motor.
247    pub fn strong_motor(&self) -> f32 {
248        self.strong_motor
249    }
250
251    /// Set the intensity of the strong motor, clamping it between 0.0 and 1.0.
252    pub fn set_strong_motor(&mut self, value: f32) {
253        self.strong_motor = value.clamp(0.0, 1.0);
254    }
255
256    /// Get the intensity of the weak motor.
257    pub fn weak_motor(&self) -> f32 {
258        self.weak_motor
259    }
260
261    /// Set the intensity of the weak motor, clamping it between 0.0 and 1.0.
262    pub fn set_weak_motor(&mut self, value: f32) {
263        self.weak_motor = value.clamp(0.0, 1.0);
264    }
265}
266
267/// Represents a request to either add, set, or stop rumble on a specific gamepad
268#[derive(HasSchema, Clone, Debug)]
269pub enum GamepadRumbleRequest {
270    /// Request to add rumble to a gamepad.
271    AddRumble {
272        /// The ID of the gamepad to rumble.
273        gamepad: u32,
274        /// The intensity of the rumble.
275        intensity: GamepadRumbleIntensity,
276        /// The duration of the rumble in seconds.
277        duration: f32,
278    },
279    /// Request to set rumble on a gamepad, replacing any existing rumble.
280    SetRumble {
281        /// The ID of the gamepad to rumble.
282        gamepad: u32,
283        /// The intensity of the rumble.
284        intensity: GamepadRumbleIntensity,
285        /// The duration of the rumble in seconds.
286        duration: f32,
287    },
288    /// Request to stop rumble on a gamepad.
289    Stop {
290        /// The ID of the gamepad to stop rumbling.
291        gamepad: u32,
292    },
293}
294
295impl Default for GamepadRumbleRequest {
296    fn default() -> Self {
297        GamepadRumbleRequest::Stop { gamepad: 0 }
298    }
299}
300
301/// Resource that provides an interface for triggering rumble on connected gamepads
302#[derive(HasSchema, Clone)]
303pub struct GamepadsRumble {
304    /// A queue to hold all the gamepad rumble requests to be processed.
305    pub requests: VecDeque<GamepadRumbleRequest>,
306    /// A vector to keep track of which gamepads are enabled for rumble.
307    enabled_gamepads: SVec<bool>,
308}
309
310impl GamepadsRumble {
311    /// Adds rumble to a specific gamepad. Ignores if the gamepad is disabled (enabled by default).
312    pub fn add_rumble(&mut self, gamepad: u32, intensity: GamepadRumbleIntensity, duration: f32) {
313        if self.is_enabled(gamepad) {
314            self.requests.push_back(GamepadRumbleRequest::AddRumble {
315                gamepad,
316                intensity,
317                duration,
318            });
319        }
320    }
321
322    /// Sets rumble on a specific gamepad, replacing any existing rumble. Ignores if the gamepad is disabled.
323    pub fn set_rumble(&mut self, gamepad: u32, intensity: GamepadRumbleIntensity, duration: f32) {
324        if self.is_enabled(gamepad) {
325            self.requests.push_back(GamepadRumbleRequest::SetRumble {
326                gamepad,
327                intensity,
328                duration,
329            });
330        }
331    }
332
333    /// Stops rumble on a specific gamepad.
334    pub fn stop(&mut self, gamepad: u32) {
335        if self.is_enabled(gamepad) {
336            self.requests
337                .push_back(GamepadRumbleRequest::Stop { gamepad });
338        }
339    }
340
341    /// Adds rumble to all enabled gamepads.
342    pub fn add_rumble_all(&mut self, intensity: GamepadRumbleIntensity, duration: f32) {
343        for gamepad in 0..self.enabled_gamepads.len() {
344            if self.is_enabled(gamepad as u32) {
345                self.add_rumble(gamepad as u32, intensity, duration);
346            }
347        }
348    }
349
350    /// Sets rumble on all enabled gamepads, replacing any existing rumble.
351    pub fn set_rumble_all(&mut self, intensity: GamepadRumbleIntensity, duration: f32) {
352        for gamepad in 0..self.enabled_gamepads.len() {
353            if self.is_enabled(gamepad as u32) {
354                self.set_rumble(gamepad as u32, intensity, duration);
355            }
356        }
357    }
358
359    /// Stops rumble on all enabled gamepads.
360    pub fn stop_all(&mut self) {
361        for gamepad in 0..self.enabled_gamepads.len() {
362            if self.is_enabled(gamepad as u32) {
363                self.stop(gamepad as u32);
364            }
365        }
366    }
367
368    /// Checks if a specific gamepad is enabled for rumble.
369    pub fn is_enabled(&self, gamepad: u32) -> bool {
370        let gamepad_index = gamepad as usize;
371        if gamepad_index < self.enabled_gamepads.len() {
372            self.enabled_gamepads[gamepad_index]
373        } else {
374            false
375        }
376    }
377
378    /// Checks if a specific gamepad is disabled for rumble (no rumble requests will work).
379    pub fn is_disabled(&self, gamepad: u32) -> bool {
380        !self.is_enabled(gamepad)
381    }
382
383    /// Re-enables rumble for a specific gamepad.
384    pub fn enable(&mut self, gamepad: u32) {
385        if let Some(enabled) = self.enabled_gamepads.get_mut(gamepad as usize) {
386            *enabled = true;
387        }
388    }
389
390    /// Disables rumble for a specific gamepad (no rumble requests will work).
391    pub fn disable(&mut self, gamepad: u32) {
392        self.stop(gamepad);
393        if let Some(enabled) = self.enabled_gamepads.get_mut(gamepad as usize) {
394            *enabled = false;
395        }
396    }
397
398    /// Enables rumble for all gamepads.
399    pub fn enable_all(&mut self) {
400        for gamepad in 0..self.enabled_gamepads.len() {
401            self.enable(gamepad as u32);
402        }
403    }
404
405    /// Disables rumble for all gamepads (no rumble requests will work).
406    pub fn disable_all(&mut self) {
407        for gamepad in 0..self.enabled_gamepads.len() {
408            self.disable(gamepad as u32);
409        }
410    }
411}
412
413impl Default for GamepadsRumble {
414    fn default() -> Self {
415        GamepadsRumble {
416            requests: VecDeque::new(),
417            enabled_gamepads: vec![true; 4].into(),
418        }
419    }
420}