@woosh/meep-engine 3.35.0 → 3.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/engine/Engine.d.ts +2 -0
- package/src/engine/Engine.d.ts.map +1 -1
- package/src/engine/Engine.js +5 -1
- package/src/engine/input/devices/XRInputDevice.d.ts +63 -0
- package/src/engine/input/devices/XRInputDevice.d.ts.map +1 -0
- package/src/engine/input/devices/XRInputDevice.js +386 -0
- package/src/engine/input/devices/xr/XRInputAction.d.ts +37 -0
- package/src/engine/input/devices/xr/XRInputAction.d.ts.map +1 -0
- package/src/engine/input/devices/xr/XRInputAction.js +85 -0
- package/src/engine/input/devices/xr/XRInputButton.d.ts +28 -0
- package/src/engine/input/devices/xr/XRInputButton.d.ts.map +1 -0
- package/src/engine/input/devices/xr/XRInputButton.js +43 -0
- package/src/engine/input/devices/xr/XRInputCoordinates.d.ts +15 -0
- package/src/engine/input/devices/xr/XRInputCoordinates.d.ts.map +1 -0
- package/src/engine/input/devices/xr/XRInputCoordinates.js +21 -0
- package/src/engine/input/devices/xr/XRInputHandle.d.ts +63 -0
- package/src/engine/input/devices/xr/XRInputHandle.d.ts.map +1 -0
- package/src/engine/input/devices/xr/XRInputHandle.js +171 -0
- package/src/engine/input/devices/xr/XRInputPose.d.ts +23 -0
- package/src/engine/input/devices/xr/XRInputPose.d.ts.map +1 -0
- package/src/engine/input/devices/xr/XRInputPose.js +36 -0
- package/src/engine/input/devices/xr/XRInputTypes.d.ts +76 -0
- package/src/engine/input/devices/xr/XRInputTypes.d.ts.map +1 -0
- package/src/engine/input/devices/xr/XRInputTypes.js +31 -0
- package/src/engine/input/devices/xr/XRInputValueSource.d.ts +11 -0
- package/src/engine/input/devices/xr/XRInputValueSource.d.ts.map +1 -0
- package/src/engine/input/devices/xr/XRInputValueSource.js +11 -0
- package/src/engine/input/ecs/ism/coordinate/InputCoordinateChannel.d.ts +15 -1
- package/src/engine/input/ecs/ism/coordinate/InputCoordinateChannel.d.ts.map +1 -1
- package/src/engine/input/ecs/ism/coordinate/InputCoordinateChannel.js +9 -0
- package/src/engine/input/ecs/ism/coordinate/InputCoordinateDevice.d.ts +15 -4
- package/src/engine/input/ecs/ism/coordinate/InputCoordinateDevice.d.ts.map +1 -1
- package/src/engine/input/ecs/ism/coordinate/InputCoordinateDevice.js +22 -0
- package/src/engine/input/ecs/ism/coordinate/InputCoordinateSwitches.d.ts +17 -2
- package/src/engine/input/ecs/ism/coordinate/InputCoordinateSwitches.d.ts.map +1 -1
- package/src/engine/input/ecs/ism/device/GamepadInputDeviceAdapter.d.ts +5 -0
- package/src/engine/input/ecs/ism/device/GamepadInputDeviceAdapter.d.ts.map +1 -1
- package/src/engine/input/ecs/ism/device/InputDeviceAdapter.d.ts +2 -0
- package/src/engine/input/ecs/ism/device/InputDeviceAdapter.d.ts.map +1 -1
- package/src/engine/input/ecs/ism/device/InputDeviceAdapter.js +2 -0
- package/src/engine/input/ecs/ism/device/KeyboardInputDeviceAdapter.d.ts +7 -0
- package/src/engine/input/ecs/ism/device/KeyboardInputDeviceAdapter.d.ts.map +1 -1
- package/src/engine/input/ecs/ism/device/ManualInputDeviceAdapter.d.ts +5 -0
- package/src/engine/input/ecs/ism/device/ManualInputDeviceAdapter.d.ts.map +1 -1
- package/src/engine/input/ecs/ism/device/PointerInputDeviceAdapter.d.ts +5 -0
- package/src/engine/input/ecs/ism/device/PointerInputDeviceAdapter.d.ts.map +1 -1
- package/src/engine/input/ecs/ism/device/XRInputDeviceAdapter.d.ts +16 -0
- package/src/engine/input/ecs/ism/device/XRInputDeviceAdapter.d.ts.map +1 -0
- package/src/engine/input/ecs/ism/device/XRInputDeviceAdapter.js +54 -0
- package/src/engine/input/ecs/ism/device/XR_INPUT_DEVICE_IDS.d.ts +9 -0
- package/src/engine/input/ecs/ism/device/XR_INPUT_DEVICE_IDS.d.ts.map +1 -0
- package/src/engine/input/ecs/ism/device/XR_INPUT_DEVICE_IDS.js +12 -0
- package/src/engine/input/ecs/ism/trigger/InputTrigger.d.ts +11 -1
- package/src/engine/input/ecs/ism/trigger/InputTrigger.d.ts.map +1 -1
- package/src/engine/input/ecs/ism/trigger/InputTrigger.js +7 -0
- package/src/engine/input/ecs/ism/trigger/InputTriggerChord.d.ts +16 -2
- package/src/engine/input/ecs/ism/trigger/InputTriggerChord.d.ts.map +1 -1
- package/src/engine/input/ecs/ism/trigger/InputTriggerHold.d.ts +22 -2
- package/src/engine/input/ecs/ism/trigger/InputTriggerHold.d.ts.map +1 -1
- package/src/engine/input/ecs/ism/trigger/InputTriggerRelease.d.ts +16 -2
- package/src/engine/input/ecs/ism/trigger/InputTriggerRelease.d.ts.map +1 -1
- package/src/engine/input/ecs/ism/trigger/InputTriggerSequence.d.ts +24 -4
- package/src/engine/input/ecs/ism/trigger/InputTriggerSequence.d.ts.map +1 -1
- package/src/engine/input/ecs/ism/trigger/InputTriggerSwitch.d.ts +6 -8
- package/src/engine/input/ecs/ism/trigger/InputTriggerSwitch.d.ts.map +1 -1
- package/src/engine/input/ecs/ism/trigger/InputTriggerSwitch.js +5 -0
- package/src/engine/input/ecs/ism/trigger/InputTriggerXRButton.d.ts +7 -0
- package/src/engine/input/ecs/ism/trigger/InputTriggerXRButton.d.ts.map +1 -0
- package/src/engine/input/ecs/ism/trigger/InputTriggerXRButton.js +15 -0
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
package/package.json
CHANGED
package/src/engine/Engine.d.ts
CHANGED
|
@@ -114,6 +114,7 @@ declare class Engine {
|
|
|
114
114
|
pointer: PointerDevice;
|
|
115
115
|
keyboard: KeyboardDevice;
|
|
116
116
|
gamepad: GamepadDevice;
|
|
117
|
+
xr: XRInputDevice;
|
|
117
118
|
};
|
|
118
119
|
/**
|
|
119
120
|
* Toggles GraphicsEngine rendering on and off
|
|
@@ -179,6 +180,7 @@ import SceneManager from "./scene/SceneManager.js";
|
|
|
179
180
|
import { PointerDevice } from "./input/devices/PointerDevice.js";
|
|
180
181
|
import KeyboardDevice from "./input/devices/KeyboardDevice.js";
|
|
181
182
|
import { GamepadDevice } from "./input/devices/GamepadDevice.js";
|
|
183
|
+
import { XRInputDevice } from "./input/devices/XRInputDevice.js";
|
|
182
184
|
import EmptyView from "../view/elements/EmptyView.js";
|
|
183
185
|
import { AssetPreloader } from "./asset/preloader/AssetPreloader.js";
|
|
184
186
|
import ObservedBoolean from "../core/model/ObservedBoolean.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Engine.d.ts","sourceRoot":"","sources":["../../../src/engine/Engine.js"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"Engine.d.ts","sourceRoot":"","sources":["../../../src/engine/Engine.js"],"names":[],"mappings":";6BAqCa,OAAO,8BAA8B,EAAE,cAAc;AAwClE;IAiGI;;;;;;;;;OASG;IACH,sBARW,cAAc;QAEU,aAAa,GAArC,aAAa;QACK,cAAc,GAAhC,OAAO;QACW,WAAW,GAA7B,OAAO;QACW,KAAK,GAAvB,OAAO;OAiPjB;IAtSD;;;OAGG;IACH,UAFU,cAAc,GAAC,IAAI,CAEb;IAEhB;;;OAGG;IACH,OAFU,WAAW,GAAC,IAAI,CAEb;IAEb,qBAA4B;IAE5B;;;;;;;;;OASG;IACH,0BAFU,uBAAuB,CAEe;IAEhD;;;OAGG;IACH,kBAFU,mBAAmB,CAEO;IAEpC;;;;OAIG;IACH,iBAFU,MAAM,CAEM;IAEtB;;;;OAIG;IACH,mBAFU,kBAAkB,CAEa;IAoBrC;;;OAGG;IACH,UAFU,cAAc,CAEA;IAKxB;;;OAGG;IACH,aAFU,gBAAgB,CAEe;IAGzC,yCAAkE;IAK9D,6BAAkC;IAMtC;;;OAGG;IACH,cAFU,aAAa,MAAM,CAAC,CAK5B;IAEF,8CAiCE;IAgCF;;;OAGG;IACH,SAFU,WAAW,CAEoB;IAEzC;;;OAGG;IACH,oCAA0C;IAE1C;;;OAGG;IACH,sCAFU,2BAA2B,CAE+B;IAEpE,yBAAoC;IAGpC;;OAEG;IACH,aAAkB;IAElB;;;OAGG;IACH,SAFU,OAAO,CAEwB;IAGzC,2BAAsC;IAuCtC;;;OAGG;IACH,KAFU,SAAS,CAEO;IAE1B;;;OAGG;IACH,uBAFU,YAAY,CAEqD;IAI3E;;;;;MAKC;IA8BD;;;OAGG;IACH,kBAFU,OAAO,CAEW;IAwIhC,wBAgCC;IApBG,oBAAwB;IAsB5B,2BA8CC;IAED,oBAiBC;IAED;;;OAGG;IACH,+CAUC;IAED,eAkDC;IAED;;;OAGG;IACH,sBAuGC;IAqBD;;OAEG;IACH,sBAgEC;IAED,aAEC;IAED;;OAEG;IACH,4BAOC;IAIL;;;OAGG;IACH,mBAFU,OAAO,CAEQ;;CAPxB;+BAl5B8B,+BAA+B;wBAWtC,wBAAwB;0BArBtB,0CAA0C;wCAeN,iDAAiD;oCAG3E,iCAAiC;mBAElD,wBAAwB;+BAtBZ,gDAAgD;iCAO9C,+CAA+C;8BAGlD,wBAAwB;6BALzB,yBAAyB;uCAIf,6DAA6D;4BAUxE,0BAA0B;+BArBvB,iCAAiC;4CAapB,qDAAqD;AAgBjG;;GAEG;AAGH;IACI,gDAA2D;IAC3D,0BAAkC;IAClC,iCAAyC;CAC5C;6BAvC4B,sCAAsC;sBA4B7C,mBAAmB;yBAJhB,yBAAyB;8BALpB,kCAAkC;2BADrC,mCAAmC;8BAFhC,kCAAkC;8BAClC,kCAAkC;sBAb1C,+BAA+B;+BAKtB,qCAAqC;4BAPxC,kCAAkC;oBAH1C,yBAAyB"}
|
package/src/engine/Engine.js
CHANGED
|
@@ -21,6 +21,7 @@ import { EntityManager } from "./ecs/EntityManager.js";
|
|
|
21
21
|
import { BinarySerializationRegistry } from "./ecs/storage/binary/BinarySerializationRegistry.js";
|
|
22
22
|
import { GraphicsEngine } from './graphics3/GraphicsEngine.js';
|
|
23
23
|
import { GamepadDevice } from "./input/devices/GamepadDevice.js";
|
|
24
|
+
import { XRInputDevice } from "./input/devices/XRInputDevice.js";
|
|
24
25
|
import KeyboardDevice from "./input/devices/KeyboardDevice.js";
|
|
25
26
|
import { PointerDevice } from "./input/devices/PointerDevice.js";
|
|
26
27
|
import { StaticKnowledgeDatabase, StaticKnowledgeState } from "./knowledge/database/StaticKnowledgeDatabase.js";
|
|
@@ -379,12 +380,14 @@ class Engine {
|
|
|
379
380
|
this.devices = {
|
|
380
381
|
pointer: new PointerDevice(this.viewStack.el),
|
|
381
382
|
keyboard: new KeyboardDevice(this.viewStack.el),
|
|
382
|
-
gamepad: new GamepadDevice()
|
|
383
|
+
gamepad: new GamepadDevice(),
|
|
384
|
+
xr: new XRInputDevice()
|
|
383
385
|
};
|
|
384
386
|
|
|
385
387
|
this.devices.pointer.start();
|
|
386
388
|
this.devices.keyboard.start();
|
|
387
389
|
this.devices.gamepad.start();
|
|
390
|
+
this.devices.xr.start();
|
|
388
391
|
|
|
389
392
|
/*
|
|
390
393
|
Only the focused element receives keyboard events. `ViewStack` sets `tabindex` on its
|
|
@@ -869,6 +872,7 @@ class Engine {
|
|
|
869
872
|
this.devices.pointer.stop();
|
|
870
873
|
this.devices.keyboard.stop();
|
|
871
874
|
this.devices.gamepad.stop();
|
|
875
|
+
this.devices.xr.stop();
|
|
872
876
|
|
|
873
877
|
// shutdown entity manager
|
|
874
878
|
if (!this.__using_external_entity_manager) {
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session-owned WebXR input. Safe to construct/start without a browser, XR support, or hardware.
|
|
3
|
+
* This device never requests a session or schedules frames. The application owns both:
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* engine.devices.xr.setSession(session, referenceSpace);
|
|
7
|
+
* // In the session's requestAnimationFrame callback, before gameplay reads input:
|
|
8
|
+
* engine.devices.xr.poll(frame);
|
|
9
|
+
* // Ordinary Vector1 and Signal bindings, valid even before a session exists:
|
|
10
|
+
* engine.devices.xr.right.select.onChanged.add(amount => { });
|
|
11
|
+
* engine.devices.xr.right.select.completed.add(() => { });
|
|
12
|
+
*
|
|
13
|
+
* left/right/none are stable slots, each retaining the oldest available source of that handedness.
|
|
14
|
+
* sources contains every live source, keyed internally by native object identity (never gamepad.index).
|
|
15
|
+
* A slot swap neutralises its old controls and cancels unfinished actions before adopting new hardware.
|
|
16
|
+
* Completed actions are not cancelled. Binding a slot midway through an action does not replay it.
|
|
17
|
+
*
|
|
18
|
+
* Lifecycle changes requested by signal handlers take effect after the current update. This keeps a
|
|
19
|
+
* stop/session replacement from being overwritten by the remainder of that update. Native frames are
|
|
20
|
+
* consumed synchronously and never retained. Recursive poll calls are ignored.
|
|
21
|
+
*/
|
|
22
|
+
export class XRInputDevice {
|
|
23
|
+
/** @readonly */
|
|
24
|
+
readonly left: XRInputHandle;
|
|
25
|
+
/** @readonly */
|
|
26
|
+
readonly right: XRInputHandle;
|
|
27
|
+
/** @readonly */
|
|
28
|
+
readonly none: XRInputHandle;
|
|
29
|
+
/** @readonly @type {XRInputHandle[]} Read only; membership is owned by the device. */
|
|
30
|
+
readonly sources: XRInputHandle[];
|
|
31
|
+
/** @readonly */
|
|
32
|
+
readonly on: {
|
|
33
|
+
/** @type {Signal} Dispatches the connected XRInputHandle. */
|
|
34
|
+
connected: Signal;
|
|
35
|
+
/** @type {Signal} Dispatches the XRInputHandle, already neutral and detached. */
|
|
36
|
+
disconnected: Signal;
|
|
37
|
+
};
|
|
38
|
+
/** @readonly @type {import('./xr/XRInputTypes.js').XRSession|null} Change through setSession. */
|
|
39
|
+
readonly session: import('./xr/XRInputTypes.js').XRSession | null;
|
|
40
|
+
/** @readonly @type {EventTarget|null} Change through setReferenceSpace. */
|
|
41
|
+
readonly referenceSpace: EventTarget | null;
|
|
42
|
+
get isRunning(): boolean;
|
|
43
|
+
start(): void;
|
|
44
|
+
/** Detach without ending the application's native XRSession. */
|
|
45
|
+
stop(): void;
|
|
46
|
+
/**
|
|
47
|
+
* May be called before start. Null detaches; attaching does not request permission or own session.end().
|
|
48
|
+
* @param {import('./xr/XRInputTypes.js').XRSession|null} session
|
|
49
|
+
* @param {EventTarget|null} [referenceSpace=null] Null still samples controls, with invalid poses.
|
|
50
|
+
*/
|
|
51
|
+
setSession(session: import('./xr/XRInputTypes.js').XRSession | null, referenceSpace?: EventTarget | null): void;
|
|
52
|
+
/** @param {EventTarget|null} referenceSpace */
|
|
53
|
+
setReferenceSpace(referenceSpace: EventTarget | null): void;
|
|
54
|
+
/**
|
|
55
|
+
* No-op without a running session. Otherwise call only within that session's active frame callback.
|
|
56
|
+
* @param {import('./xr/XRInputTypes.js').XRFrame} [frame]
|
|
57
|
+
*/
|
|
58
|
+
poll(frame?: import('./xr/XRInputTypes.js').XRFrame): void;
|
|
59
|
+
#private;
|
|
60
|
+
}
|
|
61
|
+
import { XRInputHandle } from "./xr/XRInputHandle.js";
|
|
62
|
+
import Signal from "../../../core/events/signal/Signal.js";
|
|
63
|
+
//# sourceMappingURL=XRInputDevice.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"XRInputDevice.d.ts","sourceRoot":"","sources":["../../../../../src/engine/input/devices/XRInputDevice.js"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH;IACI,gBAAgB;IAChB,6BAA2B;IAC3B,gBAAgB;IAChB,8BAA4B;IAC5B,gBAAgB;IAChB,6BAA2B;IAC3B,sFAAsF;IACtF,kBADqB,aAAa,EAAE,CACvB;IACb,gBAAgB;IAChB;QACI,6DAA6D;mBAAlD,MAAM;QAEjB,iFAAiF;sBAAtE,MAAM;MAEnB;IAOF,iGAAiG;IACjG,kBADqB,OAAO,sBAAsB,EAAE,SAAS,GAAC,IAAI,CACnD;IACf,2EAA2E;IAC3E,yBADqB,WAAW,GAAC,IAAI,CACf;IAOtB,yBAAyC;IAEzC,cAiBC;IAED,gEAAgE;IAChE,aAYC;IAED;;;;OAIG;IACH,oBAHW,OAAO,sBAAsB,EAAE,SAAS,GAAC,IAAI,mBAC7C,WAAW,GAAC,IAAI,QA4B1B;IAED,+CAA+C;IAC/C,kCADY,WAAW,GAAC,IAAI,QAuB3B;IAED;;;OAGG;IACH,aAFW,OAAO,sBAAsB,EAAE,OAAO,QAehD;;CAsNJ;8BA/X6B,uBAAuB;mBADlC,uCAAuC"}
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { assert } from "../../../core/assert.js";
|
|
2
|
+
import Signal from "../../../core/events/signal/Signal.js";
|
|
3
|
+
import { XRInputHandle } from "./xr/XRInputHandle.js";
|
|
4
|
+
|
|
5
|
+
const SESSION_EVENTS = ['inputsourceschange', 'selectstart', 'select', 'selectend',
|
|
6
|
+
'squeezestart', 'squeeze', 'squeezeend', 'visibilitychange', 'end'];
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Session-owned WebXR input. Safe to construct/start without a browser, XR support, or hardware.
|
|
10
|
+
* This device never requests a session or schedules frames. The application owns both:
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* engine.devices.xr.setSession(session, referenceSpace);
|
|
14
|
+
* // In the session's requestAnimationFrame callback, before gameplay reads input:
|
|
15
|
+
* engine.devices.xr.poll(frame);
|
|
16
|
+
* // Ordinary Vector1 and Signal bindings, valid even before a session exists:
|
|
17
|
+
* engine.devices.xr.right.select.onChanged.add(amount => { });
|
|
18
|
+
* engine.devices.xr.right.select.completed.add(() => { });
|
|
19
|
+
*
|
|
20
|
+
* left/right/none are stable slots, each retaining the oldest available source of that handedness.
|
|
21
|
+
* sources contains every live source, keyed internally by native object identity (never gamepad.index).
|
|
22
|
+
* A slot swap neutralises its old controls and cancels unfinished actions before adopting new hardware.
|
|
23
|
+
* Completed actions are not cancelled. Binding a slot midway through an action does not replay it.
|
|
24
|
+
*
|
|
25
|
+
* Lifecycle changes requested by signal handlers take effect after the current update. This keeps a
|
|
26
|
+
* stop/session replacement from being overwritten by the remainder of that update. Native frames are
|
|
27
|
+
* consumed synchronously and never retained. Recursive poll calls are ignored.
|
|
28
|
+
*/
|
|
29
|
+
export class XRInputDevice {
|
|
30
|
+
/** @readonly */
|
|
31
|
+
left = new XRInputHandle();
|
|
32
|
+
/** @readonly */
|
|
33
|
+
right = new XRInputHandle();
|
|
34
|
+
/** @readonly */
|
|
35
|
+
none = new XRInputHandle();
|
|
36
|
+
/** @readonly @type {XRInputHandle[]} Read only; membership is owned by the device. */
|
|
37
|
+
sources = [];
|
|
38
|
+
/** @readonly */
|
|
39
|
+
on = {
|
|
40
|
+
/** @type {Signal} Dispatches the connected XRInputHandle. */
|
|
41
|
+
connected: new Signal(),
|
|
42
|
+
/** @type {Signal} Dispatches the XRInputHandle, already neutral and detached. */
|
|
43
|
+
disconnected: new Signal()
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
#slots = [this.left, this.right, this.none];
|
|
47
|
+
/** @type {Map<import('./xr/XRInputTypes.js').XRInputSource, XRInputHandle>} */
|
|
48
|
+
#handles = new Map();
|
|
49
|
+
/** @type {XRInputHandle[]} */
|
|
50
|
+
#connected = [];
|
|
51
|
+
/** @readonly @type {import('./xr/XRInputTypes.js').XRSession|null} Change through setSession. */
|
|
52
|
+
session = null;
|
|
53
|
+
/** @readonly @type {EventTarget|null} Change through setReferenceSpace. */
|
|
54
|
+
referenceSpace = null;
|
|
55
|
+
#running = false;
|
|
56
|
+
#busy = false;
|
|
57
|
+
#draining = false;
|
|
58
|
+
/** @type {Array<()=>void>} Only reentrant configuration changes are queued, never frames. */
|
|
59
|
+
#pending = [];
|
|
60
|
+
|
|
61
|
+
get isRunning() { return this.#running; }
|
|
62
|
+
|
|
63
|
+
start() {
|
|
64
|
+
if (this.#busy) {
|
|
65
|
+
this.#pending.push(() => this.start());
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (this.#running) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
this.#busy = true;
|
|
72
|
+
try {
|
|
73
|
+
this.#running = true;
|
|
74
|
+
this.#listen(true);
|
|
75
|
+
this.#reconcile();
|
|
76
|
+
this.#sample(null);
|
|
77
|
+
} finally {
|
|
78
|
+
this.#finish();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Detach without ending the application's native XRSession. */
|
|
83
|
+
stop() {
|
|
84
|
+
if (this.#busy) {
|
|
85
|
+
this.#pending.push(() => this.stop());
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
this.#busy = true;
|
|
89
|
+
try {
|
|
90
|
+
this.#detach();
|
|
91
|
+
this.#running = false;
|
|
92
|
+
} finally {
|
|
93
|
+
this.#finish();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* May be called before start. Null detaches; attaching does not request permission or own session.end().
|
|
99
|
+
* @param {import('./xr/XRInputTypes.js').XRSession|null} session
|
|
100
|
+
* @param {EventTarget|null} [referenceSpace=null] Null still samples controls, with invalid poses.
|
|
101
|
+
*/
|
|
102
|
+
setSession(session, referenceSpace = null) {
|
|
103
|
+
assert.defined(session, 'session');
|
|
104
|
+
if (session === null) {
|
|
105
|
+
referenceSpace = null;
|
|
106
|
+
}
|
|
107
|
+
if (this.#busy) {
|
|
108
|
+
this.#pending.push(() => this.setSession(session, referenceSpace));
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (session === this.session) {
|
|
112
|
+
this.setReferenceSpace(referenceSpace);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
this.#busy = true;
|
|
116
|
+
try {
|
|
117
|
+
this.#detach();
|
|
118
|
+
this.session = session;
|
|
119
|
+
this.referenceSpace = session === null ? null : referenceSpace;
|
|
120
|
+
if (this.#running) {
|
|
121
|
+
this.#listen(true);
|
|
122
|
+
this.#reconcile();
|
|
123
|
+
this.#sample(null);
|
|
124
|
+
}
|
|
125
|
+
} finally {
|
|
126
|
+
this.#finish();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** @param {EventTarget|null} referenceSpace */
|
|
131
|
+
setReferenceSpace(referenceSpace) {
|
|
132
|
+
assert.defined(referenceSpace, 'referenceSpace');
|
|
133
|
+
if (this.#busy) {
|
|
134
|
+
this.#pending.push(() => this.setReferenceSpace(referenceSpace));
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (referenceSpace === this.referenceSpace) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
this.#busy = true;
|
|
141
|
+
try {
|
|
142
|
+
if (this.referenceSpace !== null && this.#running) {
|
|
143
|
+
this.referenceSpace.removeEventListener('reset', this.#onReset);
|
|
144
|
+
}
|
|
145
|
+
this.referenceSpace = referenceSpace;
|
|
146
|
+
if (referenceSpace !== null && this.#running) {
|
|
147
|
+
referenceSpace.addEventListener('reset', this.#onReset);
|
|
148
|
+
}
|
|
149
|
+
this.#invalidatePoses();
|
|
150
|
+
} finally {
|
|
151
|
+
this.#finish();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* No-op without a running session. Otherwise call only within that session's active frame callback.
|
|
157
|
+
* @param {import('./xr/XRInputTypes.js').XRFrame} [frame]
|
|
158
|
+
*/
|
|
159
|
+
poll(frame) {
|
|
160
|
+
if (!this.#running || this.session === null || this.#busy) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
assert.defined(frame, 'frame');
|
|
164
|
+
assert.equal(frame.session, this.session, 'frame.session');
|
|
165
|
+
this.#busy = true;
|
|
166
|
+
try {
|
|
167
|
+
this.#reconcile();
|
|
168
|
+
this.#sample(frame);
|
|
169
|
+
} finally {
|
|
170
|
+
this.#finish();
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** @param {boolean} add */
|
|
175
|
+
#listen(add) {
|
|
176
|
+
const method = add ? 'addEventListener' : 'removeEventListener';
|
|
177
|
+
if (this.session !== null) {
|
|
178
|
+
for (let i = 0; i < SESSION_EVENTS.length; i++) {
|
|
179
|
+
this.session[method](SESSION_EVENTS[i], this.#onEvent);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (this.referenceSpace !== null) {
|
|
183
|
+
this.referenceSpace[method]('reset', this.#onReset);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
#detach() {
|
|
188
|
+
this.#listen(false);
|
|
189
|
+
this.session = null;
|
|
190
|
+
this.referenceSpace = null;
|
|
191
|
+
this.#clear();
|
|
192
|
+
for (let i = 0; i < this.#slots.length; i++) {
|
|
193
|
+
this.#slots[i].bind(null);
|
|
194
|
+
}
|
|
195
|
+
while (this.sources.length > 0) {
|
|
196
|
+
const handle = this.sources.pop();
|
|
197
|
+
this.#handles.delete(handle.nativeSource);
|
|
198
|
+
handle.bind(null);
|
|
199
|
+
this.on.disconnected.send1(handle);
|
|
200
|
+
}
|
|
201
|
+
this.#connected.length = 0;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** @param {import('./xr/XRInputTypes.js').XRInputSource} source */
|
|
205
|
+
#contains(source) {
|
|
206
|
+
const sources = this.session.inputSources;
|
|
207
|
+
for (let i = 0; i < sources.length; i++) {
|
|
208
|
+
if (sources[i] === source) {
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
#reconcile() {
|
|
216
|
+
if (this.session === null) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
for (let i = this.sources.length - 1; i >= 0; i--) {
|
|
220
|
+
const handle = this.sources[i];
|
|
221
|
+
const source = handle.nativeSource;
|
|
222
|
+
if (!this.#contains(source)) {
|
|
223
|
+
this.sources.splice(i, 1);
|
|
224
|
+
this.#handles.delete(source);
|
|
225
|
+
for (let j = 0; j < this.#slots.length; j++) {
|
|
226
|
+
if (this.#slots[j].nativeSource === source) {
|
|
227
|
+
this.#slots[j].bind(null);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
handle.bind(null);
|
|
231
|
+
this.on.disconnected.send1(handle);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const sources = this.session.inputSources;
|
|
235
|
+
for (let i = 0; i < sources.length; i++) {
|
|
236
|
+
const source = sources[i];
|
|
237
|
+
if (!this.#handles.has(source)) {
|
|
238
|
+
const handle = new XRInputHandle();
|
|
239
|
+
handle.bind(source);
|
|
240
|
+
this.#handles.set(source, handle);
|
|
241
|
+
this.sources.push(handle);
|
|
242
|
+
this.#connected.push(handle);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
this.#bindSlot(this.left, 'left');
|
|
246
|
+
this.#bindSlot(this.right, 'right');
|
|
247
|
+
this.#bindSlot(this.none, 'none');
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/** @param {XRInputHandle} slot @param {string} handedness */
|
|
251
|
+
#bindSlot(slot, handedness) {
|
|
252
|
+
if (slot.connected) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
for (let i = 0; i < this.sources.length; i++) {
|
|
256
|
+
const source = this.sources[i].nativeSource;
|
|
257
|
+
if (source.handedness === handedness) {
|
|
258
|
+
slot.bind(source);
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** @param {import('./xr/XRInputTypes.js').XRFrame|null} frame */
|
|
265
|
+
#sample(frame) {
|
|
266
|
+
if (this.session !== null && this.session.visibilityState === 'visible') {
|
|
267
|
+
for (let i = 0; i < this.sources.length; i++) {
|
|
268
|
+
this.sources[i].sample(frame, this.referenceSpace);
|
|
269
|
+
}
|
|
270
|
+
for (let i = 0; i < this.#slots.length; i++) {
|
|
271
|
+
this.#slots[i].sample(frame, this.referenceSpace);
|
|
272
|
+
}
|
|
273
|
+
this.#flush();
|
|
274
|
+
} else {
|
|
275
|
+
this.#clear();
|
|
276
|
+
}
|
|
277
|
+
for (let i = 0; i < this.#connected.length; i++) {
|
|
278
|
+
this.on.connected.send1(this.#connected[i]);
|
|
279
|
+
}
|
|
280
|
+
this.#connected.length = 0;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
#clear() {
|
|
284
|
+
for (let i = 0; i < this.sources.length; i++) {
|
|
285
|
+
this.sources[i].clear();
|
|
286
|
+
}
|
|
287
|
+
for (let i = 0; i < this.#slots.length; i++) {
|
|
288
|
+
this.#slots[i].clear();
|
|
289
|
+
}
|
|
290
|
+
this.#flush();
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
#flush() {
|
|
294
|
+
for (let i = 0; i < this.sources.length; i++) {
|
|
295
|
+
this.sources[i].flush();
|
|
296
|
+
}
|
|
297
|
+
for (let i = 0; i < this.#slots.length; i++) {
|
|
298
|
+
this.#slots[i].flush();
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
#invalidatePoses() {
|
|
303
|
+
for (let i = 0; i < this.sources.length; i++) {
|
|
304
|
+
this.sources[i].invalidatePoses();
|
|
305
|
+
}
|
|
306
|
+
for (let i = 0; i < this.#slots.length; i++) {
|
|
307
|
+
this.#slots[i].invalidatePoses();
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
#onReset = () => {
|
|
312
|
+
if (this.#busy) {
|
|
313
|
+
this.#pending.push(() => this.#onReset());
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
this.#busy = true;
|
|
317
|
+
try {
|
|
318
|
+
this.#invalidatePoses();
|
|
319
|
+
} finally {
|
|
320
|
+
this.#finish();
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
/** @param {import('./xr/XRInputTypes.js').XRSessionInputEvent} event */
|
|
325
|
+
#onEvent = (event) => {
|
|
326
|
+
if (!this.#running || event.currentTarget !== this.session || this.#busy) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
this.#busy = true;
|
|
330
|
+
try {
|
|
331
|
+
if (event.type === 'end') {
|
|
332
|
+
this.#detach();
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
this.#reconcile();
|
|
336
|
+
const frame = event.frame === undefined ? null : event.frame;
|
|
337
|
+
if (frame !== null && frame.session !== this.session) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
this.#sample(frame);
|
|
341
|
+
if (this.session.visibilityState !== 'visible' || event.inputSource === undefined) {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
const handle = this.#handles.get(event.inputSource);
|
|
345
|
+
if (handle === undefined) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
this.#actionEvent(handle, event.type);
|
|
349
|
+
for (let i = 0; i < this.#slots.length; i++) {
|
|
350
|
+
const slot = this.#slots[i];
|
|
351
|
+
if (slot.nativeSource === event.inputSource) {
|
|
352
|
+
this.#actionEvent(slot, event.type);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
} finally {
|
|
356
|
+
this.#finish();
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
/** @param {XRInputHandle} handle @param {string} type */
|
|
361
|
+
#actionEvent(handle, type) {
|
|
362
|
+
switch (type) {
|
|
363
|
+
case 'selectstart': handle.select.begin(); break;
|
|
364
|
+
case 'select': handle.select.complete(); break;
|
|
365
|
+
case 'selectend': handle.select.end(); break;
|
|
366
|
+
case 'squeezestart': handle.squeeze.begin(); break;
|
|
367
|
+
case 'squeeze': handle.squeeze.complete(); break;
|
|
368
|
+
case 'squeezeend': handle.squeeze.end(); break;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
#finish() {
|
|
373
|
+
this.#busy = false;
|
|
374
|
+
if (this.#draining) {
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
this.#draining = true;
|
|
378
|
+
try {
|
|
379
|
+
while (this.#pending.length > 0) {
|
|
380
|
+
this.#pending.shift()();
|
|
381
|
+
}
|
|
382
|
+
} finally {
|
|
383
|
+
this.#draining = false;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observable amount of a select/squeeze action, in [0, 1]. Read x and subscribe to onChanged as with
|
|
3
|
+
* any Vector1. The device owns mutation. Scalar changes never manufacture an action outcome.
|
|
4
|
+
*
|
|
5
|
+
* Completion/cancellation describe a browser interaction, independently of the amount. There is no
|
|
6
|
+
* public up/down state or inferred threshold. The private lifecycle only pairs native events so an
|
|
7
|
+
* interrupted interaction is cancelled once and an already completed one is never cancelled.
|
|
8
|
+
*/
|
|
9
|
+
export class XRInputAction extends Vector1 {
|
|
10
|
+
/** @readonly @type {Signal} No arguments. */
|
|
11
|
+
readonly completed: Signal;
|
|
12
|
+
/** @readonly @type {Signal} No arguments. */
|
|
13
|
+
readonly cancelled: Signal;
|
|
14
|
+
/** @type {XRInputValueSource} Do not modify directly. */
|
|
15
|
+
valueSource: XRInputValueSource;
|
|
16
|
+
/**
|
|
17
|
+
* @internal
|
|
18
|
+
* @param {XRInputValueSource} source
|
|
19
|
+
* @param {number} value
|
|
20
|
+
*/
|
|
21
|
+
update(source: XRInputValueSource, value: number): void;
|
|
22
|
+
/** @internal Called only for a native start, never inferred from the amount. */
|
|
23
|
+
begin(): void;
|
|
24
|
+
/** @internal A completion without an observed start is not replayed after a rebind/interruption. */
|
|
25
|
+
complete(): void;
|
|
26
|
+
/** @internal */
|
|
27
|
+
end(): void;
|
|
28
|
+
/** @internal Stage cancellation so the whole handle can become neutral before its notification. */
|
|
29
|
+
reset(): void;
|
|
30
|
+
/** @internal */
|
|
31
|
+
flushCancellation(): void;
|
|
32
|
+
#private;
|
|
33
|
+
}
|
|
34
|
+
import { Vector1 } from "../../../../core/geom/Vector1.js";
|
|
35
|
+
import Signal from "../../../../core/events/signal/Signal.js";
|
|
36
|
+
import { XRInputValueSource } from "./XRInputValueSource.js";
|
|
37
|
+
//# sourceMappingURL=XRInputAction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"XRInputAction.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/input/devices/xr/XRInputAction.js"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AACH;IACI,6CAA6C;IAC7C,oBADqB,MAAM,CACF;IAEzB,6CAA6C;IAC7C,oBADqB,MAAM,CACF;IAEzB,yDAAyD;IACzD,aADW,kBAAkB,CACgB;IAO7C;;;;OAIG;IACH,eAHW,kBAAkB,SAClB,MAAM,QAKhB;IAED,gFAAgF;IAChF,cAQC;IAED,oGAAoG;IACpG,iBAMC;IAED,gBAAgB;IAChB,YASC;IAED,mGAAmG;IACnG,cAKC;IAED,gBAAgB;IAChB,0BAKC;;CACJ;wBAnFuB,kCAAkC;mBADvC,0CAA0C;mCAE1B,yBAAyB"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import Signal from "../../../../core/events/signal/Signal.js";
|
|
2
|
+
import { Vector1 } from "../../../../core/geom/Vector1.js";
|
|
3
|
+
import { XRInputValueSource } from "./XRInputValueSource.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Observable amount of a select/squeeze action, in [0, 1]. Read x and subscribe to onChanged as with
|
|
7
|
+
* any Vector1. The device owns mutation. Scalar changes never manufacture an action outcome.
|
|
8
|
+
*
|
|
9
|
+
* Completion/cancellation describe a browser interaction, independently of the amount. There is no
|
|
10
|
+
* public up/down state or inferred threshold. The private lifecycle only pairs native events so an
|
|
11
|
+
* interrupted interaction is cancelled once and an already completed one is never cancelled.
|
|
12
|
+
*/
|
|
13
|
+
export class XRInputAction extends Vector1 {
|
|
14
|
+
/** @readonly @type {Signal} No arguments. */
|
|
15
|
+
completed = new Signal();
|
|
16
|
+
|
|
17
|
+
/** @readonly @type {Signal} No arguments. */
|
|
18
|
+
cancelled = new Signal();
|
|
19
|
+
|
|
20
|
+
/** @type {XRInputValueSource} Do not modify directly. */
|
|
21
|
+
valueSource = XRInputValueSource.Unavailable;
|
|
22
|
+
|
|
23
|
+
/** 0: idle, 1: awaiting outcome, 2: completed, awaiting native end. */
|
|
24
|
+
#interaction = 0;
|
|
25
|
+
|
|
26
|
+
#cancelled = false;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @internal
|
|
30
|
+
* @param {XRInputValueSource} source
|
|
31
|
+
* @param {number} value
|
|
32
|
+
*/
|
|
33
|
+
update(source, value) {
|
|
34
|
+
this.valueSource = source;
|
|
35
|
+
this.set(source === XRInputValueSource.Gamepad ? value : source === XRInputValueSource.Action && this.#interaction !== 0 ? 1 : 0);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** @internal Called only for a native start, never inferred from the amount. */
|
|
39
|
+
begin() {
|
|
40
|
+
if (this.#interaction !== 0) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
this.#interaction = 1;
|
|
44
|
+
if (this.valueSource === XRInputValueSource.Action) {
|
|
45
|
+
this.set(1);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** @internal A completion without an observed start is not replayed after a rebind/interruption. */
|
|
50
|
+
complete() {
|
|
51
|
+
if (this.#interaction !== 1) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
this.#interaction = 2;
|
|
55
|
+
this.completed.send0();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** @internal */
|
|
59
|
+
end() {
|
|
60
|
+
const cancelled = this.#interaction === 1;
|
|
61
|
+
this.#interaction = 0;
|
|
62
|
+
if (this.valueSource === XRInputValueSource.Action) {
|
|
63
|
+
this.set(0);
|
|
64
|
+
}
|
|
65
|
+
if (cancelled) {
|
|
66
|
+
this.cancelled.send0();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** @internal Stage cancellation so the whole handle can become neutral before its notification. */
|
|
71
|
+
reset() {
|
|
72
|
+
this.#cancelled = this.#cancelled || this.#interaction === 1;
|
|
73
|
+
this.#interaction = 0;
|
|
74
|
+
this.valueSource = XRInputValueSource.Unavailable;
|
|
75
|
+
this.set(0);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** @internal */
|
|
79
|
+
flushCancellation() {
|
|
80
|
+
if (this.#cancelled) {
|
|
81
|
+
this.#cancelled = false;
|
|
82
|
+
this.cancelled.send0();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One raw GamepadButton: its scalar amount and the two binary facts reported by the browser.
|
|
3
|
+
* pressed is not inferred from x; a partially depressed trigger need not be pressed.
|
|
4
|
+
* The device owns mutation. Switches and onChanged keep their identity across source replacement.
|
|
5
|
+
*/
|
|
6
|
+
export class XRInputButton extends Vector1 {
|
|
7
|
+
/** @readonly */
|
|
8
|
+
readonly pressed: InputDeviceSwitch;
|
|
9
|
+
/** @readonly */
|
|
10
|
+
readonly touched: InputDeviceSwitch;
|
|
11
|
+
/**
|
|
12
|
+
* Stage binary state while updating the scalar. All numeric channels and poses are sampled before
|
|
13
|
+
* the device calls flushSwitches, so an input-map action can read the corresponding amount.
|
|
14
|
+
* @internal
|
|
15
|
+
* @param {{value: number, pressed: boolean, touched: boolean}|undefined} button
|
|
16
|
+
*/
|
|
17
|
+
update(button: {
|
|
18
|
+
value: number;
|
|
19
|
+
pressed: boolean;
|
|
20
|
+
touched: boolean;
|
|
21
|
+
} | undefined): void;
|
|
22
|
+
/** @internal */
|
|
23
|
+
flushSwitches(): void;
|
|
24
|
+
#private;
|
|
25
|
+
}
|
|
26
|
+
import { Vector1 } from "../../../../core/geom/Vector1.js";
|
|
27
|
+
import { InputDeviceSwitch } from "../InputDeviceSwitch.js";
|
|
28
|
+
//# sourceMappingURL=XRInputButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"XRInputButton.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/input/devices/xr/XRInputButton.js"],"names":[],"mappings":"AAGA;;;;GAIG;AACH;IACI,gBAAgB;IAChB,oCAAkC;IAClC,gBAAgB;IAChB,oCAAkC;IAKlC;;;;;OAKG;IACH,eAFW;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAC,GAAC,SAAS,QAMvE;IAED,gBAAgB;IAChB,sBAWC;;CACJ;wBA1CuB,kCAAkC;kCACxB,yBAAyB"}
|