@yagejs/input 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/InputPlugin.ts","../src/InputManager.ts","../src/types.ts","../src/InputPollSystem.ts","../src/InputClearSystem.ts","../src/InputDebugContributor.ts","../src/keyDisplayNames.ts"],"sourcesContent":["export { InputPlugin } from \"./InputPlugin.js\";\nexport { InputManager } from \"./InputManager.js\";\nexport { getKeyDisplayName } from \"./keyDisplayNames.js\";\nexport { InputManagerKey } from \"./types.js\";\nexport type {\n InputConfig,\n ActionMapDefinition,\n InputConflictPolicy,\n RebindOptions,\n RebindResult,\n CameraLike,\n RendererLike,\n} from \"./types.js\";\n","import type { EngineContext, Plugin, SystemScheduler } from \"@yagejs/core\";\nimport { DebugRegistryKey } from \"@yagejs/debug/api\";\nimport { InputManager } from \"./InputManager.js\";\nimport { InputManagerKey, type InputConfig } from \"./types.js\";\nimport { InputPollSystem } from \"./InputPollSystem.js\";\nimport { InputClearSystem } from \"./InputClearSystem.js\";\nimport { InputDebugContributor } from \"./InputDebugContributor.js\";\n\nconst MOUSE_BUTTON_MAP: Record<number, string> = {\n 0: \"MouseLeft\",\n 1: \"MouseMiddle\",\n 2: \"MouseRight\",\n};\n\n/** Input plugin — wires keyboard and pointer listeners, registers InputManager. */\nexport class InputPlugin implements Plugin {\n readonly name = \"input\";\n readonly version = \"2.0.0\";\n\n private readonly config: InputConfig;\n private manager!: InputManager;\n private context!: EngineContext;\n private cleanupFns: Array<() => void> = [];\n\n constructor(config?: InputConfig) {\n this.config = config ?? {};\n }\n\n install(context: EngineContext): void {\n this.context = context;\n this.manager = new InputManager();\n\n if (this.config.actions) {\n this.manager.setActionMap(this.config.actions);\n }\n\n if (this.config.groups) {\n this.manager.setGroups(this.config.groups);\n }\n\n if (this.config.cameraKey) {\n const camera = context.tryResolve(this.config.cameraKey);\n if (camera) {\n this.manager._setCamera(camera);\n }\n }\n\n const renderer = this.config.rendererKey\n ? context.tryResolve(this.config.rendererKey)\n : undefined;\n const pointerTarget: EventTarget =\n this.config.target ?? renderer?.canvas ?? document;\n\n // Element used to convert clientX/clientY to element-relative coordinates.\n // Falls back to null if the target is `document` or another non-element.\n const pointerElement: Element | null =\n this.config.target ??\n renderer?.canvas ??\n null;\n\n const preventSet = new Set(this.config.preventDefaultKeys ?? []);\n\n // Keyboard listeners\n const onKeyDown = (e: Event): void => {\n const ke = e as KeyboardEvent;\n if (ke.repeat) return;\n if (preventSet.has(ke.code)) ke.preventDefault();\n this.manager._onKeyDown(ke.code);\n };\n const onKeyUp = (e: Event): void => {\n const ke = e as KeyboardEvent;\n if (preventSet.has(ke.code)) ke.preventDefault();\n this.manager._onKeyUp(ke.code);\n };\n window.addEventListener(\"keydown\", onKeyDown);\n window.addEventListener(\"keyup\", onKeyUp);\n this.cleanupFns.push(\n () => window.removeEventListener(\"keydown\", onKeyDown),\n () => window.removeEventListener(\"keyup\", onKeyUp),\n );\n\n // Pointer listeners — pointerdown on target, pointerup/move/cancel on window\n // so releases outside the target element are still captured\n const onPointerMove = (e: Event): void => {\n const pe = e as PointerEvent;\n if (pointerElement) {\n const rect = pointerElement.getBoundingClientRect();\n this.manager._onPointerMove(pe.clientX - rect.left, pe.clientY - rect.top);\n } else {\n this.manager._onPointerMove(pe.clientX, pe.clientY);\n }\n };\n const onPointerDown = (e: Event): void => {\n const pe = e as PointerEvent;\n this.manager._onPointerDown();\n const mouseKey = MOUSE_BUTTON_MAP[pe.button];\n if (mouseKey) this.manager._onKeyDown(mouseKey);\n };\n const onPointerUp = (e: Event): void => {\n const pe = e as PointerEvent;\n this.manager._onPointerUp();\n const mouseKey = MOUSE_BUTTON_MAP[pe.button];\n if (mouseKey) this.manager._onKeyUp(mouseKey);\n };\n const onPointerCancel = (): void => {\n this.manager._onPointerUp();\n this.manager._onKeyUp(\"MouseLeft\");\n this.manager._onKeyUp(\"MouseMiddle\");\n this.manager._onKeyUp(\"MouseRight\");\n };\n\n pointerTarget.addEventListener(\"pointerdown\", onPointerDown);\n window.addEventListener(\"pointermove\", onPointerMove);\n window.addEventListener(\"pointerup\", onPointerUp);\n window.addEventListener(\"pointercancel\", onPointerCancel);\n this.cleanupFns.push(\n () => pointerTarget.removeEventListener(\"pointerdown\", onPointerDown),\n () => window.removeEventListener(\"pointermove\", onPointerMove),\n () => window.removeEventListener(\"pointerup\", onPointerUp),\n () => window.removeEventListener(\"pointercancel\", onPointerCancel),\n );\n\n context.register(InputManagerKey, this.manager);\n }\n\n registerSystems(scheduler: SystemScheduler): void {\n scheduler.add(new InputPollSystem());\n scheduler.add(new InputClearSystem());\n }\n\n onStart(): void {\n const registry = this.context.tryResolve(DebugRegistryKey);\n registry?.register(new InputDebugContributor(this.manager));\n }\n\n onDestroy(): void {\n for (const cleanup of this.cleanupFns) {\n cleanup();\n }\n this.cleanupFns.length = 0;\n }\n}\n","import { Vec2 } from \"@yagejs/core\";\nimport type {\n ActionMapDefinition,\n CameraLike,\n RebindOptions,\n RebindResult,\n} from \"./types.js\";\n\n/** Central input state manager. Resolved via DI with InputManagerKey. */\nexport class InputManager {\n private pressedKeys = new Set<string>();\n private justPressedKeys = new Set<string>();\n private justReleasedKeys = new Set<string>();\n private holdStart = new Map<string, number>();\n private actionMap = new Map<string, string[]>();\n private defaultBindings = new Map<string, string[]>();\n private groups = new Map<string, Set<string>>();\n private actionGroups = new Map<string, Set<string>>();\n private disabledGroups = new Set<string>();\n private pointerScreenPos = Vec2.ZERO;\n private pointerDownState = false;\n private camera: CameraLike | null = null;\n private elapsedMs = 0;\n private listenResolve: ((key: string | null) => void) | null = null;\n\n // -- Action-based queries --\n\n /** Whether any key mapped to this action is currently held. */\n isPressed(action: string): boolean {\n if (!this.isActionEnabled(action)) return false;\n return this.anyKeyInSet(action, this.pressedKeys);\n }\n\n /** Whether any key mapped to this action was pressed this frame. */\n isJustPressed(action: string): boolean {\n if (!this.isActionEnabled(action)) return false;\n return this.anyKeyInSet(action, this.justPressedKeys);\n }\n\n /** Whether any key mapped to this action was released this frame. */\n isJustReleased(action: string): boolean {\n if (!this.isActionEnabled(action)) return false;\n return this.anyKeyInSet(action, this.justReleasedKeys);\n }\n\n /** Returns true if any key bound to the action exists in the given set. */\n private anyKeyInSet(action: string, set: Set<string>): boolean {\n const keys = this.actionMap.get(action);\n if (!keys) return false;\n for (const key of keys) {\n if (set.has(key)) return true;\n }\n return false;\n }\n\n /** Milliseconds the action has been held. Returns 0 if not held. */\n getHoldDuration(action: string): number {\n if (!this.isActionEnabled(action)) return 0;\n const keys = this.actionMap.get(action);\n if (!keys) return 0;\n let maxDuration = 0;\n for (const key of keys) {\n const start = this.holdStart.get(key);\n if (start !== undefined) {\n maxDuration = Math.max(maxDuration, this.elapsedMs - start);\n }\n }\n return maxDuration;\n }\n\n /** Whether the action has been held for at least `minTime` ms. */\n isHeldFor(action: string, minTime: number): boolean {\n return this.getHoldDuration(action) >= minTime;\n }\n\n // -- Axis helpers --\n\n /** Returns -1, 0, or 1 based on negative/positive action states. */\n getAxis(negative: string, positive: string): number {\n const neg = this.isPressed(negative) ? 1 : 0;\n const pos = this.isPressed(positive) ? 1 : 0;\n return pos - neg;\n }\n\n /** Returns a Vec2 from four directional actions. Not normalized. */\n getVector(\n left: string,\n right: string,\n up: string,\n down: string,\n ): Vec2 {\n const x = this.getAxis(left, right);\n const y = this.getAxis(up, down);\n return new Vec2(x, y);\n }\n\n // -- Pointer --\n\n /** Pointer position in world coordinates (via Camera), or screen coords if no camera. */\n getPointerPosition(): Vec2 {\n if (this.camera) {\n const w = this.camera.screenToWorld(\n this.pointerScreenPos.x,\n this.pointerScreenPos.y,\n );\n return new Vec2(w.x, w.y);\n }\n return this.pointerScreenPos;\n }\n\n /** Raw pointer position in screen coordinates. */\n getPointerScreenPosition(): Vec2 {\n return this.pointerScreenPos;\n }\n\n /** Whether any pointer button is currently held. */\n isPointerDown(): boolean {\n return this.pointerDownState;\n }\n\n // -- Runtime action map management --\n\n /** Replace the entire action map and store it as the default for {@link resetBindings}. */\n setActionMap(actions: ActionMapDefinition): void {\n this.actionMap.clear();\n this.defaultBindings.clear();\n for (const [action, keys] of Object.entries(actions)) {\n this.actionMap.set(action, [...keys]);\n this.defaultBindings.set(action, [...keys]);\n }\n }\n\n /** Add a key binding to an action. Creates the action if it doesn't exist. */\n bindKey(action: string, key: string): void {\n let keys = this.actionMap.get(action);\n if (!keys) {\n keys = [];\n this.actionMap.set(action, keys);\n }\n if (!keys.includes(key)) {\n keys.push(key);\n }\n }\n\n /** Remove a key binding from an action. */\n unbindKey(action: string, key: string): void {\n const keys = this.actionMap.get(action);\n if (!keys) return;\n const idx = keys.indexOf(key);\n if (idx !== -1) keys.splice(idx, 1);\n }\n\n // -- Binding queries --\n\n /** Returns the current key bindings for an action, or an empty array if unmapped. */\n getBindings(action: string): readonly string[] {\n return this.actionMap.get(action) ?? [];\n }\n\n /** Returns all action names that have the given key bound. */\n getActionsForKey(key: string): string[] {\n const result: string[] = [];\n for (const [action, keys] of this.actionMap) {\n if (keys.includes(key)) result.push(action);\n }\n return result;\n }\n\n // -- Rebinding --\n\n /**\n * Rebind a key to an action with optional conflict detection.\n * Conflicts are only detected between actions sharing at least one group.\n */\n rebind(action: string, key: string, opts?: RebindOptions): RebindResult {\n const conflict = opts?.conflict ?? \"reject\";\n const slot = opts?.slot;\n\n const conflictAction = this.findConflictInGroups(action, key);\n\n if (conflictAction && conflict === \"reject\") {\n return { ok: false, conflict: { action: conflictAction, key } };\n }\n\n if (conflictAction && conflict === \"replace\") {\n this.unbindKey(conflictAction, key);\n }\n\n let keys = this.actionMap.get(action);\n if (!keys) {\n keys = [];\n this.actionMap.set(action, keys);\n }\n\n // Remove existing occurrence to avoid duplicates, adjusting slot for the shift\n const existingIdx = keys.indexOf(key);\n let targetSlot = slot;\n if (targetSlot !== undefined && existingIdx !== -1 && existingIdx !== targetSlot) {\n keys.splice(existingIdx, 1);\n if (targetSlot > existingIdx) targetSlot--;\n }\n\n if (targetSlot !== undefined && targetSlot < keys.length) {\n keys[targetSlot] = key;\n } else if (!keys.includes(key)) {\n keys.push(key);\n }\n\n return { ok: true };\n }\n\n /**\n * Finds the first action that uses the given key AND shares at least one\n * group with the target action. Ungrouped actions never conflict.\n */\n private findConflictInGroups(action: string, key: string): string | null {\n const myGroups = this.actionGroups.get(action);\n if (!myGroups || myGroups.size === 0) return null;\n\n for (const [otherAction, otherKeys] of this.actionMap) {\n if (otherAction === action) continue;\n if (!otherKeys.includes(key)) continue;\n\n const otherGroups = this.actionGroups.get(otherAction);\n if (!otherGroups) continue;\n\n for (const g of myGroups) {\n if (otherGroups.has(g)) return otherAction;\n }\n }\n return null;\n }\n\n // -- Binding persistence --\n\n /** Reset bindings to defaults. If an action name is provided, only reset that action. */\n resetBindings(action?: string): void {\n if (action !== undefined) {\n const defaults = this.defaultBindings.get(action);\n if (defaults) {\n this.actionMap.set(action, [...defaults]);\n }\n } else {\n this.actionMap.clear();\n for (const [a, keys] of this.defaultBindings) {\n this.actionMap.set(a, [...keys]);\n }\n }\n }\n\n /** Export the current bindings as a plain object for serialization. */\n exportBindings(): ActionMapDefinition {\n const result: ActionMapDefinition = {};\n for (const [action, keys] of this.actionMap) {\n result[action] = [...keys];\n }\n return result;\n }\n\n /** Load bindings from a plain object. Resets to defaults first, then overlays the provided map. */\n loadBindings(map: ActionMapDefinition): void {\n this.resetBindings();\n for (const [action, keys] of Object.entries(map)) {\n this.actionMap.set(action, [...keys]);\n }\n }\n\n // -- Group management --\n\n /** Configure input groups. Group name -> array of action names. */\n setGroups(groups: Record<string, string[]>): void {\n this.groups.clear();\n this.actionGroups.clear();\n for (const [name, actions] of Object.entries(groups)) {\n this.groups.set(name, new Set(actions));\n for (const action of actions) {\n let set = this.actionGroups.get(action);\n if (!set) {\n set = new Set();\n this.actionGroups.set(action, set);\n }\n set.add(name);\n }\n }\n }\n\n /** Enable a group by name. */\n enableGroup(name: string): void {\n this.disabledGroups.delete(name);\n }\n\n /** Disable a group by name. Actions only in disabled groups become inactive. */\n disableGroup(name: string): void {\n this.disabledGroups.add(name);\n }\n\n /** Set exactly these groups as active; all others are disabled. */\n setActiveGroups(names: string[]): void {\n this.disabledGroups.clear();\n for (const group of this.groups.keys()) {\n if (!names.includes(group)) {\n this.disabledGroups.add(group);\n }\n }\n }\n\n /** Whether a group is currently enabled. Returns true for unknown group names. */\n isGroupEnabled(name: string): boolean {\n return !this.disabledGroups.has(name);\n }\n\n /** Get all configured group names. */\n getGroups(): string[] {\n return Array.from(this.groups.keys());\n }\n\n /** Get the action names belonging to a group. Returns empty array for unknown groups. */\n getGroupActions(name: string): readonly string[] {\n const set = this.groups.get(name);\n return set ? Array.from(set) : [];\n }\n\n /** Returns true if the action is ungrouped or any of its groups is enabled. */\n private isActionEnabled(action: string): boolean {\n const groupSet = this.actionGroups.get(action);\n if (!groupSet || groupSet.size === 0) return true;\n for (const group of groupSet) {\n if (!this.disabledGroups.has(group)) return true;\n }\n return false;\n }\n\n // -- Key listening --\n\n /** Returns a promise that resolves with the next key code pressed. Intercepts the key. */\n listenForNextKey(): Promise<string | null> {\n this.cancelListen();\n return new Promise<string | null>((resolve) => {\n this.listenResolve = resolve;\n });\n }\n\n /** Cancel an active {@link listenForNextKey}. Resolves the pending promise with `null`. */\n cancelListen(): void {\n if (this.listenResolve) {\n const resolve = this.listenResolve;\n this.listenResolve = null;\n resolve(null);\n }\n }\n\n // -- Internal methods (called by InputPlugin / Systems) --\n\n /** @internal */\n _onKeyDown(code: string): void {\n if (this.listenResolve) {\n const resolve = this.listenResolve;\n this.listenResolve = null;\n resolve(code);\n return;\n }\n if (!this.pressedKeys.has(code)) {\n this.pressedKeys.add(code);\n this.justPressedKeys.add(code);\n this.holdStart.set(code, this.elapsedMs);\n }\n }\n\n /** @internal */\n _onKeyUp(code: string): void {\n if (this.pressedKeys.has(code)) {\n this.pressedKeys.delete(code);\n this.justReleasedKeys.add(code);\n this.holdStart.delete(code);\n }\n }\n\n /** @internal */\n _onPointerMove(screenX: number, screenY: number): void {\n this.pointerScreenPos = new Vec2(screenX, screenY);\n }\n\n /** @internal */\n _onPointerDown(): void {\n this.pointerDownState = true;\n }\n\n /** @internal */\n _onPointerUp(): void {\n this.pointerDownState = false;\n }\n\n /** @internal Clear per-frame justPressed/justReleased flags. */\n _clearFrameState(): void {\n this.justPressedKeys.clear();\n this.justReleasedKeys.clear();\n }\n\n /** @internal Set camera for pointer world-coord conversion. */\n _setCamera(camera: CameraLike): void {\n this.camera = camera;\n }\n\n /** Get all configured action names. */\n getActionNames(): string[] {\n return Array.from(this.actionMap.keys());\n }\n\n /** @internal Advance the elapsed game-time clock. Called by InputPollSystem. */\n _advanceTime(dtMs: number): void {\n this.elapsedMs += dtMs;\n }\n}\n","import { ServiceKey } from \"@yagejs/core\";\n\n/** Service key for the InputManager. */\nexport const InputManagerKey = new ServiceKey<\n import(\"./InputManager.js\").InputManager\n>(\"inputManager\");\n\n/** Minimal camera surface needed by InputManager for pointer world-coord conversion. */\nexport interface CameraLike {\n screenToWorld(screenX: number, screenY: number): { x: number; y: number };\n}\n\n/** Minimal renderer surface needed by InputPlugin for canvas access. */\nexport interface RendererLike {\n readonly canvas: HTMLCanvasElement;\n}\n\n/** Configuration for the InputPlugin. */\nexport interface InputConfig {\n /** Target element for pointer events (default: canvas from renderer, or document). */\n target?: HTMLElement;\n /** Action map: action name -> array of physical key codes. */\n actions?: ActionMapDefinition;\n /** Input groups: group name -> array of action names belonging to it. */\n groups?: Record<string, string[]>;\n /** Key codes to call preventDefault() on (default: none). */\n preventDefaultKeys?: string[];\n /** Service key for the camera (enables pointer world-coordinate conversion). */\n cameraKey?: ServiceKey<CameraLike>;\n /** Service key for the renderer (used to auto-target pointer events to its canvas). */\n rendererKey?: ServiceKey<RendererLike>;\n}\n\n/** Maps action names to arrays of physical key codes. */\nexport type ActionMapDefinition = Record<string, string[]>;\n\n/** How to handle a conflict when rebinding a key already used by another action in the same group. */\nexport type InputConflictPolicy = \"replace\" | \"keep-both\" | \"reject\";\n\n/** Options for {@link InputManager.rebind}. */\nexport interface RebindOptions {\n /** Index of the binding slot to replace. Appends if the slot does not exist. */\n slot?: number;\n /** How to resolve conflicts with other actions in the same group(s). Default: `\"reject\"`. */\n conflict?: InputConflictPolicy;\n}\n\n/** Result of a {@link InputManager.rebind} call. */\nexport interface RebindResult {\n /** Whether the rebind succeeded. */\n ok: boolean;\n /** Present when `ok` is false due to a conflict with `conflict: \"reject\"`. */\n conflict?: { action: string; key: string };\n}\n","import { System, Phase } from \"@yagejs/core\";\nimport { InputManagerKey } from \"./types.js\";\n\n/**\n * Runs at the start of each frame (EarlyUpdate, priority -100).\n * Advances the input elapsed clock. Gamepad polling will be added here later.\n */\nexport class InputPollSystem extends System {\n readonly phase = Phase.EarlyUpdate;\n readonly priority = -100;\n\n update(dt: number): void {\n this.use(InputManagerKey)._advanceTime(dt);\n }\n}\n","import { System, Phase } from \"@yagejs/core\";\nimport { InputManagerKey } from \"./types.js\";\n\n/**\n * Runs at the end of each frame (EndOfFrame, priority 9000).\n * Clears per-frame justPressed/justReleased flags.\n */\nexport class InputClearSystem extends System {\n readonly phase = Phase.EndOfFrame;\n readonly priority = 9000;\n\n update(): void {\n this.use(InputManagerKey)._clearFrameState();\n }\n}\n","import type {\n DebugContributor,\n WorldDebugApi,\n HudDebugApi,\n} from \"@yagejs/debug/api\";\nimport type { InputManager } from \"./InputManager.js\";\n\nconst CROSSHAIR_SIZE = 10;\nconst CROSSHAIR_COLOR = 0xff00ff;\n\n/** Debug contributor that shows pressed actions and pointer position. */\nexport class InputDebugContributor implements DebugContributor {\n readonly name = \"input\";\n readonly flags = [\"actions\", \"pointer\"] as const;\n\n constructor(private readonly manager: InputManager) {}\n\n drawWorld(api: WorldDebugApi): void {\n if (!api.isFlagEnabled(\"pointer\")) return;\n\n const pos = this.manager.getPointerPosition();\n const g = api.acquireGraphics();\n if (!g) return;\n\n const size = CROSSHAIR_SIZE / api.cameraZoom;\n const lineWidth = 1 / api.cameraZoom;\n g.moveTo(pos.x - size, pos.y)\n .lineTo(pos.x + size, pos.y)\n .moveTo(pos.x, pos.y - size)\n .lineTo(pos.x, pos.y + size)\n .stroke({ width: lineWidth, color: CROSSHAIR_COLOR });\n }\n\n drawHud(api: HudDebugApi): void {\n if (!api.isFlagEnabled(\"actions\")) return;\n\n const pressed = this.manager\n .getActionNames()\n .filter((action) => this.manager.isPressed(action));\n\n const label = pressed.length > 0 ? pressed.join(\", \") : \"(none)\";\n api.addLine(`Input: ${label}`);\n\n const groups = this.manager.getGroups();\n if (groups.length > 0) {\n const disabled = groups.filter((g) => !this.manager.isGroupEnabled(g));\n if (disabled.length > 0) {\n api.addLine(`Disabled groups: ${disabled.join(\", \")}`);\n }\n }\n }\n}\n","const KEY_DISPLAY_NAMES: Record<string, string> = {\n // Letters\n KeyA: \"A\",\n KeyB: \"B\",\n KeyC: \"C\",\n KeyD: \"D\",\n KeyE: \"E\",\n KeyF: \"F\",\n KeyG: \"G\",\n KeyH: \"H\",\n KeyI: \"I\",\n KeyJ: \"J\",\n KeyK: \"K\",\n KeyL: \"L\",\n KeyM: \"M\",\n KeyN: \"N\",\n KeyO: \"O\",\n KeyP: \"P\",\n KeyQ: \"Q\",\n KeyR: \"R\",\n KeyS: \"S\",\n KeyT: \"T\",\n KeyU: \"U\",\n KeyV: \"V\",\n KeyW: \"W\",\n KeyX: \"X\",\n KeyY: \"Y\",\n KeyZ: \"Z\",\n\n // Digits\n Digit0: \"0\",\n Digit1: \"1\",\n Digit2: \"2\",\n Digit3: \"3\",\n Digit4: \"4\",\n Digit5: \"5\",\n Digit6: \"6\",\n Digit7: \"7\",\n Digit8: \"8\",\n Digit9: \"9\",\n\n // Function keys\n F1: \"F1\",\n F2: \"F2\",\n F3: \"F3\",\n F4: \"F4\",\n F5: \"F5\",\n F6: \"F6\",\n F7: \"F7\",\n F8: \"F8\",\n F9: \"F9\",\n F10: \"F10\",\n F11: \"F11\",\n F12: \"F12\",\n\n // Modifiers\n ShiftLeft: \"Left Shift\",\n ShiftRight: \"Right Shift\",\n ControlLeft: \"Left Ctrl\",\n ControlRight: \"Right Ctrl\",\n AltLeft: \"Left Alt\",\n AltRight: \"Right Alt\",\n MetaLeft: \"Left Meta\",\n MetaRight: \"Right Meta\",\n\n // Arrows\n ArrowUp: \"Up\",\n ArrowDown: \"Down\",\n ArrowLeft: \"Left\",\n ArrowRight: \"Right\",\n\n // Common keys\n Space: \"Space\",\n Enter: \"Enter\",\n Escape: \"Esc\",\n Tab: \"Tab\",\n Backspace: \"Backspace\",\n Delete: \"Delete\",\n Insert: \"Insert\",\n Home: \"Home\",\n End: \"End\",\n PageUp: \"Page Up\",\n PageDown: \"Page Down\",\n CapsLock: \"Caps Lock\",\n NumLock: \"Num Lock\",\n ScrollLock: \"Scroll Lock\",\n PrintScreen: \"Print Screen\",\n Pause: \"Pause\",\n ContextMenu: \"Menu\",\n\n // Punctuation / symbols\n Backquote: \"`\",\n Minus: \"-\",\n Equal: \"=\",\n BracketLeft: \"[\",\n BracketRight: \"]\",\n Backslash: \"\\\\\",\n Semicolon: \";\",\n Quote: \"'\",\n Comma: \",\",\n Period: \".\",\n Slash: \"/\",\n\n // Numpad\n Numpad0: \"Numpad 0\",\n Numpad1: \"Numpad 1\",\n Numpad2: \"Numpad 2\",\n Numpad3: \"Numpad 3\",\n Numpad4: \"Numpad 4\",\n Numpad5: \"Numpad 5\",\n Numpad6: \"Numpad 6\",\n Numpad7: \"Numpad 7\",\n Numpad8: \"Numpad 8\",\n Numpad9: \"Numpad 9\",\n NumpadAdd: \"Numpad +\",\n NumpadSubtract: \"Numpad -\",\n NumpadMultiply: \"Numpad *\",\n NumpadDivide: \"Numpad /\",\n NumpadDecimal: \"Numpad .\",\n NumpadEnter: \"Numpad Enter\",\n\n // Mouse buttons (synthetic codes from InputPlugin)\n MouseLeft: \"Left Click\",\n MouseMiddle: \"Middle Click\",\n MouseRight: \"Right Click\",\n};\n\n/** Returns a human-readable display name for a `KeyboardEvent.code` or mouse key string. */\nexport function getKeyDisplayName(code: string): string {\n return KEY_DISPLAY_NAMES[code] ?? code;\n}\n"],"mappings":"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","names":["import_core","import_core","import_core"]}
@@ -0,0 +1,175 @@
1
+ import { Vec2, ServiceKey, Plugin, EngineContext, SystemScheduler } from '@yagejs/core';
2
+
3
+ /** Central input state manager. Resolved via DI with InputManagerKey. */
4
+ declare class InputManager {
5
+ private pressedKeys;
6
+ private justPressedKeys;
7
+ private justReleasedKeys;
8
+ private holdStart;
9
+ private actionMap;
10
+ private defaultBindings;
11
+ private groups;
12
+ private actionGroups;
13
+ private disabledGroups;
14
+ private pointerScreenPos;
15
+ private pointerDownState;
16
+ private camera;
17
+ private elapsedMs;
18
+ private listenResolve;
19
+ /** Whether any key mapped to this action is currently held. */
20
+ isPressed(action: string): boolean;
21
+ /** Whether any key mapped to this action was pressed this frame. */
22
+ isJustPressed(action: string): boolean;
23
+ /** Whether any key mapped to this action was released this frame. */
24
+ isJustReleased(action: string): boolean;
25
+ /** Returns true if any key bound to the action exists in the given set. */
26
+ private anyKeyInSet;
27
+ /** Milliseconds the action has been held. Returns 0 if not held. */
28
+ getHoldDuration(action: string): number;
29
+ /** Whether the action has been held for at least `minTime` ms. */
30
+ isHeldFor(action: string, minTime: number): boolean;
31
+ /** Returns -1, 0, or 1 based on negative/positive action states. */
32
+ getAxis(negative: string, positive: string): number;
33
+ /** Returns a Vec2 from four directional actions. Not normalized. */
34
+ getVector(left: string, right: string, up: string, down: string): Vec2;
35
+ /** Pointer position in world coordinates (via Camera), or screen coords if no camera. */
36
+ getPointerPosition(): Vec2;
37
+ /** Raw pointer position in screen coordinates. */
38
+ getPointerScreenPosition(): Vec2;
39
+ /** Whether any pointer button is currently held. */
40
+ isPointerDown(): boolean;
41
+ /** Replace the entire action map and store it as the default for {@link resetBindings}. */
42
+ setActionMap(actions: ActionMapDefinition): void;
43
+ /** Add a key binding to an action. Creates the action if it doesn't exist. */
44
+ bindKey(action: string, key: string): void;
45
+ /** Remove a key binding from an action. */
46
+ unbindKey(action: string, key: string): void;
47
+ /** Returns the current key bindings for an action, or an empty array if unmapped. */
48
+ getBindings(action: string): readonly string[];
49
+ /** Returns all action names that have the given key bound. */
50
+ getActionsForKey(key: string): string[];
51
+ /**
52
+ * Rebind a key to an action with optional conflict detection.
53
+ * Conflicts are only detected between actions sharing at least one group.
54
+ */
55
+ rebind(action: string, key: string, opts?: RebindOptions): RebindResult;
56
+ /**
57
+ * Finds the first action that uses the given key AND shares at least one
58
+ * group with the target action. Ungrouped actions never conflict.
59
+ */
60
+ private findConflictInGroups;
61
+ /** Reset bindings to defaults. If an action name is provided, only reset that action. */
62
+ resetBindings(action?: string): void;
63
+ /** Export the current bindings as a plain object for serialization. */
64
+ exportBindings(): ActionMapDefinition;
65
+ /** Load bindings from a plain object. Resets to defaults first, then overlays the provided map. */
66
+ loadBindings(map: ActionMapDefinition): void;
67
+ /** Configure input groups. Group name -> array of action names. */
68
+ setGroups(groups: Record<string, string[]>): void;
69
+ /** Enable a group by name. */
70
+ enableGroup(name: string): void;
71
+ /** Disable a group by name. Actions only in disabled groups become inactive. */
72
+ disableGroup(name: string): void;
73
+ /** Set exactly these groups as active; all others are disabled. */
74
+ setActiveGroups(names: string[]): void;
75
+ /** Whether a group is currently enabled. Returns true for unknown group names. */
76
+ isGroupEnabled(name: string): boolean;
77
+ /** Get all configured group names. */
78
+ getGroups(): string[];
79
+ /** Get the action names belonging to a group. Returns empty array for unknown groups. */
80
+ getGroupActions(name: string): readonly string[];
81
+ /** Returns true if the action is ungrouped or any of its groups is enabled. */
82
+ private isActionEnabled;
83
+ /** Returns a promise that resolves with the next key code pressed. Intercepts the key. */
84
+ listenForNextKey(): Promise<string | null>;
85
+ /** Cancel an active {@link listenForNextKey}. Resolves the pending promise with `null`. */
86
+ cancelListen(): void;
87
+ /** @internal */
88
+ _onKeyDown(code: string): void;
89
+ /** @internal */
90
+ _onKeyUp(code: string): void;
91
+ /** @internal */
92
+ _onPointerMove(screenX: number, screenY: number): void;
93
+ /** @internal */
94
+ _onPointerDown(): void;
95
+ /** @internal */
96
+ _onPointerUp(): void;
97
+ /** @internal Clear per-frame justPressed/justReleased flags. */
98
+ _clearFrameState(): void;
99
+ /** @internal Set camera for pointer world-coord conversion. */
100
+ _setCamera(camera: CameraLike): void;
101
+ /** Get all configured action names. */
102
+ getActionNames(): string[];
103
+ /** @internal Advance the elapsed game-time clock. Called by InputPollSystem. */
104
+ _advanceTime(dtMs: number): void;
105
+ }
106
+
107
+ /** Service key for the InputManager. */
108
+ declare const InputManagerKey: ServiceKey<InputManager>;
109
+ /** Minimal camera surface needed by InputManager for pointer world-coord conversion. */
110
+ interface CameraLike {
111
+ screenToWorld(screenX: number, screenY: number): {
112
+ x: number;
113
+ y: number;
114
+ };
115
+ }
116
+ /** Minimal renderer surface needed by InputPlugin for canvas access. */
117
+ interface RendererLike {
118
+ readonly canvas: HTMLCanvasElement;
119
+ }
120
+ /** Configuration for the InputPlugin. */
121
+ interface InputConfig {
122
+ /** Target element for pointer events (default: canvas from renderer, or document). */
123
+ target?: HTMLElement;
124
+ /** Action map: action name -> array of physical key codes. */
125
+ actions?: ActionMapDefinition;
126
+ /** Input groups: group name -> array of action names belonging to it. */
127
+ groups?: Record<string, string[]>;
128
+ /** Key codes to call preventDefault() on (default: none). */
129
+ preventDefaultKeys?: string[];
130
+ /** Service key for the camera (enables pointer world-coordinate conversion). */
131
+ cameraKey?: ServiceKey<CameraLike>;
132
+ /** Service key for the renderer (used to auto-target pointer events to its canvas). */
133
+ rendererKey?: ServiceKey<RendererLike>;
134
+ }
135
+ /** Maps action names to arrays of physical key codes. */
136
+ type ActionMapDefinition = Record<string, string[]>;
137
+ /** How to handle a conflict when rebinding a key already used by another action in the same group. */
138
+ type InputConflictPolicy = "replace" | "keep-both" | "reject";
139
+ /** Options for {@link InputManager.rebind}. */
140
+ interface RebindOptions {
141
+ /** Index of the binding slot to replace. Appends if the slot does not exist. */
142
+ slot?: number;
143
+ /** How to resolve conflicts with other actions in the same group(s). Default: `"reject"`. */
144
+ conflict?: InputConflictPolicy;
145
+ }
146
+ /** Result of a {@link InputManager.rebind} call. */
147
+ interface RebindResult {
148
+ /** Whether the rebind succeeded. */
149
+ ok: boolean;
150
+ /** Present when `ok` is false due to a conflict with `conflict: "reject"`. */
151
+ conflict?: {
152
+ action: string;
153
+ key: string;
154
+ };
155
+ }
156
+
157
+ /** Input plugin — wires keyboard and pointer listeners, registers InputManager. */
158
+ declare class InputPlugin implements Plugin {
159
+ readonly name = "input";
160
+ readonly version = "2.0.0";
161
+ private readonly config;
162
+ private manager;
163
+ private context;
164
+ private cleanupFns;
165
+ constructor(config?: InputConfig);
166
+ install(context: EngineContext): void;
167
+ registerSystems(scheduler: SystemScheduler): void;
168
+ onStart(): void;
169
+ onDestroy(): void;
170
+ }
171
+
172
+ /** Returns a human-readable display name for a `KeyboardEvent.code` or mouse key string. */
173
+ declare function getKeyDisplayName(code: string): string;
174
+
175
+ export { type ActionMapDefinition, type CameraLike, type InputConfig, type InputConflictPolicy, InputManager, InputManagerKey, InputPlugin, type RebindOptions, type RebindResult, type RendererLike, getKeyDisplayName };
@@ -0,0 +1,175 @@
1
+ import { Vec2, ServiceKey, Plugin, EngineContext, SystemScheduler } from '@yagejs/core';
2
+
3
+ /** Central input state manager. Resolved via DI with InputManagerKey. */
4
+ declare class InputManager {
5
+ private pressedKeys;
6
+ private justPressedKeys;
7
+ private justReleasedKeys;
8
+ private holdStart;
9
+ private actionMap;
10
+ private defaultBindings;
11
+ private groups;
12
+ private actionGroups;
13
+ private disabledGroups;
14
+ private pointerScreenPos;
15
+ private pointerDownState;
16
+ private camera;
17
+ private elapsedMs;
18
+ private listenResolve;
19
+ /** Whether any key mapped to this action is currently held. */
20
+ isPressed(action: string): boolean;
21
+ /** Whether any key mapped to this action was pressed this frame. */
22
+ isJustPressed(action: string): boolean;
23
+ /** Whether any key mapped to this action was released this frame. */
24
+ isJustReleased(action: string): boolean;
25
+ /** Returns true if any key bound to the action exists in the given set. */
26
+ private anyKeyInSet;
27
+ /** Milliseconds the action has been held. Returns 0 if not held. */
28
+ getHoldDuration(action: string): number;
29
+ /** Whether the action has been held for at least `minTime` ms. */
30
+ isHeldFor(action: string, minTime: number): boolean;
31
+ /** Returns -1, 0, or 1 based on negative/positive action states. */
32
+ getAxis(negative: string, positive: string): number;
33
+ /** Returns a Vec2 from four directional actions. Not normalized. */
34
+ getVector(left: string, right: string, up: string, down: string): Vec2;
35
+ /** Pointer position in world coordinates (via Camera), or screen coords if no camera. */
36
+ getPointerPosition(): Vec2;
37
+ /** Raw pointer position in screen coordinates. */
38
+ getPointerScreenPosition(): Vec2;
39
+ /** Whether any pointer button is currently held. */
40
+ isPointerDown(): boolean;
41
+ /** Replace the entire action map and store it as the default for {@link resetBindings}. */
42
+ setActionMap(actions: ActionMapDefinition): void;
43
+ /** Add a key binding to an action. Creates the action if it doesn't exist. */
44
+ bindKey(action: string, key: string): void;
45
+ /** Remove a key binding from an action. */
46
+ unbindKey(action: string, key: string): void;
47
+ /** Returns the current key bindings for an action, or an empty array if unmapped. */
48
+ getBindings(action: string): readonly string[];
49
+ /** Returns all action names that have the given key bound. */
50
+ getActionsForKey(key: string): string[];
51
+ /**
52
+ * Rebind a key to an action with optional conflict detection.
53
+ * Conflicts are only detected between actions sharing at least one group.
54
+ */
55
+ rebind(action: string, key: string, opts?: RebindOptions): RebindResult;
56
+ /**
57
+ * Finds the first action that uses the given key AND shares at least one
58
+ * group with the target action. Ungrouped actions never conflict.
59
+ */
60
+ private findConflictInGroups;
61
+ /** Reset bindings to defaults. If an action name is provided, only reset that action. */
62
+ resetBindings(action?: string): void;
63
+ /** Export the current bindings as a plain object for serialization. */
64
+ exportBindings(): ActionMapDefinition;
65
+ /** Load bindings from a plain object. Resets to defaults first, then overlays the provided map. */
66
+ loadBindings(map: ActionMapDefinition): void;
67
+ /** Configure input groups. Group name -> array of action names. */
68
+ setGroups(groups: Record<string, string[]>): void;
69
+ /** Enable a group by name. */
70
+ enableGroup(name: string): void;
71
+ /** Disable a group by name. Actions only in disabled groups become inactive. */
72
+ disableGroup(name: string): void;
73
+ /** Set exactly these groups as active; all others are disabled. */
74
+ setActiveGroups(names: string[]): void;
75
+ /** Whether a group is currently enabled. Returns true for unknown group names. */
76
+ isGroupEnabled(name: string): boolean;
77
+ /** Get all configured group names. */
78
+ getGroups(): string[];
79
+ /** Get the action names belonging to a group. Returns empty array for unknown groups. */
80
+ getGroupActions(name: string): readonly string[];
81
+ /** Returns true if the action is ungrouped or any of its groups is enabled. */
82
+ private isActionEnabled;
83
+ /** Returns a promise that resolves with the next key code pressed. Intercepts the key. */
84
+ listenForNextKey(): Promise<string | null>;
85
+ /** Cancel an active {@link listenForNextKey}. Resolves the pending promise with `null`. */
86
+ cancelListen(): void;
87
+ /** @internal */
88
+ _onKeyDown(code: string): void;
89
+ /** @internal */
90
+ _onKeyUp(code: string): void;
91
+ /** @internal */
92
+ _onPointerMove(screenX: number, screenY: number): void;
93
+ /** @internal */
94
+ _onPointerDown(): void;
95
+ /** @internal */
96
+ _onPointerUp(): void;
97
+ /** @internal Clear per-frame justPressed/justReleased flags. */
98
+ _clearFrameState(): void;
99
+ /** @internal Set camera for pointer world-coord conversion. */
100
+ _setCamera(camera: CameraLike): void;
101
+ /** Get all configured action names. */
102
+ getActionNames(): string[];
103
+ /** @internal Advance the elapsed game-time clock. Called by InputPollSystem. */
104
+ _advanceTime(dtMs: number): void;
105
+ }
106
+
107
+ /** Service key for the InputManager. */
108
+ declare const InputManagerKey: ServiceKey<InputManager>;
109
+ /** Minimal camera surface needed by InputManager for pointer world-coord conversion. */
110
+ interface CameraLike {
111
+ screenToWorld(screenX: number, screenY: number): {
112
+ x: number;
113
+ y: number;
114
+ };
115
+ }
116
+ /** Minimal renderer surface needed by InputPlugin for canvas access. */
117
+ interface RendererLike {
118
+ readonly canvas: HTMLCanvasElement;
119
+ }
120
+ /** Configuration for the InputPlugin. */
121
+ interface InputConfig {
122
+ /** Target element for pointer events (default: canvas from renderer, or document). */
123
+ target?: HTMLElement;
124
+ /** Action map: action name -> array of physical key codes. */
125
+ actions?: ActionMapDefinition;
126
+ /** Input groups: group name -> array of action names belonging to it. */
127
+ groups?: Record<string, string[]>;
128
+ /** Key codes to call preventDefault() on (default: none). */
129
+ preventDefaultKeys?: string[];
130
+ /** Service key for the camera (enables pointer world-coordinate conversion). */
131
+ cameraKey?: ServiceKey<CameraLike>;
132
+ /** Service key for the renderer (used to auto-target pointer events to its canvas). */
133
+ rendererKey?: ServiceKey<RendererLike>;
134
+ }
135
+ /** Maps action names to arrays of physical key codes. */
136
+ type ActionMapDefinition = Record<string, string[]>;
137
+ /** How to handle a conflict when rebinding a key already used by another action in the same group. */
138
+ type InputConflictPolicy = "replace" | "keep-both" | "reject";
139
+ /** Options for {@link InputManager.rebind}. */
140
+ interface RebindOptions {
141
+ /** Index of the binding slot to replace. Appends if the slot does not exist. */
142
+ slot?: number;
143
+ /** How to resolve conflicts with other actions in the same group(s). Default: `"reject"`. */
144
+ conflict?: InputConflictPolicy;
145
+ }
146
+ /** Result of a {@link InputManager.rebind} call. */
147
+ interface RebindResult {
148
+ /** Whether the rebind succeeded. */
149
+ ok: boolean;
150
+ /** Present when `ok` is false due to a conflict with `conflict: "reject"`. */
151
+ conflict?: {
152
+ action: string;
153
+ key: string;
154
+ };
155
+ }
156
+
157
+ /** Input plugin — wires keyboard and pointer listeners, registers InputManager. */
158
+ declare class InputPlugin implements Plugin {
159
+ readonly name = "input";
160
+ readonly version = "2.0.0";
161
+ private readonly config;
162
+ private manager;
163
+ private context;
164
+ private cleanupFns;
165
+ constructor(config?: InputConfig);
166
+ install(context: EngineContext): void;
167
+ registerSystems(scheduler: SystemScheduler): void;
168
+ onStart(): void;
169
+ onDestroy(): void;
170
+ }
171
+
172
+ /** Returns a human-readable display name for a `KeyboardEvent.code` or mouse key string. */
173
+ declare function getKeyDisplayName(code: string): string;
174
+
175
+ export { type ActionMapDefinition, type CameraLike, type InputConfig, type InputConflictPolicy, InputManager, InputManagerKey, InputPlugin, type RebindOptions, type RebindResult, type RendererLike, getKeyDisplayName };