Skip to content

Input

InputManager provides a unified binding system across keyboard, mouse, gamepad, and touch. Bind multiple physical inputs to a single action, then query by action name.

Quick Start

typescript
import { InputManager, GamepadButtons, GamepadAxes } from "quantum-forge/input";

const input = new InputManager({ logger });

// Bind multiple sources to one action
input.bind("jump",
  { type: "key", code: "Space" },
  { type: "gamepad-button", index: GamepadButtons.A },
);

input.bind("move-up",
  { type: "key", code: "KeyW" },
  { type: "gamepad-axis", index: GamepadAxes.LeftStickY, direction: -1 },
);

// Game loop
function update(dt: number) {
  input.poll(); // MUST call every frame

  if (input.isActionDown("move-up")) { /* held */ }
  if (input.isActionJustPressed("jump")) { /* edge detection */ }

  const speed = input.getActionValue("move-up") * MAX_SPEED; // 0-1 analog
}

Source Types

TypeExampleValues
key{ type: "key", code: "Space" }0 or 1
mouse-button{ type: "mouse-button", button: 0 }0 or 1
gamepad-button{ type: "gamepad-button", index: GamepadButtons.A }0–1 (pressure)
gamepad-axis{ type: "gamepad-axis", index: GamepadAxes.LeftStickY, direction: -1 }0–1 (after dead zone)
touch-zone{ type: "touch-zone", zone: "left-half" }0 or 1
touch-joystick{ type: "touch-joystick", joystick: "move", axis: "y", direction: -1 }0–1
touch-gesture{ type: "touch-gesture", gesture: "tap" }0 or 1 (one frame)

Event Handlers

For discrete actions (menu toggle, ability activation), use .on():

typescript
input.on("pause", () => togglePause());
input.on("ability", () => engine.getHelpers().useAbility());

// Returns unsubscribe function
const unsub = input.on("pause", handler);
unsub();

Active Device Detection

typescript
const device = input.getActiveDevice(); // "keyboard" | "mouse" | "touch" | "gamepad"
const prompt = device === "gamepad" ? "Press A" : "Press Space";

Touch Controls

Touch Zones

Register named zones with normalized 0-1 coordinates:

typescript
input.addTouchZone({ name: "left-half", x: 0, y: 0, w: 0.5, h: 1 });
input.bind("move-left", { type: "touch-zone", zone: "left-half" });

Virtual Joystick

typescript
input.addJoystick({
  name: "move",
  zone: { name: "left-half", x: 0, y: 0, w: 0.5, h: 1 },
  radius: 60,      // max drag px
  deadZone: 0.15,  // 0-1
  dynamic: true,    // center on touch-down
});

input.bind("move-up",
  { type: "touch-joystick", joystick: "move", axis: "y", direction: -1 },
);

// Raw state
const joy = input.getJoystickState("move");
if (joy?.active) {
  player.x += joy.x * joy.magnitude * speed * dt;
}

Gestures

typescript
input.bindGesture("tap", "shoot");
input.bindGesture("swipe-up", "jump");

// Gesture types: tap, double-tap, long-press,
// swipe-up, swipe-down, swipe-left, swipe-right, swipe,
// pinch, rotate

Gamepad Constants

typescript
import { GamepadButtons, GamepadAxes } from "quantum-forge/input";

// GamepadButtons: A, B, X, Y, LB, RB, LT, RT, Back, Start,
//                 LeftStick, RightStick, DpadUp, DpadDown, DpadLeft, DpadRight

// GamepadAxes: LeftStickX, LeftStickY, RightStickX, RightStickY

Local Multiplayer

typescript
import { LocalMultiplayerManager } from "quantum-forge/input";

const mp = new LocalMultiplayerManager({ players: 2, logger });

// Bind per-player keys
mp.getPlayer(0)!.bindKey("KeyW", "move-up");
mp.getPlayer(1)!.bindKey("ArrowUp", "move-up");

// Bind gamepad to all players (auto-assigned)
mp.bindAll("action", { type: "gamepad-button", index: GamepadButtons.A });

// Game loop
mp.pollAll();
for (const slot of mp.getPlayers()) {
  if (slot.input.isActionDown("move-up")) { /* move player slot.index */ }
}

mp.destroy(); // cleanup

Cleanup

Always call input.destroy() when the game stops.

Powered by Quantum Forge