All files / src/components/VirtualWalkthrough xr-face-buttons.ts

100% Statements 15/15
100% Branches 6/6
100% Functions 5/5
100% Lines 14/14

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39      3x     3x   3x 18x   23x       3x 14x     3x 4x             2x       8x 8x 8x   8x      
import { XrInputSource } from 'playcanvas';
 
/** xr-standard gamepad button indices for the face buttons: A/X (4) and B/Y (5). */
const FACE_BUTTON_INDICES = [4, 5];
 
/** xr-standard gamepad button indices for the secondary face button: B on the right hand, Y on the left. */
const SECONDARY_FACE_BUTTON_INDICES = [5];
 
const anyButtonPressed = (inputSource: XrInputSource, indices: number[]): boolean => {
  const buttons = inputSource.gamepad?.buttons;
 
  return buttons ? indices.some((index) => buttons[index]?.pressed === true) : false;
};
 
/** True while either face button is held. False for hand-tracked sources, which have no gamepad. */
export const faceButtonPressed = (inputSource: XrInputSource): boolean =>
  anyButtonPressed(inputSource, FACE_BUTTON_INDICES);
 
/** True while B or Y is held, regardless of which hand holds the controller. */
export const secondaryFaceButtonPressed = (inputSource: XrInputSource): boolean =>
  anyButtonPressed(inputSource, SECONDARY_FACE_BUTTON_INDICES);
 
/**
 * Edge-detects face-button presses per input source so one press fires once. Callers must poll every
 * frame for every source they care about; a press and release between polls is missed.
 */
export class FaceButtonPressTracker {
  private _down = new WeakMap<XrInputSource, boolean>();
 
  /** True only on the poll where a face button goes from released to pressed. */
  justPressed(inputSource: XrInputSource): boolean {
    const pressed = faceButtonPressed(inputSource);
    const wasPressed = this._down.get(inputSource) ?? false;
    this._down.set(inputSource, pressed);
 
    return pressed && !wasPressed;
  }
}