forked from mirrors/gecko-dev
		
	 975fde609c
			
		
	
	
		975fde609c
		
	
	
	
	
		
			
			<!-- Please describe your changes on the following line: --> Gamepad API implementation. Tested with HTC Vive and Daydream controllers ;) --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #10977 <!-- Either: --> - [ ] There are tests for these changes OR - [X] These changes do not require tests because : current gamepad tests are manual (https://github.com/w3c/web-platform-tests/tree/master/gamepad). There is a open issue about the best way to test WebVR/Gamepad without real devices https://github.com/w3c/webvr/issues/187. We'll work on the testing suite & mock devices/data on a separate issue. <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: 26c45275ffaccf746e47606a74b3aee519673e54 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 5ae2853a5fc26b6a0fedc0cbb9b3eef9e6ad6049
		
			
				
	
	
		
			206 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			206 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| use core::nonzero::NonZero;
 | |
| use dom::bindings::codegen::Bindings::GamepadBinding;
 | |
| use dom::bindings::codegen::Bindings::GamepadBinding::GamepadMethods;
 | |
| use dom::bindings::inheritance::Castable;
 | |
| use dom::bindings::js::{JS, Root};
 | |
| use dom::bindings::num::Finite;
 | |
| use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
 | |
| use dom::bindings::str::DOMString;
 | |
| use dom::event::Event;
 | |
| use dom::eventtarget::EventTarget;
 | |
| use dom::gamepadbuttonlist::GamepadButtonList;
 | |
| use dom::gamepadevent::{GamepadEvent, GamepadEventType};
 | |
| use dom::globalscope::GlobalScope;
 | |
| use dom::vrpose::VRPose;
 | |
| use dom_struct::dom_struct;
 | |
| use js::jsapi::{Heap, JSContext, JSObject};
 | |
| use js::typedarray::{Float64Array, CreateWith};
 | |
| use std::cell::Cell;
 | |
| use std::ptr;
 | |
| use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState};
 | |
| 
 | |
| #[dom_struct]
 | |
| pub struct Gamepad {
 | |
|     reflector_: Reflector,
 | |
|     gamepad_id: u32,
 | |
|     id: String,
 | |
|     index: Cell<i32>,
 | |
|     connected: Cell<bool>,
 | |
|     timestamp: Cell<f64>,
 | |
|     mapping_type: String,
 | |
|     axes: Heap<*mut JSObject>,
 | |
|     buttons: JS<GamepadButtonList>,
 | |
|     pose: Option<JS<VRPose>>,
 | |
|     #[ignore_heap_size_of = "Defined in rust-webvr"]
 | |
|     hand: WebVRGamepadHand,
 | |
|     display_id: u32
 | |
| }
 | |
| 
 | |
| impl Gamepad {
 | |
|     fn new_inherited(gamepad_id: u32,
 | |
|                      id: String,
 | |
|                      index: i32,
 | |
|                      connected: bool,
 | |
|                      timestamp: f64,
 | |
|                      mapping_type: String,
 | |
|                      axes: *mut JSObject,
 | |
|                      buttons: &GamepadButtonList,
 | |
|                      pose: Option<&VRPose>,
 | |
|                      hand: WebVRGamepadHand,
 | |
|                      display_id: u32) -> Gamepad {
 | |
|         Self {
 | |
|             reflector_: Reflector::new(),
 | |
|             gamepad_id: gamepad_id,
 | |
|             id: id,
 | |
|             index: Cell::new(index),
 | |
|             connected: Cell::new(connected),
 | |
|             timestamp: Cell::new(timestamp),
 | |
|             mapping_type: mapping_type,
 | |
|             axes: Heap::new(axes),
 | |
|             buttons: JS::from_ref(buttons),
 | |
|             pose: pose.map(JS::from_ref),
 | |
|             hand: hand,
 | |
|             display_id: display_id
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     #[allow(unsafe_code)]
 | |
|     pub fn new_from_vr(global: &GlobalScope,
 | |
|                        index: i32,
 | |
|                        data: &WebVRGamepadData,
 | |
|                        state: &WebVRGamepadState) -> Root<Gamepad> {
 | |
|         let buttons = GamepadButtonList::new_from_vr(&global, &state.buttons);
 | |
|         let pose = VRPose::new(&global, &state.pose);
 | |
|         let cx = global.get_cx();
 | |
|         rooted!(in (cx) let mut axes = ptr::null_mut());
 | |
|         unsafe {
 | |
|             let _ = Float64Array::create(cx,
 | |
|                                          CreateWith::Slice(&state.axes),
 | |
|                                          axes.handle_mut());
 | |
|         }
 | |
| 
 | |
|         reflect_dom_object(box Gamepad::new_inherited(state.gamepad_id,
 | |
|                                                       data.name.clone(),
 | |
|                                                       index,
 | |
|                                                       state.connected,
 | |
|                                                       state.timestamp,
 | |
|                                                       "".into(),
 | |
|                                                       axes.get(),
 | |
|                                                       &buttons,
 | |
|                                                       Some(&pose),
 | |
|                                                       data.hand.clone(),
 | |
|                                                       data.display_id),
 | |
|                            global,
 | |
|                            GamepadBinding::Wrap)
 | |
| 
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl GamepadMethods for Gamepad {
 | |
|     // https://w3c.github.io/gamepad/#dom-gamepad-id
 | |
|     fn Id(&self) -> DOMString {
 | |
|         DOMString::from(self.id.clone())
 | |
|     }
 | |
| 
 | |
|     // https://w3c.github.io/gamepad/#dom-gamepad-index
 | |
|     fn Index(&self) -> i32 {
 | |
|         self.index.get()
 | |
|     }
 | |
| 
 | |
|     // https://w3c.github.io/gamepad/#dom-gamepad-connected
 | |
|     fn Connected(&self) -> bool {
 | |
|         self.connected.get()
 | |
|     }
 | |
| 
 | |
|     // https://w3c.github.io/gamepad/#dom-gamepad-timestamp
 | |
|     fn Timestamp(&self) -> Finite<f64> {
 | |
|         Finite::wrap(self.timestamp.get())
 | |
|     }
 | |
| 
 | |
|     // https://w3c.github.io/gamepad/#dom-gamepad-mapping
 | |
|     fn Mapping(&self) -> DOMString {
 | |
|         DOMString::from(self.mapping_type.clone())
 | |
|     }
 | |
| 
 | |
|     #[allow(unsafe_code)]
 | |
|     // https://w3c.github.io/gamepad/#dom-gamepad-axes
 | |
|     unsafe fn Axes(&self, _cx: *mut JSContext) -> NonZero<*mut JSObject> {
 | |
|         NonZero::new(self.axes.get())
 | |
|     }
 | |
| 
 | |
|     // https://w3c.github.io/gamepad/#dom-gamepad-buttons
 | |
|     fn Buttons(&self) -> Root<GamepadButtonList> {
 | |
|         Root::from_ref(&*self.buttons)
 | |
|     }
 | |
| 
 | |
|     // https://w3c.github.io/gamepad/extensions.html#gamepadhand-enum
 | |
|     fn Hand(&self) -> DOMString {
 | |
|         let value = match self.hand {
 | |
|             WebVRGamepadHand::Unknown => "",
 | |
|             WebVRGamepadHand::Left => "left",
 | |
|             WebVRGamepadHand::Right => "right"
 | |
|         };
 | |
|         value.into()
 | |
|     }
 | |
| 
 | |
|     // https://w3c.github.io/gamepad/extensions.html#dom-gamepad-pose
 | |
|     fn GetPose(&self) -> Option<Root<VRPose>> {
 | |
|         self.pose.as_ref().map(|p| Root::from_ref(&**p))
 | |
|     }
 | |
| 
 | |
|     // https://w3c.github.io/webvr/spec/1.1/#gamepad-getvrdisplays-attribute
 | |
|     fn DisplayId(&self) -> u32 {
 | |
|         self.display_id
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl Gamepad {
 | |
|     #[allow(unsafe_code)]
 | |
|     pub fn update_from_vr(&self, state: &WebVRGamepadState) {
 | |
|         self.timestamp.set(state.timestamp);
 | |
|         unsafe {
 | |
|             let cx = self.global().get_cx();
 | |
|             typedarray!(in(cx) let axes: Float64Array = self.axes.get());
 | |
|             if let Ok(mut array) = axes {
 | |
|                 array.update(&state.axes);
 | |
|             }
 | |
|         }
 | |
|         self.buttons.sync_from_vr(&state.buttons);
 | |
|         if let Some(ref pose) = self.pose {
 | |
|             pose.update(&state.pose);
 | |
|         }
 | |
|         self.update_connected(state.connected);
 | |
|     }
 | |
| 
 | |
|     pub fn gamepad_id(&self) -> u32 {
 | |
|         self.gamepad_id
 | |
|     }
 | |
| 
 | |
|     pub fn update_connected(&self, connected: bool) {
 | |
|         if self.connected.get() == connected {
 | |
|             return;
 | |
|         }
 | |
|         self.connected.set(connected);
 | |
| 
 | |
|         let event_type = if connected {
 | |
|             GamepadEventType::Connected
 | |
|         } else {
 | |
|             GamepadEventType::Disconnected
 | |
|         };
 | |
| 
 | |
|         self.notify_event(event_type);
 | |
|     }
 | |
| 
 | |
|     pub fn update_index(&self, index: i32) {
 | |
|         self.index.set(index);
 | |
|     }
 | |
| 
 | |
|     pub fn notify_event(&self, event_type: GamepadEventType) {
 | |
|         let event = GamepadEvent::new_with_type(&self.global(), event_type, &self);
 | |
|         event.upcast::<Event>().fire(self.global().as_window().upcast::<EventTarget>());
 | |
|     }
 | |
| }
 |