@yagejs/input 0.2.0 → 0.4.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.
package/dist/index.d.ts CHANGED
@@ -1,158 +1,6 @@
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
- /** Set camera for pointer world-coord conversion. */
100
- setCamera(camera: CameraLike): void;
101
- /** Clear the camera reference (e.g. on scene exit). */
102
- clearCamera(): void;
103
- /** Get all configured action names. */
104
- getActionNames(): string[];
105
- /** @internal Advance the elapsed game-time clock. Called by InputPollSystem. */
106
- _advanceTime(dtMs: number): void;
107
- }
108
-
109
- /** Service key for the InputManager. */
110
- declare const InputManagerKey: ServiceKey<InputManager>;
111
- /** Minimal camera surface needed by InputManager for pointer world-coord conversion. */
112
- interface CameraLike {
113
- screenToWorld(screenX: number, screenY: number): {
114
- x: number;
115
- y: number;
116
- };
117
- }
118
- /** Minimal renderer surface needed by InputPlugin for canvas access. */
119
- interface RendererLike {
120
- readonly canvas: HTMLCanvasElement;
121
- }
122
- /** Configuration for the InputPlugin. */
123
- interface InputConfig {
124
- /** Target element for pointer events (default: canvas from renderer, or document). */
125
- target?: HTMLElement;
126
- /** Action map: action name -> array of physical key codes. */
127
- actions?: ActionMapDefinition;
128
- /** Input groups: group name -> array of action names belonging to it. */
129
- groups?: Record<string, string[]>;
130
- /** Key codes to call preventDefault() on (default: none). */
131
- preventDefaultKeys?: string[];
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
- }
1
+ import { Plugin, EngineContext, SystemScheduler } from '@yagejs/core';
2
+ import { I as InputConfig } from './api-CTGj55Rb.js';
3
+ export { A as ActionMapDefinition, C as CameraLike, a as InputConflictPolicy, b as InputManager, c as InputManagerKey, R as RebindOptions, d as RebindResult, e as RendererLike } from './api-CTGj55Rb.js';
156
4
 
157
5
  /** Input plugin — wires keyboard and pointer listeners, registers InputManager. */
158
6
  declare class InputPlugin implements Plugin {
@@ -172,4 +20,4 @@ declare class InputPlugin implements Plugin {
172
20
  /** Returns a human-readable display name for a `KeyboardEvent.code` or mouse key string. */
173
21
  declare function getKeyDisplayName(code: string): string;
174
22
 
175
- export { type ActionMapDefinition, type CameraLike, type InputConfig, type InputConflictPolicy, InputManager, InputManagerKey, InputPlugin, type RebindOptions, type RebindResult, type RendererLike, getKeyDisplayName };
23
+ export { InputConfig, InputPlugin, getKeyDisplayName };
package/dist/index.js CHANGED
@@ -1,7 +1,10 @@
1
- var __defProp = Object.defineProperty;
2
- var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
1
+ import {
2
+ InputManagerKey,
3
+ __name
4
+ } from "./chunk-CYWOKPMI.js";
3
5
 
4
6
  // src/InputPlugin.ts
7
+ import { RendererAdapterKey } from "@yagejs/core";
5
8
  import { DebugRegistryKey } from "@yagejs/debug/api";
6
9
 
7
10
  // src/InputManager.ts
@@ -14,6 +17,8 @@ var InputManager = class {
14
17
  justPressedKeys = /* @__PURE__ */ new Set();
15
18
  justReleasedKeys = /* @__PURE__ */ new Set();
16
19
  holdStart = /* @__PURE__ */ new Map();
20
+ syntheticPressedActions = /* @__PURE__ */ new Set();
21
+ syntheticActionStarts = /* @__PURE__ */ new Map();
17
22
  actionMap = /* @__PURE__ */ new Map();
18
23
  defaultBindings = /* @__PURE__ */ new Map();
19
24
  groups = /* @__PURE__ */ new Map();
@@ -21,6 +26,9 @@ var InputManager = class {
21
26
  disabledGroups = /* @__PURE__ */ new Set();
22
27
  pointerScreenPos = Vec2.ZERO;
23
28
  pointerDownState = false;
29
+ pressedMouseButtons = /* @__PURE__ */ new Set();
30
+ gamepadButtons = /* @__PURE__ */ new Map();
31
+ gamepadAxes = /* @__PURE__ */ new Map();
24
32
  camera = null;
25
33
  elapsedMs = 0;
26
34
  listenResolve = null;
@@ -28,12 +36,12 @@ var InputManager = class {
28
36
  /** Whether any key mapped to this action is currently held. */
29
37
  isPressed(action) {
30
38
  if (!this.isActionEnabled(action)) return false;
31
- return this.anyKeyInSet(action, this.pressedKeys);
39
+ return this.syntheticPressedActions.has(action) || this.anyKeyInSet(action, this.pressedKeys);
32
40
  }
33
41
  /** Whether any key mapped to this action was pressed this frame. */
34
42
  isJustPressed(action) {
35
43
  if (!this.isActionEnabled(action)) return false;
36
- return this.anyKeyInSet(action, this.justPressedKeys);
44
+ return this.syntheticPressedActions.has(action) || this.anyKeyInSet(action, this.justPressedKeys);
37
45
  }
38
46
  /** Whether any key mapped to this action was released this frame. */
39
47
  isJustReleased(action) {
@@ -53,14 +61,18 @@ var InputManager = class {
53
61
  getHoldDuration(action) {
54
62
  if (!this.isActionEnabled(action)) return 0;
55
63
  const keys = this.actionMap.get(action);
56
- if (!keys) return 0;
64
+ if (!keys && !this.syntheticPressedActions.has(action)) return 0;
57
65
  let maxDuration = 0;
58
- for (const key of keys) {
66
+ for (const key of keys ?? []) {
59
67
  const start = this.holdStart.get(key);
60
68
  if (start !== void 0) {
61
69
  maxDuration = Math.max(maxDuration, this.elapsedMs - start);
62
70
  }
63
71
  }
72
+ const syntheticStart = this.syntheticActionStarts.get(action);
73
+ if (syntheticStart !== void 0) {
74
+ maxDuration = Math.max(maxDuration, this.elapsedMs - syntheticStart);
75
+ }
64
76
  return maxDuration;
65
77
  }
66
78
  /** Whether the action has been held for at least `minTime` ms. */
@@ -294,6 +306,101 @@ var InputManager = class {
294
306
  resolve(null);
295
307
  }
296
308
  }
309
+ /** Public wrapper for synthetic key-down injection. */
310
+ fireKeyDown(code) {
311
+ this._onKeyDown(code);
312
+ }
313
+ /** Public wrapper for synthetic key-up injection. */
314
+ fireKeyUp(code) {
315
+ this._onKeyUp(code);
316
+ }
317
+ /** Public wrapper for synthetic pointer movement. */
318
+ firePointerMove(screenX, screenY) {
319
+ this._onPointerMove(screenX, screenY);
320
+ }
321
+ /** Public wrapper for synthetic pointer-button presses. */
322
+ firePointerDown(button = 0) {
323
+ this._onPointerDown();
324
+ this.pressedMouseButtons.add(button);
325
+ if (button === 0) this._onKeyDown("MouseLeft");
326
+ if (button === 1) this._onKeyDown("MouseMiddle");
327
+ if (button === 2) this._onKeyDown("MouseRight");
328
+ }
329
+ /** Public wrapper for synthetic pointer-button releases. */
330
+ firePointerUp(button = 0) {
331
+ this.pressedMouseButtons.delete(button);
332
+ this.pointerDownState = this.pressedMouseButtons.size > 0;
333
+ if (!this.pointerDownState) {
334
+ this._onPointerUp();
335
+ }
336
+ if (button === 0) this._onKeyUp("MouseLeft");
337
+ if (button === 1) this._onKeyUp("MouseMiddle");
338
+ if (button === 2) this._onKeyUp("MouseRight");
339
+ }
340
+ /** Store synthetic gamepad button state. */
341
+ fireGamepadButton(idx, pressed) {
342
+ this.gamepadButtons.set(idx, pressed);
343
+ }
344
+ /** Store synthetic gamepad axis state. */
345
+ fireGamepadAxis(idx, value) {
346
+ this.gamepadAxes.set(idx, value);
347
+ }
348
+ /** Inject a one-frame synthetic action pulse. */
349
+ fireAction(name) {
350
+ if (!this.actionMap.has(name)) {
351
+ throw new Error(`InputManager.fireAction(): unknown action "${name}".`);
352
+ }
353
+ this.syntheticPressedActions.add(name);
354
+ this.syntheticActionStarts.set(name, this.elapsedMs);
355
+ }
356
+ /** Release all synthetic and physical input state. */
357
+ clearAll() {
358
+ for (const code of [...this.pressedKeys]) {
359
+ this._onKeyUp(code);
360
+ }
361
+ this.justPressedKeys.clear();
362
+ this.justReleasedKeys.clear();
363
+ this.holdStart.clear();
364
+ this.syntheticPressedActions.clear();
365
+ this.syntheticActionStarts.clear();
366
+ this.pressedMouseButtons.clear();
367
+ this.pointerDownState = false;
368
+ this.gamepadButtons.clear();
369
+ this.gamepadAxes.clear();
370
+ }
371
+ /** Release any pressed pointer buttons without touching keyboard state. */
372
+ clearPointerButtons() {
373
+ for (const button of [...this.pressedMouseButtons]) {
374
+ if (button === 0) this._onKeyUp("MouseLeft");
375
+ if (button === 1) this._onKeyUp("MouseMiddle");
376
+ if (button === 2) this._onKeyUp("MouseRight");
377
+ }
378
+ this.pressedMouseButtons.clear();
379
+ this.pointerDownState = false;
380
+ }
381
+ /** Snapshot of current held input state for inspector tooling. */
382
+ snapshotState() {
383
+ const cmp = /* @__PURE__ */ __name((a, b) => a < b ? -1 : a > b ? 1 : 0, "cmp");
384
+ const keys = [...this.pressedKeys].sort(cmp);
385
+ const actions = this.getActionNames().filter((action) => this.isPressed(action)).sort(cmp);
386
+ const buttons = [...this.pressedMouseButtons].sort((a, b) => a - b);
387
+ const pressedButtons = [...this.gamepadButtons.entries()].filter(([, pressed]) => pressed).map(([idx]) => idx).sort((a, b) => a - b);
388
+ const axes = [...this.gamepadAxes.entries()].filter(([, value]) => value !== 0).sort(([a], [b]) => a - b).map(([index, value]) => ({ index, value }));
389
+ return {
390
+ keys,
391
+ actions,
392
+ mouse: {
393
+ x: this.pointerScreenPos.x,
394
+ y: this.pointerScreenPos.y,
395
+ buttons,
396
+ down: this.pointerDownState
397
+ },
398
+ gamepad: {
399
+ buttons: pressedButtons,
400
+ axes
401
+ }
402
+ };
403
+ }
297
404
  // -- Internal methods (called by InputPlugin / Systems) --
298
405
  /** @internal */
299
406
  _onKeyDown(code) {
@@ -333,6 +440,8 @@ var InputManager = class {
333
440
  _clearFrameState() {
334
441
  this.justPressedKeys.clear();
335
442
  this.justReleasedKeys.clear();
443
+ this.syntheticPressedActions.clear();
444
+ this.syntheticActionStarts.clear();
336
445
  }
337
446
  /** Set camera for pointer world-coord conversion. */
338
447
  setCamera(camera) {
@@ -352,10 +461,6 @@ var InputManager = class {
352
461
  }
353
462
  };
354
463
 
355
- // src/types.ts
356
- import { ServiceKey } from "@yagejs/core";
357
- var InputManagerKey = new ServiceKey("inputManager");
358
-
359
464
  // src/InputPollSystem.ts
360
465
  import { System, Phase } from "@yagejs/core";
361
466
  var InputPollSystem = class extends System {
@@ -447,9 +552,11 @@ var InputPlugin = class {
447
552
  if (this.config.groups) {
448
553
  this.manager.setGroups(this.config.groups);
449
554
  }
450
- const renderer = this.config.rendererKey ? context.tryResolve(this.config.rendererKey) : void 0;
555
+ const rendererKey = this.config.rendererKey ?? RendererAdapterKey;
556
+ const renderer = context.tryResolve(rendererKey);
451
557
  const pointerTarget = this.config.target ?? renderer?.canvas ?? document;
452
- const pointerElement = this.config.target ?? renderer?.canvas ?? null;
558
+ const coordinateElement = renderer?.canvas ?? this.config.target ?? null;
559
+ const mapPointer = /* @__PURE__ */ __name((cssX, cssY) => renderer?.canvasToVirtual?.(cssX, cssY) ?? { x: cssX, y: cssY }, "mapPointer");
453
560
  const preventSet = new Set(this.config.preventDefaultKeys ?? []);
454
561
  const onKeyDown = /* @__PURE__ */ __name((e) => {
455
562
  const ke = e;
@@ -470,30 +577,39 @@ var InputPlugin = class {
470
577
  );
471
578
  const onPointerMove = /* @__PURE__ */ __name((e) => {
472
579
  const pe = e;
473
- if (pointerElement) {
474
- const rect = pointerElement.getBoundingClientRect();
475
- this.manager._onPointerMove(pe.clientX - rect.left, pe.clientY - rect.top);
580
+ let cssX;
581
+ let cssY;
582
+ if (coordinateElement) {
583
+ const rect = coordinateElement.getBoundingClientRect();
584
+ cssX = pe.clientX - rect.left;
585
+ cssY = pe.clientY - rect.top;
476
586
  } else {
477
- this.manager._onPointerMove(pe.clientX, pe.clientY);
587
+ cssX = pe.clientX;
588
+ cssY = pe.clientY;
478
589
  }
590
+ const mapped = mapPointer(cssX, cssY);
591
+ this.manager._onPointerMove(mapped.x, mapped.y);
479
592
  }, "onPointerMove");
480
593
  const onPointerDown = /* @__PURE__ */ __name((e) => {
481
594
  const pe = e;
482
- this.manager._onPointerDown();
483
- const mouseKey = MOUSE_BUTTON_MAP[pe.button];
484
- if (mouseKey) this.manager._onKeyDown(mouseKey);
595
+ const button = pe.button;
596
+ if (button in MOUSE_BUTTON_MAP) {
597
+ this.manager.firePointerDown(button);
598
+ } else {
599
+ this.manager._onPointerDown();
600
+ }
485
601
  }, "onPointerDown");
486
602
  const onPointerUp = /* @__PURE__ */ __name((e) => {
487
603
  const pe = e;
488
- this.manager._onPointerUp();
489
- const mouseKey = MOUSE_BUTTON_MAP[pe.button];
490
- if (mouseKey) this.manager._onKeyUp(mouseKey);
604
+ const button = pe.button;
605
+ if (button in MOUSE_BUTTON_MAP) {
606
+ this.manager.firePointerUp(button);
607
+ } else {
608
+ this.manager._onPointerUp();
609
+ }
491
610
  }, "onPointerUp");
492
611
  const onPointerCancel = /* @__PURE__ */ __name(() => {
493
- this.manager._onPointerUp();
494
- this.manager._onKeyUp("MouseLeft");
495
- this.manager._onKeyUp("MouseMiddle");
496
- this.manager._onKeyUp("MouseRight");
612
+ this.manager.clearPointerButtons();
497
613
  }, "onPointerCancel");
498
614
  pointerTarget.addEventListener("pointerdown", onPointerDown);
499
615
  window.addEventListener("pointermove", onPointerMove);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/InputPlugin.ts","../src/InputManager.ts","../src/types.ts","../src/InputPollSystem.ts","../src/InputClearSystem.ts","../src/InputDebugContributor.ts","../src/keyDisplayNames.ts"],"sourcesContent":["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 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 /** Set camera for pointer world-coord conversion. */\n setCamera(camera: CameraLike): void {\n this.camera = camera;\n }\n\n /** Clear the camera reference (e.g. on scene exit). */\n clearCamera(): void {\n this.camera = null;\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 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":["System","Phase","System","Phase"]}
1
+ {"version":3,"sources":["../src/InputPlugin.ts","../src/InputManager.ts","../src/InputPollSystem.ts","../src/InputClearSystem.ts","../src/InputDebugContributor.ts","../src/keyDisplayNames.ts"],"sourcesContent":["import type { EngineContext, Plugin, SystemScheduler } from \"@yagejs/core\";\nimport { RendererAdapterKey } 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 // Default to the well-known RendererAdapterKey so the canonical renderer\n // is picked up with no config. `rendererKey` stays as an override for\n // custom/foreign renderers registered under a different key.\n const rendererKey = this.config.rendererKey ?? RendererAdapterKey;\n const renderer = context.tryResolve(rendererKey);\n const pointerTarget: EventTarget =\n this.config.target ?? renderer?.canvas ?? document;\n\n // Element used to convert clientX/clientY to element-relative coordinates.\n // When `canvasToVirtual` is available, it always expects canvas-origin\n // pixels — so prefer the canvas over a custom `config.target` (which may\n // be a wrapping element). Falls back to null if neither is available.\n const coordinateElement: Element | null =\n renderer?.canvas ??\n this.config.target ??\n null;\n\n // When the renderer exposes canvasToVirtual, route pointer coords through\n // it so they stay correct under responsive fit or custom virtual sizes.\n // Without it, raw canvas-relative CSS pixels are passed through unchanged\n // (works only when canvas CSS size == virtual size — the default).\n const mapPointer = (cssX: number, cssY: number): { x: number; y: number } =>\n renderer?.canvasToVirtual?.(cssX, cssY) ?? { x: cssX, y: cssY };\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 let cssX: number;\n let cssY: number;\n if (coordinateElement) {\n const rect = coordinateElement.getBoundingClientRect();\n cssX = pe.clientX - rect.left;\n cssY = pe.clientY - rect.top;\n } else {\n cssX = pe.clientX;\n cssY = pe.clientY;\n }\n const mapped = mapPointer(cssX, cssY);\n this.manager._onPointerMove(mapped.x, mapped.y);\n };\n const onPointerDown = (e: Event): void => {\n const pe = e as PointerEvent;\n const button = pe.button as 0 | 1 | 2;\n if (button in MOUSE_BUTTON_MAP) {\n this.manager.firePointerDown(button);\n } else {\n this.manager._onPointerDown();\n }\n };\n const onPointerUp = (e: Event): void => {\n const pe = e as PointerEvent;\n const button = pe.button as 0 | 1 | 2;\n if (button in MOUSE_BUTTON_MAP) {\n this.manager.firePointerUp(button);\n } else {\n this.manager._onPointerUp();\n }\n };\n const onPointerCancel = (): void => {\n this.manager.clearPointerButtons();\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 syntheticPressedActions = new Set<string>();\n private syntheticActionStarts = 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 pressedMouseButtons = new Set<number>();\n private gamepadButtons = new Map<number, boolean>();\n private gamepadAxes = new Map<number, number>();\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.syntheticPressedActions.has(action) ||\n 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.syntheticPressedActions.has(action) ||\n 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 && !this.syntheticPressedActions.has(action)) 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 const syntheticStart = this.syntheticActionStarts.get(action);\n if (syntheticStart !== undefined) {\n maxDuration = Math.max(maxDuration, this.elapsedMs - syntheticStart);\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 /** Public wrapper for synthetic key-down injection. */\n fireKeyDown(code: string): void {\n this._onKeyDown(code);\n }\n\n /** Public wrapper for synthetic key-up injection. */\n fireKeyUp(code: string): void {\n this._onKeyUp(code);\n }\n\n /** Public wrapper for synthetic pointer movement. */\n firePointerMove(screenX: number, screenY: number): void {\n this._onPointerMove(screenX, screenY);\n }\n\n /** Public wrapper for synthetic pointer-button presses. */\n firePointerDown(button: 0 | 1 | 2 = 0): void {\n this._onPointerDown();\n this.pressedMouseButtons.add(button);\n\n if (button === 0) this._onKeyDown(\"MouseLeft\");\n if (button === 1) this._onKeyDown(\"MouseMiddle\");\n if (button === 2) this._onKeyDown(\"MouseRight\");\n }\n\n /** Public wrapper for synthetic pointer-button releases. */\n firePointerUp(button: 0 | 1 | 2 = 0): void {\n this.pressedMouseButtons.delete(button);\n this.pointerDownState = this.pressedMouseButtons.size > 0;\n if (!this.pointerDownState) {\n this._onPointerUp();\n }\n\n if (button === 0) this._onKeyUp(\"MouseLeft\");\n if (button === 1) this._onKeyUp(\"MouseMiddle\");\n if (button === 2) this._onKeyUp(\"MouseRight\");\n }\n\n /** Store synthetic gamepad button state. */\n fireGamepadButton(idx: number, pressed: boolean): void {\n this.gamepadButtons.set(idx, pressed);\n }\n\n /** Store synthetic gamepad axis state. */\n fireGamepadAxis(idx: number, value: number): void {\n this.gamepadAxes.set(idx, value);\n }\n\n /** Inject a one-frame synthetic action pulse. */\n fireAction(name: string): void {\n if (!this.actionMap.has(name)) {\n throw new Error(`InputManager.fireAction(): unknown action \"${name}\".`);\n }\n this.syntheticPressedActions.add(name);\n this.syntheticActionStarts.set(name, this.elapsedMs);\n }\n\n /** Release all synthetic and physical input state. */\n clearAll(): void {\n for (const code of [...this.pressedKeys]) {\n this._onKeyUp(code);\n }\n // Hard reset: synthetic releases generated above are intentionally\n // discarded. Callers want a clean slate, not a flurry of justReleased\n // pulses for downstream listeners.\n this.justPressedKeys.clear();\n this.justReleasedKeys.clear();\n this.holdStart.clear();\n this.syntheticPressedActions.clear();\n this.syntheticActionStarts.clear();\n this.pressedMouseButtons.clear();\n this.pointerDownState = false;\n this.gamepadButtons.clear();\n this.gamepadAxes.clear();\n }\n\n /** Release any pressed pointer buttons without touching keyboard state. */\n clearPointerButtons(): void {\n for (const button of [...this.pressedMouseButtons]) {\n if (button === 0) this._onKeyUp(\"MouseLeft\");\n if (button === 1) this._onKeyUp(\"MouseMiddle\");\n if (button === 2) this._onKeyUp(\"MouseRight\");\n }\n this.pressedMouseButtons.clear();\n this.pointerDownState = false;\n }\n\n /** Snapshot of current held input state for inspector tooling. */\n snapshotState(): {\n keys: string[];\n actions: string[];\n mouse: { x: number; y: number; buttons: number[]; down: boolean };\n gamepad: {\n buttons: number[];\n axes: Array<{ index: number; value: number }>;\n };\n } {\n const cmp = (a: string, b: string) => (a < b ? -1 : a > b ? 1 : 0);\n const keys = [...this.pressedKeys].sort(cmp);\n const actions = this.getActionNames()\n .filter((action) => this.isPressed(action))\n .sort(cmp);\n const buttons = [...this.pressedMouseButtons].sort((a, b) => a - b);\n const pressedButtons = [...this.gamepadButtons.entries()]\n .filter(([, pressed]) => pressed)\n .map(([idx]) => idx)\n .sort((a, b) => a - b);\n const axes = [...this.gamepadAxes.entries()]\n .filter(([, value]) => value !== 0)\n .sort(([a], [b]) => a - b)\n .map(([index, value]) => ({ index, value }));\n\n return {\n keys,\n actions,\n mouse: {\n x: this.pointerScreenPos.x,\n y: this.pointerScreenPos.y,\n buttons,\n down: this.pointerDownState,\n },\n gamepad: {\n buttons: pressedButtons,\n axes,\n },\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 this.syntheticPressedActions.clear();\n this.syntheticActionStarts.clear();\n }\n\n /** Set camera for pointer world-coord conversion. */\n setCamera(camera: CameraLike): void {\n this.camera = camera;\n }\n\n /** Clear the camera reference (e.g. on scene exit). */\n clearCamera(): void {\n this.camera = null;\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 { 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":";;;;;;AACA,SAAS,0BAA0B;AACnC,SAAS,wBAAwB;;;ACFjC,SAAS,YAAY;AASd,IAAM,eAAN,MAAmB;AAAA,EAT1B,OAS0B;AAAA;AAAA;AAAA,EAChB,cAAc,oBAAI,IAAY;AAAA,EAC9B,kBAAkB,oBAAI,IAAY;AAAA,EAClC,mBAAmB,oBAAI,IAAY;AAAA,EACnC,YAAY,oBAAI,IAAoB;AAAA,EACpC,0BAA0B,oBAAI,IAAY;AAAA,EAC1C,wBAAwB,oBAAI,IAAoB;AAAA,EAChD,YAAY,oBAAI,IAAsB;AAAA,EACtC,kBAAkB,oBAAI,IAAsB;AAAA,EAC5C,SAAS,oBAAI,IAAyB;AAAA,EACtC,eAAe,oBAAI,IAAyB;AAAA,EAC5C,iBAAiB,oBAAI,IAAY;AAAA,EACjC,mBAAmB,KAAK;AAAA,EACxB,mBAAmB;AAAA,EACnB,sBAAsB,oBAAI,IAAY;AAAA,EACtC,iBAAiB,oBAAI,IAAqB;AAAA,EAC1C,cAAc,oBAAI,IAAoB;AAAA,EACtC,SAA4B;AAAA,EAC5B,YAAY;AAAA,EACZ,gBAAuD;AAAA;AAAA;AAAA,EAK/D,UAAU,QAAyB;AACjC,QAAI,CAAC,KAAK,gBAAgB,MAAM,EAAG,QAAO;AAC1C,WAAO,KAAK,wBAAwB,IAAI,MAAM,KAC5C,KAAK,YAAY,QAAQ,KAAK,WAAW;AAAA,EAC7C;AAAA;AAAA,EAGA,cAAc,QAAyB;AACrC,QAAI,CAAC,KAAK,gBAAgB,MAAM,EAAG,QAAO;AAC1C,WAAO,KAAK,wBAAwB,IAAI,MAAM,KAC5C,KAAK,YAAY,QAAQ,KAAK,eAAe;AAAA,EACjD;AAAA;AAAA,EAGA,eAAe,QAAyB;AACtC,QAAI,CAAC,KAAK,gBAAgB,MAAM,EAAG,QAAO;AAC1C,WAAO,KAAK,YAAY,QAAQ,KAAK,gBAAgB;AAAA,EACvD;AAAA;AAAA,EAGQ,YAAY,QAAgB,KAA2B;AAC7D,UAAM,OAAO,KAAK,UAAU,IAAI,MAAM;AACtC,QAAI,CAAC,KAAM,QAAO;AAClB,eAAW,OAAO,MAAM;AACtB,UAAI,IAAI,IAAI,GAAG,EAAG,QAAO;AAAA,IAC3B;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,gBAAgB,QAAwB;AACtC,QAAI,CAAC,KAAK,gBAAgB,MAAM,EAAG,QAAO;AAC1C,UAAM,OAAO,KAAK,UAAU,IAAI,MAAM;AACtC,QAAI,CAAC,QAAQ,CAAC,KAAK,wBAAwB,IAAI,MAAM,EAAG,QAAO;AAC/D,QAAI,cAAc;AAClB,eAAW,OAAO,QAAQ,CAAC,GAAG;AAC5B,YAAM,QAAQ,KAAK,UAAU,IAAI,GAAG;AACpC,UAAI,UAAU,QAAW;AACvB,sBAAc,KAAK,IAAI,aAAa,KAAK,YAAY,KAAK;AAAA,MAC5D;AAAA,IACF;AACA,UAAM,iBAAiB,KAAK,sBAAsB,IAAI,MAAM;AAC5D,QAAI,mBAAmB,QAAW;AAChC,oBAAc,KAAK,IAAI,aAAa,KAAK,YAAY,cAAc;AAAA,IACrE;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,UAAU,QAAgB,SAA0B;AAClD,WAAO,KAAK,gBAAgB,MAAM,KAAK;AAAA,EACzC;AAAA;AAAA;AAAA,EAKA,QAAQ,UAAkB,UAA0B;AAClD,UAAM,MAAM,KAAK,UAAU,QAAQ,IAAI,IAAI;AAC3C,UAAM,MAAM,KAAK,UAAU,QAAQ,IAAI,IAAI;AAC3C,WAAO,MAAM;AAAA,EACf;AAAA;AAAA,EAGA,UACE,MACA,OACA,IACA,MACM;AACN,UAAM,IAAI,KAAK,QAAQ,MAAM,KAAK;AAClC,UAAM,IAAI,KAAK,QAAQ,IAAI,IAAI;AAC/B,WAAO,IAAI,KAAK,GAAG,CAAC;AAAA,EACtB;AAAA;AAAA;AAAA,EAKA,qBAA2B;AACzB,QAAI,KAAK,QAAQ;AACf,YAAM,IAAI,KAAK,OAAO;AAAA,QACpB,KAAK,iBAAiB;AAAA,QACtB,KAAK,iBAAiB;AAAA,MACxB;AACA,aAAO,IAAI,KAAK,EAAE,GAAG,EAAE,CAAC;AAAA,IAC1B;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,2BAAiC;AAC/B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,gBAAyB;AACvB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA,EAKA,aAAa,SAAoC;AAC/C,SAAK,UAAU,MAAM;AACrB,SAAK,gBAAgB,MAAM;AAC3B,eAAW,CAAC,QAAQ,IAAI,KAAK,OAAO,QAAQ,OAAO,GAAG;AACpD,WAAK,UAAU,IAAI,QAAQ,CAAC,GAAG,IAAI,CAAC;AACpC,WAAK,gBAAgB,IAAI,QAAQ,CAAC,GAAG,IAAI,CAAC;AAAA,IAC5C;AAAA,EACF;AAAA;AAAA,EAGA,QAAQ,QAAgB,KAAmB;AACzC,QAAI,OAAO,KAAK,UAAU,IAAI,MAAM;AACpC,QAAI,CAAC,MAAM;AACT,aAAO,CAAC;AACR,WAAK,UAAU,IAAI,QAAQ,IAAI;AAAA,IACjC;AACA,QAAI,CAAC,KAAK,SAAS,GAAG,GAAG;AACvB,WAAK,KAAK,GAAG;AAAA,IACf;AAAA,EACF;AAAA;AAAA,EAGA,UAAU,QAAgB,KAAmB;AAC3C,UAAM,OAAO,KAAK,UAAU,IAAI,MAAM;AACtC,QAAI,CAAC,KAAM;AACX,UAAM,MAAM,KAAK,QAAQ,GAAG;AAC5B,QAAI,QAAQ,GAAI,MAAK,OAAO,KAAK,CAAC;AAAA,EACpC;AAAA;AAAA;AAAA,EAKA,YAAY,QAAmC;AAC7C,WAAO,KAAK,UAAU,IAAI,MAAM,KAAK,CAAC;AAAA,EACxC;AAAA;AAAA,EAGA,iBAAiB,KAAuB;AACtC,UAAM,SAAmB,CAAC;AAC1B,eAAW,CAAC,QAAQ,IAAI,KAAK,KAAK,WAAW;AAC3C,UAAI,KAAK,SAAS,GAAG,EAAG,QAAO,KAAK,MAAM;AAAA,IAC5C;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,QAAgB,KAAa,MAAoC;AACtE,UAAM,WAAW,MAAM,YAAY;AACnC,UAAM,OAAO,MAAM;AAEnB,UAAM,iBAAiB,KAAK,qBAAqB,QAAQ,GAAG;AAE5D,QAAI,kBAAkB,aAAa,UAAU;AAC3C,aAAO,EAAE,IAAI,OAAO,UAAU,EAAE,QAAQ,gBAAgB,IAAI,EAAE;AAAA,IAChE;AAEA,QAAI,kBAAkB,aAAa,WAAW;AAC5C,WAAK,UAAU,gBAAgB,GAAG;AAAA,IACpC;AAEA,QAAI,OAAO,KAAK,UAAU,IAAI,MAAM;AACpC,QAAI,CAAC,MAAM;AACT,aAAO,CAAC;AACR,WAAK,UAAU,IAAI,QAAQ,IAAI;AAAA,IACjC;AAGA,UAAM,cAAc,KAAK,QAAQ,GAAG;AACpC,QAAI,aAAa;AACjB,QAAI,eAAe,UAAa,gBAAgB,MAAM,gBAAgB,YAAY;AAChF,WAAK,OAAO,aAAa,CAAC;AAC1B,UAAI,aAAa,YAAa;AAAA,IAChC;AAEA,QAAI,eAAe,UAAa,aAAa,KAAK,QAAQ;AACxD,WAAK,UAAU,IAAI;AAAA,IACrB,WAAW,CAAC,KAAK,SAAS,GAAG,GAAG;AAC9B,WAAK,KAAK,GAAG;AAAA,IACf;AAEA,WAAO,EAAE,IAAI,KAAK;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,qBAAqB,QAAgB,KAA4B;AACvE,UAAM,WAAW,KAAK,aAAa,IAAI,MAAM;AAC7C,QAAI,CAAC,YAAY,SAAS,SAAS,EAAG,QAAO;AAE7C,eAAW,CAAC,aAAa,SAAS,KAAK,KAAK,WAAW;AACrD,UAAI,gBAAgB,OAAQ;AAC5B,UAAI,CAAC,UAAU,SAAS,GAAG,EAAG;AAE9B,YAAM,cAAc,KAAK,aAAa,IAAI,WAAW;AACrD,UAAI,CAAC,YAAa;AAElB,iBAAW,KAAK,UAAU;AACxB,YAAI,YAAY,IAAI,CAAC,EAAG,QAAO;AAAA,MACjC;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA,EAKA,cAAc,QAAuB;AACnC,QAAI,WAAW,QAAW;AACxB,YAAM,WAAW,KAAK,gBAAgB,IAAI,MAAM;AAChD,UAAI,UAAU;AACZ,aAAK,UAAU,IAAI,QAAQ,CAAC,GAAG,QAAQ,CAAC;AAAA,MAC1C;AAAA,IACF,OAAO;AACL,WAAK,UAAU,MAAM;AACrB,iBAAW,CAAC,GAAG,IAAI,KAAK,KAAK,iBAAiB;AAC5C,aAAK,UAAU,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,iBAAsC;AACpC,UAAM,SAA8B,CAAC;AACrC,eAAW,CAAC,QAAQ,IAAI,KAAK,KAAK,WAAW;AAC3C,aAAO,MAAM,IAAI,CAAC,GAAG,IAAI;AAAA,IAC3B;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,aAAa,KAAgC;AAC3C,SAAK,cAAc;AACnB,eAAW,CAAC,QAAQ,IAAI,KAAK,OAAO,QAAQ,GAAG,GAAG;AAChD,WAAK,UAAU,IAAI,QAAQ,CAAC,GAAG,IAAI,CAAC;AAAA,IACtC;AAAA,EACF;AAAA;AAAA;AAAA,EAKA,UAAU,QAAwC;AAChD,SAAK,OAAO,MAAM;AAClB,SAAK,aAAa,MAAM;AACxB,eAAW,CAAC,MAAM,OAAO,KAAK,OAAO,QAAQ,MAAM,GAAG;AACpD,WAAK,OAAO,IAAI,MAAM,IAAI,IAAI,OAAO,CAAC;AACtC,iBAAW,UAAU,SAAS;AAC5B,YAAI,MAAM,KAAK,aAAa,IAAI,MAAM;AACtC,YAAI,CAAC,KAAK;AACR,gBAAM,oBAAI,IAAI;AACd,eAAK,aAAa,IAAI,QAAQ,GAAG;AAAA,QACnC;AACA,YAAI,IAAI,IAAI;AAAA,MACd;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,YAAY,MAAoB;AAC9B,SAAK,eAAe,OAAO,IAAI;AAAA,EACjC;AAAA;AAAA,EAGA,aAAa,MAAoB;AAC/B,SAAK,eAAe,IAAI,IAAI;AAAA,EAC9B;AAAA;AAAA,EAGA,gBAAgB,OAAuB;AACrC,SAAK,eAAe,MAAM;AAC1B,eAAW,SAAS,KAAK,OAAO,KAAK,GAAG;AACtC,UAAI,CAAC,MAAM,SAAS,KAAK,GAAG;AAC1B,aAAK,eAAe,IAAI,KAAK;AAAA,MAC/B;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,eAAe,MAAuB;AACpC,WAAO,CAAC,KAAK,eAAe,IAAI,IAAI;AAAA,EACtC;AAAA;AAAA,EAGA,YAAsB;AACpB,WAAO,MAAM,KAAK,KAAK,OAAO,KAAK,CAAC;AAAA,EACtC;AAAA;AAAA,EAGA,gBAAgB,MAAiC;AAC/C,UAAM,MAAM,KAAK,OAAO,IAAI,IAAI;AAChC,WAAO,MAAM,MAAM,KAAK,GAAG,IAAI,CAAC;AAAA,EAClC;AAAA;AAAA,EAGQ,gBAAgB,QAAyB;AAC/C,UAAM,WAAW,KAAK,aAAa,IAAI,MAAM;AAC7C,QAAI,CAAC,YAAY,SAAS,SAAS,EAAG,QAAO;AAC7C,eAAW,SAAS,UAAU;AAC5B,UAAI,CAAC,KAAK,eAAe,IAAI,KAAK,EAAG,QAAO;AAAA,IAC9C;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA,EAKA,mBAA2C;AACzC,SAAK,aAAa;AAClB,WAAO,IAAI,QAAuB,CAAC,YAAY;AAC7C,WAAK,gBAAgB;AAAA,IACvB,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,eAAqB;AACnB,QAAI,KAAK,eAAe;AACtB,YAAM,UAAU,KAAK;AACrB,WAAK,gBAAgB;AACrB,cAAQ,IAAI;AAAA,IACd;AAAA,EACF;AAAA;AAAA,EAGA,YAAY,MAAoB;AAC9B,SAAK,WAAW,IAAI;AAAA,EACtB;AAAA;AAAA,EAGA,UAAU,MAAoB;AAC5B,SAAK,SAAS,IAAI;AAAA,EACpB;AAAA;AAAA,EAGA,gBAAgB,SAAiB,SAAuB;AACtD,SAAK,eAAe,SAAS,OAAO;AAAA,EACtC;AAAA;AAAA,EAGA,gBAAgB,SAAoB,GAAS;AAC3C,SAAK,eAAe;AACpB,SAAK,oBAAoB,IAAI,MAAM;AAEnC,QAAI,WAAW,EAAG,MAAK,WAAW,WAAW;AAC7C,QAAI,WAAW,EAAG,MAAK,WAAW,aAAa;AAC/C,QAAI,WAAW,EAAG,MAAK,WAAW,YAAY;AAAA,EAChD;AAAA;AAAA,EAGA,cAAc,SAAoB,GAAS;AACzC,SAAK,oBAAoB,OAAO,MAAM;AACtC,SAAK,mBAAmB,KAAK,oBAAoB,OAAO;AACxD,QAAI,CAAC,KAAK,kBAAkB;AAC1B,WAAK,aAAa;AAAA,IACpB;AAEA,QAAI,WAAW,EAAG,MAAK,SAAS,WAAW;AAC3C,QAAI,WAAW,EAAG,MAAK,SAAS,aAAa;AAC7C,QAAI,WAAW,EAAG,MAAK,SAAS,YAAY;AAAA,EAC9C;AAAA;AAAA,EAGA,kBAAkB,KAAa,SAAwB;AACrD,SAAK,eAAe,IAAI,KAAK,OAAO;AAAA,EACtC;AAAA;AAAA,EAGA,gBAAgB,KAAa,OAAqB;AAChD,SAAK,YAAY,IAAI,KAAK,KAAK;AAAA,EACjC;AAAA;AAAA,EAGA,WAAW,MAAoB;AAC7B,QAAI,CAAC,KAAK,UAAU,IAAI,IAAI,GAAG;AAC7B,YAAM,IAAI,MAAM,8CAA8C,IAAI,IAAI;AAAA,IACxE;AACA,SAAK,wBAAwB,IAAI,IAAI;AACrC,SAAK,sBAAsB,IAAI,MAAM,KAAK,SAAS;AAAA,EACrD;AAAA;AAAA,EAGA,WAAiB;AACf,eAAW,QAAQ,CAAC,GAAG,KAAK,WAAW,GAAG;AACxC,WAAK,SAAS,IAAI;AAAA,IACpB;AAIA,SAAK,gBAAgB,MAAM;AAC3B,SAAK,iBAAiB,MAAM;AAC5B,SAAK,UAAU,MAAM;AACrB,SAAK,wBAAwB,MAAM;AACnC,SAAK,sBAAsB,MAAM;AACjC,SAAK,oBAAoB,MAAM;AAC/B,SAAK,mBAAmB;AACxB,SAAK,eAAe,MAAM;AAC1B,SAAK,YAAY,MAAM;AAAA,EACzB;AAAA;AAAA,EAGA,sBAA4B;AAC1B,eAAW,UAAU,CAAC,GAAG,KAAK,mBAAmB,GAAG;AAClD,UAAI,WAAW,EAAG,MAAK,SAAS,WAAW;AAC3C,UAAI,WAAW,EAAG,MAAK,SAAS,aAAa;AAC7C,UAAI,WAAW,EAAG,MAAK,SAAS,YAAY;AAAA,IAC9C;AACA,SAAK,oBAAoB,MAAM;AAC/B,SAAK,mBAAmB;AAAA,EAC1B;AAAA;AAAA,EAGA,gBAQE;AACA,UAAM,MAAM,wBAAC,GAAW,MAAe,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,GAApD;AACZ,UAAM,OAAO,CAAC,GAAG,KAAK,WAAW,EAAE,KAAK,GAAG;AAC3C,UAAM,UAAU,KAAK,eAAe,EACjC,OAAO,CAAC,WAAW,KAAK,UAAU,MAAM,CAAC,EACzC,KAAK,GAAG;AACX,UAAM,UAAU,CAAC,GAAG,KAAK,mBAAmB,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAClE,UAAM,iBAAiB,CAAC,GAAG,KAAK,eAAe,QAAQ,CAAC,EACrD,OAAO,CAAC,CAAC,EAAE,OAAO,MAAM,OAAO,EAC/B,IAAI,CAAC,CAAC,GAAG,MAAM,GAAG,EAClB,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AACvB,UAAM,OAAO,CAAC,GAAG,KAAK,YAAY,QAAQ,CAAC,EACxC,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,UAAU,CAAC,EACjC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,EACxB,IAAI,CAAC,CAAC,OAAO,KAAK,OAAO,EAAE,OAAO,MAAM,EAAE;AAE7C,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,OAAO;AAAA,QACL,GAAG,KAAK,iBAAiB;AAAA,QACzB,GAAG,KAAK,iBAAiB;AAAA,QACzB;AAAA,QACA,MAAM,KAAK;AAAA,MACb;AAAA,MACA,SAAS;AAAA,QACP,SAAS;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA,EAKA,WAAW,MAAoB;AAC7B,QAAI,KAAK,eAAe;AACtB,YAAM,UAAU,KAAK;AACrB,WAAK,gBAAgB;AACrB,cAAQ,IAAI;AACZ;AAAA,IACF;AACA,QAAI,CAAC,KAAK,YAAY,IAAI,IAAI,GAAG;AAC/B,WAAK,YAAY,IAAI,IAAI;AACzB,WAAK,gBAAgB,IAAI,IAAI;AAC7B,WAAK,UAAU,IAAI,MAAM,KAAK,SAAS;AAAA,IACzC;AAAA,EACF;AAAA;AAAA,EAGA,SAAS,MAAoB;AAC3B,QAAI,KAAK,YAAY,IAAI,IAAI,GAAG;AAC9B,WAAK,YAAY,OAAO,IAAI;AAC5B,WAAK,iBAAiB,IAAI,IAAI;AAC9B,WAAK,UAAU,OAAO,IAAI;AAAA,IAC5B;AAAA,EACF;AAAA;AAAA,EAGA,eAAe,SAAiB,SAAuB;AACrD,SAAK,mBAAmB,IAAI,KAAK,SAAS,OAAO;AAAA,EACnD;AAAA;AAAA,EAGA,iBAAuB;AACrB,SAAK,mBAAmB;AAAA,EAC1B;AAAA;AAAA,EAGA,eAAqB;AACnB,SAAK,mBAAmB;AAAA,EAC1B;AAAA;AAAA,EAGA,mBAAyB;AACvB,SAAK,gBAAgB,MAAM;AAC3B,SAAK,iBAAiB,MAAM;AAC5B,SAAK,wBAAwB,MAAM;AACnC,SAAK,sBAAsB,MAAM;AAAA,EACnC;AAAA;AAAA,EAGA,UAAU,QAA0B;AAClC,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA,EAGA,cAAoB;AAClB,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA,EAGA,iBAA2B;AACzB,WAAO,MAAM,KAAK,KAAK,UAAU,KAAK,CAAC;AAAA,EACzC;AAAA;AAAA,EAGA,aAAa,MAAoB;AAC/B,SAAK,aAAa;AAAA,EACpB;AACF;;;AC9iBA,SAAS,QAAQ,aAAa;AAOvB,IAAM,kBAAN,cAA8B,OAAO;AAAA,EAP5C,OAO4C;AAAA;AAAA;AAAA,EACjC,QAAQ,MAAM;AAAA,EACd,WAAW;AAAA,EAEpB,OAAO,IAAkB;AACvB,SAAK,IAAI,eAAe,EAAE,aAAa,EAAE;AAAA,EAC3C;AACF;;;ACdA,SAAS,UAAAA,SAAQ,SAAAC,cAAa;AAOvB,IAAM,mBAAN,cAA+BC,QAAO;AAAA,EAP7C,OAO6C;AAAA;AAAA;AAAA,EAClC,QAAQC,OAAM;AAAA,EACd,WAAW;AAAA,EAEpB,SAAe;AACb,SAAK,IAAI,eAAe,EAAE,iBAAiB;AAAA,EAC7C;AACF;;;ACPA,IAAM,iBAAiB;AACvB,IAAM,kBAAkB;AAGjB,IAAM,wBAAN,MAAwD;AAAA,EAI7D,YAA6B,SAAuB;AAAvB;AAAA,EAAwB;AAAA,EAAxB;AAAA,EAf/B,OAW+D;AAAA;AAAA;AAAA,EACpD,OAAO;AAAA,EACP,QAAQ,CAAC,WAAW,SAAS;AAAA,EAItC,UAAU,KAA0B;AAClC,QAAI,CAAC,IAAI,cAAc,SAAS,EAAG;AAEnC,UAAM,MAAM,KAAK,QAAQ,mBAAmB;AAC5C,UAAM,IAAI,IAAI,gBAAgB;AAC9B,QAAI,CAAC,EAAG;AAER,UAAM,OAAO,iBAAiB,IAAI;AAClC,UAAM,YAAY,IAAI,IAAI;AAC1B,MAAE,OAAO,IAAI,IAAI,MAAM,IAAI,CAAC,EACzB,OAAO,IAAI,IAAI,MAAM,IAAI,CAAC,EAC1B,OAAO,IAAI,GAAG,IAAI,IAAI,IAAI,EAC1B,OAAO,IAAI,GAAG,IAAI,IAAI,IAAI,EAC1B,OAAO,EAAE,OAAO,WAAW,OAAO,gBAAgB,CAAC;AAAA,EACxD;AAAA,EAEA,QAAQ,KAAwB;AAC9B,QAAI,CAAC,IAAI,cAAc,SAAS,EAAG;AAEnC,UAAM,UAAU,KAAK,QAClB,eAAe,EACf,OAAO,CAAC,WAAW,KAAK,QAAQ,UAAU,MAAM,CAAC;AAEpD,UAAM,QAAQ,QAAQ,SAAS,IAAI,QAAQ,KAAK,IAAI,IAAI;AACxD,QAAI,QAAQ,UAAU,KAAK,EAAE;AAE7B,UAAM,SAAS,KAAK,QAAQ,UAAU;AACtC,QAAI,OAAO,SAAS,GAAG;AACrB,YAAM,WAAW,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,QAAQ,eAAe,CAAC,CAAC;AACrE,UAAI,SAAS,SAAS,GAAG;AACvB,YAAI,QAAQ,oBAAoB,SAAS,KAAK,IAAI,CAAC,EAAE;AAAA,MACvD;AAAA,IACF;AAAA,EACF;AACF;;;AJ1CA,IAAM,mBAA2C;AAAA,EAC/C,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AACL;AAGO,IAAM,cAAN,MAAoC;AAAA,EAhB3C,OAgB2C;AAAA;AAAA;AAAA,EAChC,OAAO;AAAA,EACP,UAAU;AAAA,EAEF;AAAA,EACT;AAAA,EACA;AAAA,EACA,aAAgC,CAAC;AAAA,EAEzC,YAAY,QAAsB;AAChC,SAAK,SAAS,UAAU,CAAC;AAAA,EAC3B;AAAA,EAEA,QAAQ,SAA8B;AACpC,SAAK,UAAU;AACf,SAAK,UAAU,IAAI,aAAa;AAEhC,QAAI,KAAK,OAAO,SAAS;AACvB,WAAK,QAAQ,aAAa,KAAK,OAAO,OAAO;AAAA,IAC/C;AAEA,QAAI,KAAK,OAAO,QAAQ;AACtB,WAAK,QAAQ,UAAU,KAAK,OAAO,MAAM;AAAA,IAC3C;AAKA,UAAM,cAAc,KAAK,OAAO,eAAe;AAC/C,UAAM,WAAW,QAAQ,WAAW,WAAW;AAC/C,UAAM,gBACJ,KAAK,OAAO,UAAU,UAAU,UAAU;AAM5C,UAAM,oBACJ,UAAU,UACV,KAAK,OAAO,UACZ;AAMF,UAAM,aAAa,wBAAC,MAAc,SAChC,UAAU,kBAAkB,MAAM,IAAI,KAAK,EAAE,GAAG,MAAM,GAAG,KAAK,GAD7C;AAGnB,UAAM,aAAa,IAAI,IAAI,KAAK,OAAO,sBAAsB,CAAC,CAAC;AAG/D,UAAM,YAAY,wBAAC,MAAmB;AACpC,YAAM,KAAK;AACX,UAAI,GAAG,OAAQ;AACf,UAAI,WAAW,IAAI,GAAG,IAAI,EAAG,IAAG,eAAe;AAC/C,WAAK,QAAQ,WAAW,GAAG,IAAI;AAAA,IACjC,GALkB;AAMlB,UAAM,UAAU,wBAAC,MAAmB;AAClC,YAAM,KAAK;AACX,UAAI,WAAW,IAAI,GAAG,IAAI,EAAG,IAAG,eAAe;AAC/C,WAAK,QAAQ,SAAS,GAAG,IAAI;AAAA,IAC/B,GAJgB;AAKhB,WAAO,iBAAiB,WAAW,SAAS;AAC5C,WAAO,iBAAiB,SAAS,OAAO;AACxC,SAAK,WAAW;AAAA,MACd,MAAM,OAAO,oBAAoB,WAAW,SAAS;AAAA,MACrD,MAAM,OAAO,oBAAoB,SAAS,OAAO;AAAA,IACnD;AAIA,UAAM,gBAAgB,wBAAC,MAAmB;AACxC,YAAM,KAAK;AACX,UAAI;AACJ,UAAI;AACJ,UAAI,mBAAmB;AACrB,cAAM,OAAO,kBAAkB,sBAAsB;AACrD,eAAO,GAAG,UAAU,KAAK;AACzB,eAAO,GAAG,UAAU,KAAK;AAAA,MAC3B,OAAO;AACL,eAAO,GAAG;AACV,eAAO,GAAG;AAAA,MACZ;AACA,YAAM,SAAS,WAAW,MAAM,IAAI;AACpC,WAAK,QAAQ,eAAe,OAAO,GAAG,OAAO,CAAC;AAAA,IAChD,GAdsB;AAetB,UAAM,gBAAgB,wBAAC,MAAmB;AACxC,YAAM,KAAK;AACX,YAAM,SAAS,GAAG;AAClB,UAAI,UAAU,kBAAkB;AAC9B,aAAK,QAAQ,gBAAgB,MAAM;AAAA,MACrC,OAAO;AACL,aAAK,QAAQ,eAAe;AAAA,MAC9B;AAAA,IACF,GARsB;AAStB,UAAM,cAAc,wBAAC,MAAmB;AACtC,YAAM,KAAK;AACX,YAAM,SAAS,GAAG;AAClB,UAAI,UAAU,kBAAkB;AAC9B,aAAK,QAAQ,cAAc,MAAM;AAAA,MACnC,OAAO;AACL,aAAK,QAAQ,aAAa;AAAA,MAC5B;AAAA,IACF,GARoB;AASpB,UAAM,kBAAkB,6BAAY;AAClC,WAAK,QAAQ,oBAAoB;AAAA,IACnC,GAFwB;AAIxB,kBAAc,iBAAiB,eAAe,aAAa;AAC3D,WAAO,iBAAiB,eAAe,aAAa;AACpD,WAAO,iBAAiB,aAAa,WAAW;AAChD,WAAO,iBAAiB,iBAAiB,eAAe;AACxD,SAAK,WAAW;AAAA,MACd,MAAM,cAAc,oBAAoB,eAAe,aAAa;AAAA,MACpE,MAAM,OAAO,oBAAoB,eAAe,aAAa;AAAA,MAC7D,MAAM,OAAO,oBAAoB,aAAa,WAAW;AAAA,MACzD,MAAM,OAAO,oBAAoB,iBAAiB,eAAe;AAAA,IACnE;AAEA,YAAQ,SAAS,iBAAiB,KAAK,OAAO;AAAA,EAChD;AAAA,EAEA,gBAAgB,WAAkC;AAChD,cAAU,IAAI,IAAI,gBAAgB,CAAC;AACnC,cAAU,IAAI,IAAI,iBAAiB,CAAC;AAAA,EACtC;AAAA,EAEA,UAAgB;AACd,UAAM,WAAW,KAAK,QAAQ,WAAW,gBAAgB;AACzD,cAAU,SAAS,IAAI,sBAAsB,KAAK,OAAO,CAAC;AAAA,EAC5D;AAAA,EAEA,YAAkB;AAChB,eAAW,WAAW,KAAK,YAAY;AACrC,cAAQ;AAAA,IACV;AACA,SAAK,WAAW,SAAS;AAAA,EAC3B;AACF;;;AK3JA,IAAM,oBAA4C;AAAA;AAAA,EAEhD,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA;AAAA,EAGN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA;AAAA,EAGR,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA;AAAA,EAGL,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,cAAc;AAAA,EACd,SAAS;AAAA,EACT,UAAU;AAAA,EACV,UAAU;AAAA,EACV,WAAW;AAAA;AAAA,EAGX,SAAS;AAAA,EACT,WAAW;AAAA,EACX,WAAW;AAAA,EACX,YAAY;AAAA;AAAA,EAGZ,OAAO;AAAA,EACP,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,KAAK;AAAA,EACL,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,UAAU;AAAA,EACV,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,OAAO;AAAA,EACP,aAAa;AAAA;AAAA,EAGb,WAAW;AAAA,EACX,OAAO;AAAA,EACP,OAAO;AAAA,EACP,aAAa;AAAA,EACb,cAAc;AAAA,EACd,WAAW;AAAA,EACX,WAAW;AAAA,EACX,OAAO;AAAA,EACP,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,OAAO;AAAA;AAAA,EAGP,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,WAAW;AAAA,EACX,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,eAAe;AAAA,EACf,aAAa;AAAA;AAAA,EAGb,WAAW;AAAA,EACX,aAAa;AAAA,EACb,YAAY;AACd;AAGO,SAAS,kBAAkB,MAAsB;AACtD,SAAO,kBAAkB,IAAI,KAAK;AACpC;AAFgB;","names":["System","Phase","System","Phase"]}