script/dom/webxr/
xrinputsource.rs1use dom_struct::dom_struct;
6use embedder_traits::GamepadSupportedHapticEffects;
7use js::context::JSContext;
8use js::conversions::ToJSValConvertible;
9use js::jsapi::Heap;
10use js::jsval::{JSVal, UndefinedValue};
11use js::rust::MutableHandleValue;
12use script_bindings::codegen::GenericBindings::GamepadBinding::GamepadMappingType;
13use script_bindings::reflector::{Reflector, reflect_dom_object};
14use webxr_api::{Handedness, InputFrame, InputId, InputSource, TargetRayMode};
15
16use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding::{
17 XRHandedness, XRInputSourceMethods, XRTargetRayMode,
18};
19use crate::dom::bindings::reflector::DomGlobal;
20use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
21use crate::dom::gamepad::Gamepad;
22use crate::dom::window::Window;
23use crate::dom::xrhand::XRHand;
24use crate::dom::xrsession::XRSession;
25use crate::dom::xrspace::XRSpace;
26use crate::realms::enter_auto_realm;
27
28#[dom_struct]
29pub(crate) struct XRInputSource {
30 reflector: Reflector,
31 session: Dom<XRSession>,
32 #[no_trace]
33 info: InputSource,
34 target_ray_space: MutNullableDom<XRSpace>,
35 grip_space: MutNullableDom<XRSpace>,
36 hand: MutNullableDom<XRHand>,
37 #[ignore_malloc_size_of = "mozjs"]
38 profiles: Heap<JSVal>,
39 gamepad: Dom<Gamepad>,
40}
41
42impl XRInputSource {
43 fn new_inherited(session: &XRSession, info: InputSource, gamepad: &Gamepad) -> XRInputSource {
44 XRInputSource {
45 reflector: Reflector::new(),
46 session: Dom::from_ref(session),
47 info,
48 target_ray_space: Default::default(),
49 grip_space: Default::default(),
50 hand: Default::default(),
51 profiles: Heap::default(),
52 gamepad: Dom::from_ref(gamepad),
53 }
54 }
55
56 pub(crate) fn new(
57 cx: &mut JSContext,
58 window: &Window,
59 session: &XRSession,
60 info: InputSource,
61 ) -> DomRoot<XRInputSource> {
62 let gamepad = Gamepad::new(
64 cx,
65 window,
66 0,
67 String::new(),
68 GamepadMappingType::Xr_standard,
69 (-1.0, 1.0),
70 (0.0, 1.0),
71 GamepadSupportedHapticEffects {
72 supports_dual_rumble: false,
73 supports_trigger_rumble: false,
74 },
75 true,
76 );
77
78 let source = reflect_dom_object(
79 cx,
80 Box::new(XRInputSource::new_inherited(session, info, &gamepad)),
81 window,
82 );
83
84 let mut realm = enter_auto_realm(cx, window);
85 let cx = &mut realm.current_realm();
86 rooted!(&in(cx) let mut profiles = UndefinedValue());
87 source.info.profiles.to_jsval(cx, profiles.handle_mut());
88 source.profiles.set(profiles.get());
89 source
90 }
91
92 pub(crate) fn id(&self) -> InputId {
93 self.info.id
94 }
95
96 pub(crate) fn session(&self) -> &XRSession {
97 &self.session
98 }
99
100 pub(crate) fn update_gamepad_state(&self, frame: InputFrame) {
101 frame
102 .button_values
103 .iter()
104 .enumerate()
105 .for_each(|(i, value)| {
106 self.gamepad.map_and_normalize_buttons(i, *value as f64);
107 });
108 frame.axis_values.iter().enumerate().for_each(|(i, value)| {
109 self.gamepad.map_and_normalize_axes(i, *value as f64);
110 });
111 }
112
113 pub(crate) fn gamepad(&self) -> &Gamepad {
114 &self.gamepad
115 }
116}
117
118impl XRInputSourceMethods<crate::DomTypeHolder> for XRInputSource {
119 fn Handedness(&self) -> XRHandedness {
121 match self.info.handedness {
122 Handedness::None => XRHandedness::None,
123 Handedness::Left => XRHandedness::Left,
124 Handedness::Right => XRHandedness::Right,
125 }
126 }
127
128 fn TargetRayMode(&self) -> XRTargetRayMode {
130 match self.info.target_ray_mode {
131 TargetRayMode::Gaze => XRTargetRayMode::Gaze,
132 TargetRayMode::TrackedPointer => XRTargetRayMode::Tracked_pointer,
133 TargetRayMode::Screen => XRTargetRayMode::Screen,
134 TargetRayMode::TransientPointer => XRTargetRayMode::Transient_pointer,
135 }
136 }
137
138 fn TargetRaySpace(&self, cx: &mut JSContext) -> DomRoot<XRSpace> {
140 self.target_ray_space.or_init(|| {
141 let global = self.global();
142 XRSpace::new_inputspace(cx, &global, &self.session, self, false)
143 })
144 }
145
146 fn GetGripSpace(&self, cx: &mut JSContext) -> Option<DomRoot<XRSpace>> {
148 if self.info.supports_grip {
149 Some(self.grip_space.or_init(|| {
150 let global = self.global();
151 XRSpace::new_inputspace(cx, &global, &self.session, self, true)
152 }))
153 } else {
154 None
155 }
156 }
157 fn Profiles(&self, mut retval: MutableHandleValue) {
159 retval.set(self.profiles.get())
160 }
161
162 fn SkipRendering(&self) -> bool {
164 false
167 }
168
169 fn GetGamepad(&self) -> Option<DomRoot<Gamepad>> {
171 Some(DomRoot::from_ref(&*self.gamepad))
172 }
173
174 fn GetHand(&self, cx: &mut JSContext) -> Option<DomRoot<XRHand>> {
176 self.info.hand_support.as_ref().map(|hand| {
177 self.hand
178 .or_init(|| XRHand::new(cx, &self.global(), self, hand.clone()))
179 })
180 }
181}