stdweb/webapi/
gamepad.rs

1use webcore::try_from::{
2    TryFrom,
3    TryInto,
4};
5use webcore::value::{
6    ConversionError,
7    Reference,
8    Value,
9};
10
11/// The set of known gamepad layout mappings.
12///
13/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Gamepad/mapping)
14// https://w3c.github.io/gamepad/#dom-gamepadmappingtype
15#[derive(Copy, Clone, Debug, Eq, PartialEq)]
16pub enum GamepadMappingType {
17    /// No mapping is in use for this gamepad
18    NoMapping,
19    /// This gamepad is mapped to the [Standard Gamepad layout](https://w3c.github.io/gamepad/#remapping)
20    Standard,
21}
22
23impl TryFrom<Value> for GamepadMappingType {
24    type Error = ConversionError;
25
26    fn try_from(v: Value) -> Result<Self, Self::Error> {
27        let value: String = v.try_into()?;
28        match value.as_ref() {
29            "" => Ok(GamepadMappingType::NoMapping),
30            "standard" => Ok(GamepadMappingType::Standard),
31            s => Err(ConversionError::Custom(format!("invalid gamepad mapping type \"{}\"", s))),
32        }
33    }
34}
35
36/// The state of an individual button on a gamepad device.
37///
38/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/GamepadButton)
39// https://w3c.github.io/gamepad/#gamepadbutton-interface
40#[derive(Clone, Debug, Eq, PartialEq, ReferenceType)]
41#[reference(instance_of = "GamepadButton")]
42pub struct GamepadButton( Reference );
43
44impl GamepadButton {
45
46    /// Is the button currently pressed?
47    ///
48    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/GamepadButton/pressed)
49    // https://w3c.github.io/gamepad/#dom-gamepadbutton-pressed
50    #[inline]
51    pub fn pressed(&self) -> bool {
52        js!(
53            return @{self.as_ref()}.pressed;
54        ).try_into().unwrap()
55    }
56
57    /// Is the button currently touched?
58    ///
59    /// MDN does not document this. Firefox supports it, but Chrome (as of v65) does not.
60    // https://w3c.github.io/gamepad/#dom-gamepadbutton-touched
61    #[inline]
62    pub fn touched(&self) -> bool {
63        js!(
64            return @{self.as_ref()}.touched;
65        ).try_into().unwrap()
66    }
67
68    /// The amount which the button has been pressed, between 0.0 (not pressed), and 1.0 (fully pressed).
69    ///
70    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/GamepadButton/value)
71    // https://w3c.github.io/gamepad/#dom-gamepadbutton-value
72    #[inline]
73    pub fn value(&self) -> f64 {
74        js!(
75            return @{self.as_ref()}.value;
76        ).try_into().unwrap()
77    }
78}
79
80/// An individual gamepad/controller.
81///
82/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Gamepad)
83// https://w3c.github.io/gamepad/#gamepad-interface
84#[derive(Clone, Debug, Eq, PartialEq, ReferenceType)]
85#[reference(instance_of = "Gamepad")]
86pub struct Gamepad( Reference );
87
88impl Gamepad {
89
90    /// A string containing some information about this gamepad.
91    ///
92    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Gamepad/id)
93    // https://w3c.github.io/gamepad/#dom-gamepad-id
94    #[inline]
95    pub fn id(&self) -> String {
96        js!(
97            return @{self.as_ref()}.id;
98        ).try_into().unwrap()
99    }
100
101    /// An auto-incrementing integer to uniquely identify a connected Gamepad.
102    ///
103    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Gamepad/index)
104    // https://w3c.github.io/gamepad/#dom-gamepad-index
105    #[inline]
106    pub fn index(&self) -> i32 {
107        js!(
108            return @{self.as_ref()}.index;
109        ).try_into().unwrap()
110    }
111
112    /// Is this gamepad connected to the system, powered on, and usable?
113    ///
114    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Gamepad/connected)
115    // https://w3c.github.io/gamepad/#dom-gamepad-connected
116    #[inline]
117    pub fn connected(&self) -> bool {
118        js!(
119            return @{self.as_ref()}.connected;
120        ).try_into().unwrap()
121    }
122
123    /// Monotonically increasing time this gamepad was updated.
124    ///
125    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Gamepad/timestamp)
126    // https://w3c.github.io/gamepad/#dom-gamepad-timestamp
127    #[inline]
128    pub fn timestamp(&self) -> f64 {
129        js!(
130            return @{self.as_ref()}.timestamp;
131        ).try_into().unwrap()
132    }
133
134    /// The mapping in use for this device.
135    ///
136    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Gamepad/mapping)
137    // https://w3c.github.io/gamepad/#dom-gamepad-mapping
138    #[inline]
139    pub fn mapping(&self) -> GamepadMappingType {
140        js!(
141            return @{self.as_ref()}.mapping;
142        ).try_into().unwrap()
143    }
144
145    /// Array of values for all axes of the gamepad.
146    ///
147    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Gamepad/axes)
148    // https://w3c.github.io/gamepad/#dom-gamepad-axes
149    #[inline]
150    pub fn axes(&self) -> Vec<f64> {
151        js!(
152            return @{self.as_ref()}.axes;
153        ).try_into().unwrap()
154    }
155
156    /// Array of button states for all buttons of the gamepad.
157    ///
158    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Gamepad/buttons)
159    // https://w3c.github.io/gamepad/#dom-gamepad-buttons
160    #[inline]
161    pub fn buttons(&self) -> Vec<GamepadButton> {
162        js!(
163            return @{self.as_ref()}.buttons;
164        ).try_into().unwrap()
165    }
166
167    /// Retrieve all connected gamepads, in an array indexed by each gamepad's `index` member.
168    ///
169    /// Chrome doesn't update Gamepad state automatically, you must call this function each frame.
170    ///
171    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/getGamepads)
172    // https://w3c.github.io/gamepad/#dom-navigator-getgamepads
173    pub fn get_all() -> Vec<Option<Gamepad>> {
174        js!(
175            return Array.from(navigator.getGamepads());
176        ).try_into().unwrap()
177    }
178}
179
180#[cfg(test)]
181mod tests {
182    use super::GamepadMappingType;
183
184    use webcore::try_from::TryInto;
185    use webcore::value::{ConversionError, Value};
186
187    #[test]
188    fn test_value_into_gamepad_mapping() {
189
190        let to_mapping = |v: Value| -> Result<GamepadMappingType, ConversionError> {
191            v.try_into()
192        };
193
194        assert_eq!(to_mapping("standard".into()), Ok(GamepadMappingType::Standard));
195        assert_eq!(to_mapping("".into()), Ok(GamepadMappingType::NoMapping));
196        assert!(to_mapping("fakemapping".into()).is_err());
197        assert!(to_mapping(Value::Null).is_err());
198    }
199
200    // most of the Gamepad API is not testable,
201    // because Gamepad and GamepadButton are not constructible
202}