UNPKG

@pmndrs/xr

Version:
96 lines (95 loc) 4.4 kB
import { XRControllerLayoutLoader, createXRControllerState, } from './controller/index.js'; import { createXRHandState, } from './hand/index.js'; export function isXRInputSourceState(val) { return val != null && typeof val === 'object' && 'inputSource' in val; } function setupEvents(session, events) { const listener = (e) => events.push(e); session.addEventListener('selectstart', listener); session.addEventListener('selectend', listener); session.addEventListener('select', listener); session.addEventListener('squeeze', listener); session.addEventListener('squeezestart', listener); session.addEventListener('squeezeend', listener); return () => { session.removeEventListener('selectstart', listener); session.removeEventListener('selectend', listener); session.removeEventListener('select', listener); session.removeEventListener('squeeze', listener); session.removeEventListener('squeezestart', listener); session.removeEventListener('squeezeend', listener); }; } let idCounter = 0; export function createSyncXRInputSourceStates(addController, options) { const cleanupMap = new Map(); const controllerLayoutLoader = new XRControllerLayoutLoader(options); const idMap = new Map(); return (session, current, changes) => { if (changes === 'remove-all') { for (const cleanup of cleanupMap.values()) { cleanup(); } return current; } const target = [...current]; for (const { added, isPrimary, removed } of changes) { if (removed != null) { for (const inputSource of removed) { const index = target.findIndex(({ inputSource: is, isPrimary: ip }) => ip === isPrimary && is === inputSource); if (index === -1) { continue; } target.splice(index, 1); cleanupMap.get(inputSource)?.(); cleanupMap.delete(inputSource); } } if (added == null) { continue; } for (const inputSource of added) { const events = []; let cleanup = setupEvents(session, events); const key = `${inputSource.handedness}-${inputSource.hand ? 'hand' : 'nohand'}-${inputSource.targetRayMode}-${inputSource.profiles.join(',')}`; let id; if ((id = idMap.get(key)) == null) { idMap.set(key, (id = `${idCounter++}`)); } if (inputSource.hand != null) { target.push(createXRHandState(id, inputSource, options, events, isPrimary)); } else { switch (inputSource.targetRayMode) { case 'gaze': target.push({ id, isPrimary, type: 'gaze', inputSource, events }); break; case 'screen': target.push({ id, isPrimary, type: 'screenInput', inputSource, events }); break; case 'transient-pointer': target.push({ id, isPrimary, type: 'transientPointer', inputSource, events }); break; case 'tracked-pointer': let aborted = false; const cleanupEvents = cleanup; cleanup = () => { cleanupEvents(); aborted = true; }; const stateResult = createXRControllerState(id, inputSource, controllerLayoutLoader, events, isPrimary); if (stateResult instanceof Promise) { stateResult.then((state) => !aborted && addController(state)).catch(console.error); } else { target.push(stateResult); } break; } } cleanupMap.set(inputSource, cleanup); } } return target; }; }