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
| Type | Example | Values |
|---|---|---|
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, rotateGamepad 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, RightStickYLocal 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(); // cleanupCleanup
Always call input.destroy() when the game stops.