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