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}