@ferret/input
Actions over the console's buttons and sticks, keyboard and mouse, touch and gamepads; games bind actions, not devices.
Classes
InputService class
class InputService implements ServiceActions over every input device. Games bind actions, not devices. The active kind follows what the player uses last (a gamepad plugged in, a keyboard used on a tablet) and prompts show the matching button.
readonly name: "input" | |
kind: InputKind | |
enabled: boolean | false = all actions read as released/zero (a menu is open, a cutscene plays). Devices are still tracked. |
readonly opts: InputOptions | |
dominantHand: XrHand | which hand xrButton without hand means |
canvas?: HTMLElement | the page's canvas, once attached; Pointer Lock is requested on it |
constructor(opts: InputOptions) | |
init(world: World) | |
down(action: string) | |
pressed(action: string) | |
released(action: string) | |
axis(action: string): { x: number; y: number } | |
lookDelta() | Look delta accumulated during the last step, in radians (x = yaw, y = pitch). Consumed by the step. |
prompt(action: string): string | The label of the binding in the active kind ("A", "E", "Tap"...), for UI prompts. |
setKind(kind: InputKind) | |
setKey(code: string, down: boolean) | |
addLook(dx: number, dy: number) | |
setPad(buttons: Iterable<number>, axes: number[]) | |
setTouchStick(which: 'left' | 'right', x: number, y: number) | |
setTouchButton(name: string, down: boolean) | |
setXrActive(on: boolean) | The xr kind while in a session; the previous kind comes back on leaving. |
setXrButton(hand: XrHand, b: XrButton | 'pinch', down: boolean) | |
setXrStick(hand: XrHand, x: number, y: number) | |
setXrPose(who: 'head' | XrHand, p: XrPose) | Poses sampled for the rendered frame (renderPose); the fixed step copies them for gameplay (pose). |
pose(who: 'head' | XrHand): XrPose | undefined | |
renderPose(who: 'head' | XrHand): XrPose | undefined | |
inject(action: string, v: { x?: number; y?: number; down?: boolean } | null) | Tests and scripted input: force an action regardless of devices. |
fixedUpdate() | Called before the components' fixed update, at the fixed rate. |
sample() | Compute the actions from the raw state. Called each fixed step; also callable directly in tests. |
attach(canvas: HTMLElement, opts: { pointerLock?: boolean } = {}) | Listen to the page. On OS Beroun the cursor, A and B arrive as keys; Pointer Lock is only used in desktop browsers. |
update() | Poll the Gamepad API; call once per frame (the Ferret loop does it through update). |
dispose() |
packages/input/src/input.ts:46
TouchControls class
class TouchControlsOn-screen controls for phones and tablets, generated from the game's touch bindings: a virtual stick on the left, look by dragging on the right half, and a round button per touchButton binding. Sized to the screen.
readonly root: HTMLDivElement | |
constructor(private input: InputService, parent: HTMLElement = document.body) | |
relayout() | |
dispose() |
packages/input/src/touch.ts:10
Interfaces
InputOptions interface
interface InputOptionsactions: Record<string, ActionDef> | |
bindings: BindingMap | |
defaultKind?: InputKind | Kind used until the player touches something. OS Beroun: 'console', phones: 'touch', else 'keyboard'. |
packages/input/src/input.ts:29
XrPose interface
interface XrPosea hand or the head in the room: metres, quaternion, m/s, rad/s
position: [number, number, number] | |
rotation: [number, number, number, number] | |
linear: [number, number, number] | |
angular: [number, number, number] | |
tracked: boolean |
packages/input/src/input.ts:9
Types
ActionDef type
type ActionDef = { kind: 'button' } | { kind: 'axis2' }packages/input/src/input.ts:11
Binding type
type Binding = | { key: string; label?: string } // KeyboardEvent.code (or .key for console) | { mouse: 0 | 1 | 2; label?: string } // a mouse button: 0 left, 1 middle, 2 right | { axisKeys: [left: string, right: string, down: string, up: string]; label?: string } // x = right - left, y = up - down | { pad: number; label?: string } // Gamepad button index | { padAxes: [x: number, y: number]; deadzone?: number } | { mouseLook: true; sensitivity?: number } // pointer-locked (or dragged) mouse -> axis2 in radians | { touchStick: 'left' | 'right' } | { touchButton: string; label?: string } | { xrButton: XrButton; hand?: XrHand; label?: string } // a controller button; no hand = the dominant hand | { xrStick: XrHand; deadzone?: number } // a controller thumbstick -> axis2 | { xrPinch: XrHand; label?: string }One way to produce an action. Which button does what is each game's call: Ferret ships no mapping.
packages/input/src/input.ts:14
BindingMap type
type BindingMap = Partial<Record<InputKind, Record<string, Binding[]>>>packages/input/src/input.ts:27
InputKind type
type InputKind = 'console' | 'keyboard' | 'gamepad' | 'touch' | 'xr'Where the player's commands come from. console = OS Beroun's cursor, A and B (they reach the page as arrow keys, Enter and Escape).
packages/input/src/input.ts:4
XrButton type
type XrButton = 'trigger' | 'squeeze' | 'thumbstick' | 'a' | 'b' | 'x' | 'y' | 'menu'packages/input/src/input.ts:6
XrHand type
type XrHand = 'left' | 'right'packages/input/src/input.ts:7