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 #[no_trace]
34 id: InputId,
35}
36
37impl FakeXRInputController {
38 pub(crate) fn new_inherited(
39 sender: GenericSender<MockDeviceMsg>,
40 id: InputId,
41 ) -> FakeXRInputController {
42 FakeXRInputController {
43 reflector: Reflector::new(),
44 sender,
45 id,
46 }
47 }
48
49 pub(crate) fn new(
50 global: &GlobalScope,
51 sender: GenericSender<MockDeviceMsg>,
52 id: InputId,
53 can_gc: CanGc,
54 ) -> DomRoot<FakeXRInputController> {
55 reflect_dom_object(
56 Box::new(FakeXRInputController::new_inherited(sender, id)),
57 global,
58 can_gc,
59 )
60 }
61
62 fn send_message(&self, msg: MockInputMsg) {
63 let _ = self
64 .sender
65 .send(MockDeviceMsg::MessageInputSource(self.id, msg));
66 }
67}
68
69impl FakeXRInputControllerMethods<crate::DomTypeHolder> for FakeXRInputController {
70 fn SetPointerOrigin(&self, origin: &FakeXRRigidTransformInit, _emulated: bool) -> Fallible<()> {
72 self.send_message(MockInputMsg::SetPointerOrigin(Some(get_origin(origin)?)));
73 Ok(())
74 }
75
76 fn SetGripOrigin(&self, origin: &FakeXRRigidTransformInit, _emulated: bool) -> Fallible<()> {
78 self.send_message(MockInputMsg::SetGripOrigin(Some(get_origin(origin)?)));
79 Ok(())
80 }
81
82 fn ClearGripOrigin(&self) {
84 self.send_message(MockInputMsg::SetGripOrigin(None))
85 }
86
87 fn Disconnect(&self) {
89 self.send_message(MockInputMsg::Disconnect)
90 }
91
92 fn Reconnect(&self) {
94 self.send_message(MockInputMsg::Reconnect)
95 }
96
97 fn StartSelection(&self) {
99 self.send_message(MockInputMsg::TriggerSelect(
100 SelectKind::Select,
101 SelectEvent::Start,
102 ))
103 }
104
105 fn EndSelection(&self) {
107 self.send_message(MockInputMsg::TriggerSelect(
108 SelectKind::Select,
109 SelectEvent::End,
110 ))
111 }
112
113 fn SimulateSelect(&self) {
115 self.send_message(MockInputMsg::TriggerSelect(
116 SelectKind::Select,
117 SelectEvent::Select,
118 ))
119 }
120
121 fn SetHandedness(&self, handedness: XRHandedness) {
123 let h = match handedness {
124 XRHandedness::None => Handedness::None,
125 XRHandedness::Left => Handedness::Left,
126 XRHandedness::Right => Handedness::Right,
127 };
128 self.send_message(MockInputMsg::SetHandedness(h));
129 }
130
131 fn SetTargetRayMode(&self, target_ray_mode: XRTargetRayMode) {
133 let t = match target_ray_mode {
134 XRTargetRayMode::Gaze => TargetRayMode::Gaze,
135 XRTargetRayMode::Tracked_pointer => TargetRayMode::TrackedPointer,
136 XRTargetRayMode::Screen => TargetRayMode::Screen,
137 XRTargetRayMode::Transient_pointer => TargetRayMode::TransientPointer,
138 };
139 self.send_message(MockInputMsg::SetTargetRayMode(t));
140 }
141
142 fn SetProfiles(&self, profiles: Vec<DOMString>) {
144 let t = profiles.into_iter().map(String::from).collect();
145 self.send_message(MockInputMsg::SetProfiles(t));
146 }
147
148 fn SetSupportedButtons(&self, supported_buttons: Vec<FakeXRButtonStateInit>) {
150 let supported = init_to_mock_buttons(&supported_buttons);
151 self.send_message(MockInputMsg::SetSupportedButtons(supported));
152 }
153
154 fn UpdateButtonState(&self, button_state: &FakeXRButtonStateInit) -> Fallible<()> {
156 if (button_state.pressed || *button_state.pressedValue > 0.0) && !button_state.touched {
158 return Err(Error::Type(c"Pressed button must also be touched".into()));
159 }
160 if *button_state.pressedValue < 0.0 {
161 return Err(Error::Type(c"Pressed value must be non-negative".into()));
162 }
163
164 Ok(())
170 }
171}
172
173impl Convert<MockButtonType> for FakeXRButtonType {
174 fn convert(self) -> MockButtonType {
175 match self {
176 FakeXRButtonType::Grip => MockButtonType::Grip,
177 FakeXRButtonType::Touchpad => MockButtonType::Touchpad,
178 FakeXRButtonType::Thumbstick => MockButtonType::Thumbstick,
179 FakeXRButtonType::Optional_button => MockButtonType::OptionalButton,
180 FakeXRButtonType::Optional_thumbstick => MockButtonType::OptionalThumbstick,
181 }
182 }
183}
184
185pub(crate) fn init_to_mock_buttons(buttons: &[FakeXRButtonStateInit]) -> Vec<MockButton> {
187 let supported: Vec<MockButton> = buttons
188 .iter()
189 .map(|b| MockButton {
190 button_type: b.buttonType.convert(),
191 pressed: b.pressed,
192 touched: b.touched,
193 pressed_value: *b.pressedValue,
194 x_value: *b.xValue,
195 y_value: *b.yValue,
196 })
197 .collect();
198 supported
199}