script/dom/webxr/
fakexrinputcontroller.rs1use base::generic_channel::GenericSender;
6use dom_struct::dom_struct;
7use webxr_api::{
8 Handedness, InputId, MockButton, MockButtonType, MockDeviceMsg, MockInputMsg, SelectEvent,
9 SelectKind, TargetRayMode,
10};
11
12use crate::conversions::Convert;
13use crate::dom::bindings::codegen::Bindings::FakeXRDeviceBinding::FakeXRRigidTransformInit;
14use crate::dom::bindings::codegen::Bindings::FakeXRInputControllerBinding::{
15 FakeXRButtonStateInit, FakeXRButtonType, FakeXRInputControllerMethods,
16};
17use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding::{
18 XRHandedness, XRTargetRayMode,
19};
20use crate::dom::bindings::error::{Error, Fallible};
21use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
22use crate::dom::bindings::root::DomRoot;
23use crate::dom::bindings::str::DOMString;
24use crate::dom::fakexrdevice::get_origin;
25use crate::dom::globalscope::GlobalScope;
26use crate::script_runtime::CanGc;
27
28#[dom_struct]
29pub(crate) struct FakeXRInputController {
30 reflector: Reflector,
31 #[no_trace]
32 sender: GenericSender<MockDeviceMsg>,
33 #[ignore_malloc_size_of = "defined in webxr-api"]
34 #[no_trace]
35 id: InputId,
36}
37
38impl FakeXRInputController {
39 pub(crate) fn new_inherited(
40 sender: GenericSender<MockDeviceMsg>,
41 id: InputId,
42 ) -> FakeXRInputController {
43 FakeXRInputController {
44 reflector: Reflector::new(),
45 sender,
46 id,
47 }
48 }
49
50 pub(crate) fn new(
51 global: &GlobalScope,
52 sender: GenericSender<MockDeviceMsg>,
53 id: InputId,
54 can_gc: CanGc,
55 ) -> DomRoot<FakeXRInputController> {
56 reflect_dom_object(
57 Box::new(FakeXRInputController::new_inherited(sender, id)),
58 global,
59 can_gc,
60 )
61 }
62
63 fn send_message(&self, msg: MockInputMsg) {
64 let _ = self
65 .sender
66 .send(MockDeviceMsg::MessageInputSource(self.id, msg));
67 }
68}
69
70impl FakeXRInputControllerMethods<crate::DomTypeHolder> for FakeXRInputController {
71 fn SetPointerOrigin(&self, origin: &FakeXRRigidTransformInit, _emulated: bool) -> Fallible<()> {
73 self.send_message(MockInputMsg::SetPointerOrigin(Some(get_origin(origin)?)));
74 Ok(())
75 }
76
77 fn SetGripOrigin(&self, origin: &FakeXRRigidTransformInit, _emulated: bool) -> Fallible<()> {
79 self.send_message(MockInputMsg::SetGripOrigin(Some(get_origin(origin)?)));
80 Ok(())
81 }
82
83 fn ClearGripOrigin(&self) {
85 self.send_message(MockInputMsg::SetGripOrigin(None))
86 }
87
88 fn Disconnect(&self) {
90 self.send_message(MockInputMsg::Disconnect)
91 }
92
93 fn Reconnect(&self) {
95 self.send_message(MockInputMsg::Reconnect)
96 }
97
98 fn StartSelection(&self) {
100 self.send_message(MockInputMsg::TriggerSelect(
101 SelectKind::Select,
102 SelectEvent::Start,
103 ))
104 }
105
106 fn EndSelection(&self) {
108 self.send_message(MockInputMsg::TriggerSelect(
109 SelectKind::Select,
110 SelectEvent::End,
111 ))
112 }
113
114 fn SimulateSelect(&self) {
116 self.send_message(MockInputMsg::TriggerSelect(
117 SelectKind::Select,
118 SelectEvent::Select,
119 ))
120 }
121
122 fn SetHandedness(&self, handedness: XRHandedness) {
124 let h = match handedness {
125 XRHandedness::None => Handedness::None,
126 XRHandedness::Left => Handedness::Left,
127 XRHandedness::Right => Handedness::Right,
128 };
129 self.send_message(MockInputMsg::SetHandedness(h));
130 }
131
132 fn SetTargetRayMode(&self, target_ray_mode: XRTargetRayMode) {
134 let t = match target_ray_mode {
135 XRTargetRayMode::Gaze => TargetRayMode::Gaze,
136 XRTargetRayMode::Tracked_pointer => TargetRayMode::TrackedPointer,
137 XRTargetRayMode::Screen => TargetRayMode::Screen,
138 XRTargetRayMode::Transient_pointer => TargetRayMode::TransientPointer,
139 };
140 self.send_message(MockInputMsg::SetTargetRayMode(t));
141 }
142
143 fn SetProfiles(&self, profiles: Vec<DOMString>) {
145 let t = profiles.into_iter().map(String::from).collect();
146 self.send_message(MockInputMsg::SetProfiles(t));
147 }
148
149 fn SetSupportedButtons(&self, supported_buttons: Vec<FakeXRButtonStateInit>) {
151 let supported = init_to_mock_buttons(&supported_buttons);
152 self.send_message(MockInputMsg::SetSupportedButtons(supported));
153 }
154
155 fn UpdateButtonState(&self, button_state: &FakeXRButtonStateInit) -> Fallible<()> {
157 if (button_state.pressed || *button_state.pressedValue > 0.0) && !button_state.touched {
159 return Err(Error::Type("Pressed button must also be touched".into()));
160 }
161 if *button_state.pressedValue < 0.0 {
162 return Err(Error::Type("Pressed value must be non-negative".into()));
163 }
164
165 Ok(())
171 }
172}
173
174impl Convert<MockButtonType> for FakeXRButtonType {
175 fn convert(self) -> MockButtonType {
176 match self {
177 FakeXRButtonType::Grip => MockButtonType::Grip,
178 FakeXRButtonType::Touchpad => MockButtonType::Touchpad,
179 FakeXRButtonType::Thumbstick => MockButtonType::Thumbstick,
180 FakeXRButtonType::Optional_button => MockButtonType::OptionalButton,
181 FakeXRButtonType::Optional_thumbstick => MockButtonType::OptionalThumbstick,
182 }
183 }
184}
185
186pub(crate) fn init_to_mock_buttons(buttons: &[FakeXRButtonStateInit]) -> Vec<MockButton> {
188 let supported: Vec<MockButton> = buttons
189 .iter()
190 .map(|b| MockButton {
191 button_type: b.buttonType.convert(),
192 pressed: b.pressed,
193 touched: b.touched,
194 pressed_value: *b.pressedValue,
195 x_value: *b.xValue,
196 y_value: *b.yValue,
197 })
198 .collect();
199 supported
200}