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