@yagejs/input 0.3.0 → 0.5.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/api-BaItBbSe.d.cts +685 -0
- package/dist/api-BaItBbSe.d.ts +685 -0
- package/dist/api.cjs +34 -0
- package/dist/api.cjs.map +1 -0
- package/dist/api.d.cts +2 -0
- package/dist/api.d.ts +2 -0
- package/dist/api.js +7 -0
- package/dist/api.js.map +1 -0
- package/dist/chunk-O2U7FZ7Q.js +12 -0
- package/dist/chunk-O2U7FZ7Q.js.map +1 -0
- package/dist/index.cjs +1322 -56
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -164
- package/dist/index.d.ts +4 -164
- package/dist/index.js +1326 -62
- package/dist/index.js.map +1 -1
- package/package.json +13 -3
|
@@ -0,0 +1,685 @@
|
|
|
1
|
+
import { Vec2, RendererAdapter, ServiceKey } 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 syntheticPressedActions;
|
|
10
|
+
private syntheticActionStarts;
|
|
11
|
+
private actionMap;
|
|
12
|
+
private defaultBindings;
|
|
13
|
+
private groups;
|
|
14
|
+
private actionGroups;
|
|
15
|
+
private disabledGroups;
|
|
16
|
+
/** Tracked pointers keyed by `pointerId`. Mouse persists; touch/pen removed on up/cancel. */
|
|
17
|
+
private pointers;
|
|
18
|
+
/** Id of the pointer the browser last marked `isPrimary`, or `null` when none are tracked. */
|
|
19
|
+
private primaryPointerId;
|
|
20
|
+
/**
|
|
21
|
+
* Aggregate "any pointer has this button held" cache. The action-map codes
|
|
22
|
+
* `MouseLeft`/`MouseMiddle`/`MouseRight` are driven from edges into/out of this
|
|
23
|
+
* set so two simultaneous taps holding button 0 do not double-fire.
|
|
24
|
+
* Consumed pointers are excluded from the aggregate so UI-claimed presses
|
|
25
|
+
* never propagate to gameplay actions.
|
|
26
|
+
*/
|
|
27
|
+
private mouseButtonAggregate;
|
|
28
|
+
/**
|
|
29
|
+
* Pointers marked as "claimed" via {@link consumePointer} (or auto-claimed by
|
|
30
|
+
* the renderer's UI hit-test fallback). Lifetime is per-pointer-event-cycle:
|
|
31
|
+
* cleared when the pointer's last button releases (drained `pointerUp`) or on
|
|
32
|
+
* `pointercancel`.
|
|
33
|
+
*/
|
|
34
|
+
private consumedPointers;
|
|
35
|
+
/** Wheel-edge gate flipped by {@link consumeWheel}. Cleared at end of frame. */
|
|
36
|
+
private consumedWheelThisFrame;
|
|
37
|
+
/** Buffered DOM-originated events awaiting drain at `Phase.EarlyUpdate`. */
|
|
38
|
+
private inputQueue;
|
|
39
|
+
/**
|
|
40
|
+
* Renderer reference for the optional `hitTestUI(x, y)` lookup. Stashed by
|
|
41
|
+
* {@link _setRenderer} during `InputPlugin.install` so the drain step can
|
|
42
|
+
* read it cheaply each frame.
|
|
43
|
+
*/
|
|
44
|
+
private renderer;
|
|
45
|
+
private pointerDownListeners;
|
|
46
|
+
private pointerUpListeners;
|
|
47
|
+
private pointerMoveListeners;
|
|
48
|
+
private keyDownListenersAny;
|
|
49
|
+
private keyUpListenersAny;
|
|
50
|
+
private keyDownListeners;
|
|
51
|
+
private keyUpListeners;
|
|
52
|
+
private actionListeners;
|
|
53
|
+
private actionReleasedListeners;
|
|
54
|
+
private wheelListeners;
|
|
55
|
+
/** Real-pad axis values keyed by `${padIndex}:${axisKey}`. */
|
|
56
|
+
private gamepadAxisState;
|
|
57
|
+
/** Synthetic axis values for fireGamepadAxis injection (test path). */
|
|
58
|
+
private syntheticAxisState;
|
|
59
|
+
/** "Any pad" aggregate of currently-pressed gamepad codes. */
|
|
60
|
+
private lastButtonState;
|
|
61
|
+
/** Per-pad "anything happening" flag, used to detect rising-edge activity for active-pad promotion. */
|
|
62
|
+
private lastPadActivity;
|
|
63
|
+
/** Pads currently known to the engine (populated via events or polling). */
|
|
64
|
+
private connectedPads;
|
|
65
|
+
/** Index of the pad whose analog input is read by default. `null` when no pad is connected. */
|
|
66
|
+
private activePadIndex;
|
|
67
|
+
private gamepadConnectListeners;
|
|
68
|
+
private gamepadDisconnectListeners;
|
|
69
|
+
private activePadListeners;
|
|
70
|
+
private stickDeadzone;
|
|
71
|
+
private triggerDeadzone;
|
|
72
|
+
private triggerThreshold;
|
|
73
|
+
private pollingEnabled;
|
|
74
|
+
private camera;
|
|
75
|
+
private elapsedMs;
|
|
76
|
+
private listenResolve;
|
|
77
|
+
/** Whether any key mapped to this action is currently held. */
|
|
78
|
+
isPressed(action: string): boolean;
|
|
79
|
+
/** Whether any key mapped to this action was pressed this frame. */
|
|
80
|
+
isJustPressed(action: string): boolean;
|
|
81
|
+
/** Whether any key mapped to this action was released this frame. */
|
|
82
|
+
isJustReleased(action: string): boolean;
|
|
83
|
+
/** Returns true if any key bound to the action exists in the given set. */
|
|
84
|
+
private anyKeyInSet;
|
|
85
|
+
/** Milliseconds the action has been held. Returns 0 if not held. */
|
|
86
|
+
getHoldDuration(action: string): number;
|
|
87
|
+
/** Whether the action has been held for at least `minTime` ms. */
|
|
88
|
+
isHeldFor(action: string, minTime: number): boolean;
|
|
89
|
+
/** Returns -1, 0, or 1 based on negative/positive action states. */
|
|
90
|
+
getAxis(negative: string, positive: string): number;
|
|
91
|
+
/** Returns a Vec2 from four directional actions. Not normalized. */
|
|
92
|
+
getVector(left: string, right: string, up: string, down: string): Vec2;
|
|
93
|
+
/**
|
|
94
|
+
* Primary pointer's position in world coordinates (via Camera), or screen
|
|
95
|
+
* coords if no camera. Returns `Vec2.ZERO` when no pointer is tracked.
|
|
96
|
+
*
|
|
97
|
+
* For multi-pointer access (touch UIs etc.) iterate {@link getPointers} and
|
|
98
|
+
* convert each `screenPos` via the camera as needed.
|
|
99
|
+
*/
|
|
100
|
+
getPointerPosition(): Vec2;
|
|
101
|
+
/** Primary pointer's raw position in screen coordinates, or `Vec2.ZERO` when no pointer is tracked. */
|
|
102
|
+
getPointerScreenPosition(): Vec2;
|
|
103
|
+
/** Whether the primary pointer has any button held. */
|
|
104
|
+
isPointerDown(): boolean;
|
|
105
|
+
/** All currently-tracked pointers (one per active mouse, pen, or finger). */
|
|
106
|
+
getPointers(): readonly PointerInfo[];
|
|
107
|
+
/** Direct lookup by `pointerId`, or `undefined` if no pointer with that id is tracked. */
|
|
108
|
+
getPointer(id: number): PointerInfo | undefined;
|
|
109
|
+
/**
|
|
110
|
+
* Defensive snapshot of a tracked pointer. The runtime `MutablePointerInfo`
|
|
111
|
+
* holds a real `Set` for `buttons` — even though the `PointerInfo` type
|
|
112
|
+
* declares `ReadonlySet`, JS doesn't enforce that at runtime, so we copy the
|
|
113
|
+
* set on every public read. `Vec2` is convention-immutable across YAGE, so
|
|
114
|
+
* we share the same instance.
|
|
115
|
+
*/
|
|
116
|
+
private toPointerInfo;
|
|
117
|
+
/**
|
|
118
|
+
* Subscribe to pointer-down events (button transitions from up → down on a
|
|
119
|
+
* tracked pointer). Returns a disposer that detaches the listener.
|
|
120
|
+
*/
|
|
121
|
+
onPointerDown(fn: (info: PointerInfo) => void): () => void;
|
|
122
|
+
/**
|
|
123
|
+
* Subscribe to pointer-up events (button transitions from down → up, plus
|
|
124
|
+
* touch / pen lifecycle ends and `pointercancel`). Returns a disposer.
|
|
125
|
+
*/
|
|
126
|
+
onPointerUp(fn: (info: PointerInfo) => void): () => void;
|
|
127
|
+
/** Subscribe to pointer-move events. Returns a disposer. */
|
|
128
|
+
onPointerMove(fn: (info: PointerInfo) => void): () => void;
|
|
129
|
+
/**
|
|
130
|
+
* Mark a pointer as claimed for the rest of its event cycle (down → up).
|
|
131
|
+
* Subsequent action-map edges for this pointer (e.g. the `MouseLeft` edge a
|
|
132
|
+
* `pointerdown` would normally fire) are suppressed; `onPointerDown/Up/Move`
|
|
133
|
+
* listeners still fire because they are explicit user opt-ins.
|
|
134
|
+
*
|
|
135
|
+
* The mark clears automatically when the pointer's last button releases or
|
|
136
|
+
* on `pointercancel`. Call from a Pixi `pointerdown` handler that wants to
|
|
137
|
+
* own the event: `manager.consumePointer(e.pointerId)`.
|
|
138
|
+
*/
|
|
139
|
+
consumePointer(id: number): void;
|
|
140
|
+
/** Whether the pointer is currently marked consumed. */
|
|
141
|
+
isPointerConsumed(id: number): boolean;
|
|
142
|
+
/**
|
|
143
|
+
* Suppress wheel action-map edges (`WheelUp/Down/Left/Right`) for the rest
|
|
144
|
+
* of the current frame. `onWheel` listeners still fire.
|
|
145
|
+
*/
|
|
146
|
+
consumeWheel(): void;
|
|
147
|
+
/**
|
|
148
|
+
* Subscribe to key-down events. Pass a code (e.g. `"Space"`, `"GamepadA"`)
|
|
149
|
+
* to filter, or `"*"` for all keys. The listener fires on the same edge
|
|
150
|
+
* `isJustPressed` reports — for DOM-originated events that's the next
|
|
151
|
+
* `Phase.EarlyUpdate` after the browser dispatches; for synthetic injection
|
|
152
|
+
* (`fireKeyDown`) it's synchronous. Returns a disposer.
|
|
153
|
+
*/
|
|
154
|
+
onKeyDown(code: string, fn: (code: string) => void): () => void;
|
|
155
|
+
/** Subscribe to key-up events. See {@link onKeyDown}. */
|
|
156
|
+
onKeyUp(code: string, fn: (code: string) => void): () => void;
|
|
157
|
+
/**
|
|
158
|
+
* Subscribe to action press edges (rising edge of any key bound to the
|
|
159
|
+
* action). Fires once per press. Returns a disposer.
|
|
160
|
+
*/
|
|
161
|
+
onAction(name: string, fn: (name: string) => void): () => void;
|
|
162
|
+
/** Subscribe to action release edges. Returns a disposer. */
|
|
163
|
+
onActionReleased(name: string, fn: (name: string) => void): () => void;
|
|
164
|
+
/**
|
|
165
|
+
* Subscribe to scroll-wheel events. Receives raw `deltaX`/`deltaY` (already
|
|
166
|
+
* sign-flipped by `InputConfig.wheelInvertY` if set). Fires regardless of
|
|
167
|
+
* {@link consumeWheel} — it only gates action edges. Returns a disposer.
|
|
168
|
+
*/
|
|
169
|
+
onWheel(fn: (dx: number, dy: number) => void): () => void;
|
|
170
|
+
private getPrimaryPointer;
|
|
171
|
+
/** Replace the entire action map and store it as the default for {@link resetBindings}. */
|
|
172
|
+
setActionMap(actions: ActionMapDefinition): void;
|
|
173
|
+
/** Add a key binding to an action. Creates the action if it doesn't exist. */
|
|
174
|
+
bindKey(action: string, key: string): void;
|
|
175
|
+
/** Remove a key binding from an action. */
|
|
176
|
+
unbindKey(action: string, key: string): void;
|
|
177
|
+
/** Returns the current key bindings for an action, or an empty array if unmapped. */
|
|
178
|
+
getBindings(action: string): readonly string[];
|
|
179
|
+
/** Returns all action names that have the given key bound. */
|
|
180
|
+
getActionsForKey(key: string): string[];
|
|
181
|
+
/**
|
|
182
|
+
* Rebind a key to an action with optional conflict detection.
|
|
183
|
+
* Conflicts are only detected between actions sharing at least one group.
|
|
184
|
+
*/
|
|
185
|
+
rebind(action: string, key: string, opts?: RebindOptions): RebindResult;
|
|
186
|
+
/**
|
|
187
|
+
* Finds the first action that uses the given key AND shares at least one
|
|
188
|
+
* group with the target action. Ungrouped actions never conflict.
|
|
189
|
+
*/
|
|
190
|
+
private findConflictInGroups;
|
|
191
|
+
/** Reset bindings to defaults. If an action name is provided, only reset that action. */
|
|
192
|
+
resetBindings(action?: string): void;
|
|
193
|
+
/** Export the current bindings as a plain object for serialization. */
|
|
194
|
+
exportBindings(): ActionMapDefinition;
|
|
195
|
+
/** Load bindings from a plain object. Resets to defaults first, then overlays the provided map. */
|
|
196
|
+
loadBindings(map: ActionMapDefinition): void;
|
|
197
|
+
/** Configure input groups. Group name -> array of action names. */
|
|
198
|
+
setGroups(groups: Record<string, string[]>): void;
|
|
199
|
+
/** Enable a group by name. */
|
|
200
|
+
enableGroup(name: string): void;
|
|
201
|
+
/** Disable a group by name. Actions only in disabled groups become inactive. */
|
|
202
|
+
disableGroup(name: string): void;
|
|
203
|
+
/** Set exactly these groups as active; all others are disabled. */
|
|
204
|
+
setActiveGroups(names: string[]): void;
|
|
205
|
+
/** Whether a group is currently enabled. Returns true for unknown group names. */
|
|
206
|
+
isGroupEnabled(name: string): boolean;
|
|
207
|
+
/** Get all configured group names. */
|
|
208
|
+
getGroups(): string[];
|
|
209
|
+
/** Get the action names belonging to a group. Returns empty array for unknown groups. */
|
|
210
|
+
getGroupActions(name: string): readonly string[];
|
|
211
|
+
/** Returns true if the action is ungrouped or any of its groups is enabled. */
|
|
212
|
+
private isActionEnabled;
|
|
213
|
+
/** Returns a promise that resolves with the next key code pressed. Intercepts the key. */
|
|
214
|
+
listenForNextKey(): Promise<string | null>;
|
|
215
|
+
/** Cancel an active {@link listenForNextKey}. Resolves the pending promise with `null`. */
|
|
216
|
+
cancelListen(): void;
|
|
217
|
+
/** Public wrapper for synthetic key-down injection. Applies sync. */
|
|
218
|
+
fireKeyDown(code: string): void;
|
|
219
|
+
/** Public wrapper for synthetic key-up injection. Applies sync. */
|
|
220
|
+
fireKeyUp(code: string): void;
|
|
221
|
+
/**
|
|
222
|
+
* Public wrapper for synthetic pointer movement. Defaults to the primary
|
|
223
|
+
* mouse pointer (`id: 1`, `type: "mouse"`); pass `opts` to drive a specific
|
|
224
|
+
* touch / pen pointer.
|
|
225
|
+
*/
|
|
226
|
+
firePointerMove(screenX: number, screenY: number, opts?: {
|
|
227
|
+
id?: number;
|
|
228
|
+
type?: PointerType;
|
|
229
|
+
isPrimary?: boolean;
|
|
230
|
+
}): void;
|
|
231
|
+
/**
|
|
232
|
+
* Public wrapper for synthetic pointer-button presses. Defaults to button 0
|
|
233
|
+
* on the primary mouse pointer. Pass `opts` for touch / pen / non-primary
|
|
234
|
+
* pointers (e.g. `{ id: 5, type: "touch", isPrimary: false }`).
|
|
235
|
+
*/
|
|
236
|
+
firePointerDown(button?: 0 | 1 | 2, opts?: {
|
|
237
|
+
id?: number;
|
|
238
|
+
type?: PointerType;
|
|
239
|
+
isPrimary?: boolean;
|
|
240
|
+
}): void;
|
|
241
|
+
/** Public wrapper for synthetic pointer-button releases. */
|
|
242
|
+
firePointerUp(button?: 0 | 1 | 2, opts?: {
|
|
243
|
+
id?: number;
|
|
244
|
+
}): void;
|
|
245
|
+
/** Public wrapper for synthetic wheel input. Applies sync, including
|
|
246
|
+
* action edges and `onWheel` listener notification — matching the DOM path
|
|
247
|
+
* so tests and inspector probes drive the full surface. */
|
|
248
|
+
fireWheel(dx: number, dy: number): void;
|
|
249
|
+
private makeSyntheticInfo;
|
|
250
|
+
/**
|
|
251
|
+
* Inject a synthetic gamepad button edge. Routes through the same internal
|
|
252
|
+
* path as real polling, so action queries (`isPressed`, `isJustPressed`),
|
|
253
|
+
* `listenForNextKey`, and rebinding all see the synthetic input.
|
|
254
|
+
*
|
|
255
|
+
* `code` should be a gamepad code string (e.g. `"GamepadA"`, `"GamepadLT"`).
|
|
256
|
+
* Used by inspector probes / deterministic tests in lieu of real polling.
|
|
257
|
+
*/
|
|
258
|
+
fireGamepadButton(code: string, pressed: boolean): void;
|
|
259
|
+
/**
|
|
260
|
+
* Inject a synthetic gamepad axis value. Stored separately from real-pad
|
|
261
|
+
* axis state and consulted by `getStick` / `getTrigger` only when no real
|
|
262
|
+
* pad is active — matching how a test fixture would use the API.
|
|
263
|
+
*
|
|
264
|
+
* Trigger axes additionally emit `GamepadLT`/`GamepadRT` button edges when
|
|
265
|
+
* crossing `triggerThreshold`, mirroring real-pad polling so synthetic
|
|
266
|
+
* inspector probes drive `isPressed` the same way as physical hardware.
|
|
267
|
+
*/
|
|
268
|
+
fireGamepadAxis(side: GamepadAxisKey, value: number): void;
|
|
269
|
+
/**
|
|
270
|
+
* Returns the deadzoned, magnitude-clamped stick vector for the given side.
|
|
271
|
+
*
|
|
272
|
+
* By default reads from the active pad (the most recently used controller,
|
|
273
|
+
* or the first connected one if nothing has been used yet). Pass
|
|
274
|
+
* `{ pad: index }` to read from a specific pad — useful for couch-co-op
|
|
275
|
+
* where each player's controller is addressed explicitly.
|
|
276
|
+
*
|
|
277
|
+
* Falls back to synthetic injection (`fireGamepadAxis`) when no pad is
|
|
278
|
+
* active — that's the test/probe path.
|
|
279
|
+
*/
|
|
280
|
+
getStick(side: "left" | "right", opts?: {
|
|
281
|
+
pad?: number;
|
|
282
|
+
}): Vec2;
|
|
283
|
+
/**
|
|
284
|
+
* Returns the deadzoned trigger value (0..1) for the given side.
|
|
285
|
+
* Reads from the active pad by default; use `{ pad: index }` for explicit
|
|
286
|
+
* per-pad reads. Falls back to synthetic state when no pad is active.
|
|
287
|
+
*/
|
|
288
|
+
getTrigger(side: "left" | "right", opts?: {
|
|
289
|
+
pad?: number;
|
|
290
|
+
}): number;
|
|
291
|
+
/**
|
|
292
|
+
* Synchronously poll `navigator.getGamepads()` for currently-connected pads.
|
|
293
|
+
* Use this rather than the cached event-driven list when you need ground
|
|
294
|
+
* truth — `gamepadconnected` doesn't fire until the user presses a button.
|
|
295
|
+
*/
|
|
296
|
+
gamepads(): readonly GamepadInfo[];
|
|
297
|
+
/**
|
|
298
|
+
* Subscribe to gamepad-connected events. Replays currently-known pads
|
|
299
|
+
* synchronously so callers don't need a separate `gamepads()` call.
|
|
300
|
+
* Returns a disposer.
|
|
301
|
+
*/
|
|
302
|
+
onGamepadConnected(fn: (info: GamepadInfo) => void): () => void;
|
|
303
|
+
/** Subscribe to gamepad-disconnected events. Returns a disposer. */
|
|
304
|
+
onGamepadDisconnected(fn: (info: GamepadInfo) => void): () => void;
|
|
305
|
+
/**
|
|
306
|
+
* The pad whose analog input is read by default. Auto-promotes on input
|
|
307
|
+
* activity (button press or stick/trigger above deadzone) and on first
|
|
308
|
+
* connect. Returns `null` when no pad is connected.
|
|
309
|
+
*/
|
|
310
|
+
getActivePad(): GamepadInfo | null;
|
|
311
|
+
/**
|
|
312
|
+
* Manually set the active pad. Index must match a currently connected pad
|
|
313
|
+
* — pass an unknown index and the call is a no-op. Pass `null` to clear
|
|
314
|
+
* (analog reads will fall back to synthetic state if any).
|
|
315
|
+
*/
|
|
316
|
+
setActivePad(index: number | null): void;
|
|
317
|
+
/**
|
|
318
|
+
* Subscribe to active-pad changes. Replays the current active pad
|
|
319
|
+
* synchronously on subscribe so callers get the present state without a
|
|
320
|
+
* separate `getActivePad()` call. Returns a disposer.
|
|
321
|
+
*/
|
|
322
|
+
onActivePadChanged(fn: (info: GamepadInfo | null) => void): () => void;
|
|
323
|
+
private setActivePadInternal;
|
|
324
|
+
/** Enable or disable real gamepad polling. Synthetic injection still works when disabled. */
|
|
325
|
+
setPollingEnabled(enabled: boolean): void;
|
|
326
|
+
/** Whether real gamepad polling is currently enabled. */
|
|
327
|
+
isPollingEnabled(): boolean;
|
|
328
|
+
/**
|
|
329
|
+
* Update analog deadzones at runtime. Either field may be omitted.
|
|
330
|
+
* Values are clamped to `[0, 0.999]` — capping below 1 keeps the rescaling
|
|
331
|
+
* denominator non-zero. Non-finite values are ignored.
|
|
332
|
+
*/
|
|
333
|
+
setDeadzones(opts: {
|
|
334
|
+
stick?: number;
|
|
335
|
+
trigger?: number;
|
|
336
|
+
}): void;
|
|
337
|
+
/**
|
|
338
|
+
* Set the trigger button-edge threshold (default 0.5). Clamped to `[0, 1]`;
|
|
339
|
+
* non-finite values are ignored.
|
|
340
|
+
*/
|
|
341
|
+
setTriggerThreshold(value: number): void;
|
|
342
|
+
/**
|
|
343
|
+
* @internal Force-release held gamepad buttons and clear real-pad analog
|
|
344
|
+
* snapshots. Used on tab-hide (where `navigator.getGamepads()` returns
|
|
345
|
+
* stale data) and on disconnect when polling is paused. Synthetic axes
|
|
346
|
+
* live in their own field, so they're untouched.
|
|
347
|
+
*/
|
|
348
|
+
_releaseAllGamepadState(): void;
|
|
349
|
+
/** @internal Called by InputPlugin from `gamepadconnected` event or by
|
|
350
|
+
* polling when discovering a previously-unknown pad. Idempotent. */
|
|
351
|
+
_onGamepadConnected(info: GamepadInfo): void;
|
|
352
|
+
/** @internal Called by InputPlugin from `gamepaddisconnected` event or by
|
|
353
|
+
* polling when a pad vanishes silently. Idempotent. */
|
|
354
|
+
_onGamepadDisconnected(info: GamepadInfo): void;
|
|
355
|
+
/**
|
|
356
|
+
* @internal Poll real gamepads via `navigator.getGamepads()` and emit
|
|
357
|
+
* key-down/key-up edges for any aggregate state changes. Called by
|
|
358
|
+
* `InputPollSystem` once per frame.
|
|
359
|
+
*/
|
|
360
|
+
_pollGamepads(): void;
|
|
361
|
+
/** Whether a pad has any input that should claim active-pad ownership. */
|
|
362
|
+
private padHasActivity;
|
|
363
|
+
/**
|
|
364
|
+
* Aggregate "any pad pressed" per code across the supplied pad list and
|
|
365
|
+
* emit `_applyKeyDown`/`_applyKeyUp` edges. `lastButtonState` is updated
|
|
366
|
+
* unconditionally so listen-mode interception doesn't cause held-button
|
|
367
|
+
* re-fires on subsequent frames.
|
|
368
|
+
*/
|
|
369
|
+
private reconcileButtonStateAcrossPads;
|
|
370
|
+
/** Inject a one-frame synthetic action pulse. */
|
|
371
|
+
fireAction(name: string): void;
|
|
372
|
+
/** Release all synthetic and physical input state. */
|
|
373
|
+
clearAll(): void;
|
|
374
|
+
/**
|
|
375
|
+
* Drop all tracked pointers and release the aggregate `MouseLeft/Middle/Right`
|
|
376
|
+
* codes without touching keyboard or gamepad state. Useful for window-blur
|
|
377
|
+
* / page-hide handling.
|
|
378
|
+
*/
|
|
379
|
+
clearPointerButtons(): void;
|
|
380
|
+
/** Snapshot of current held input state for inspector tooling. */
|
|
381
|
+
snapshotState(): {
|
|
382
|
+
keys: string[];
|
|
383
|
+
actions: string[];
|
|
384
|
+
mouse: {
|
|
385
|
+
x: number;
|
|
386
|
+
y: number;
|
|
387
|
+
buttons: number[];
|
|
388
|
+
down: boolean;
|
|
389
|
+
};
|
|
390
|
+
pointers: Array<{
|
|
391
|
+
id: number;
|
|
392
|
+
x: number;
|
|
393
|
+
y: number;
|
|
394
|
+
type: PointerType;
|
|
395
|
+
isPrimary: boolean;
|
|
396
|
+
buttons: number[];
|
|
397
|
+
down: boolean;
|
|
398
|
+
}>;
|
|
399
|
+
gamepad: {
|
|
400
|
+
buttons: string[];
|
|
401
|
+
axes: Array<{
|
|
402
|
+
key: string;
|
|
403
|
+
value: number;
|
|
404
|
+
}>;
|
|
405
|
+
};
|
|
406
|
+
};
|
|
407
|
+
/**
|
|
408
|
+
* @internal Stash the renderer adapter so the drain step can call its
|
|
409
|
+
* optional `hitTestUI(x, y)` for the auto-consume fallback. Called by
|
|
410
|
+
* `InputPlugin.install`.
|
|
411
|
+
*/
|
|
412
|
+
_setRenderer(renderer: RendererAdapter | null): void;
|
|
413
|
+
/** @internal */
|
|
414
|
+
_enqueueKeyDown(code: string): void;
|
|
415
|
+
/** @internal */
|
|
416
|
+
_enqueueKeyUp(code: string): void;
|
|
417
|
+
/**
|
|
418
|
+
* @internal Sync portion: upsert the pointer entry (existence, screenPos,
|
|
419
|
+
* type, isPrimary, primaryPointerId) and notify pointerMoveListeners so
|
|
420
|
+
* pointer-tracking UIs see live cursor positions. Move events do not carry
|
|
421
|
+
* action-map edges, so they are not queued.
|
|
422
|
+
*/
|
|
423
|
+
_enqueuePointerMove(info: PointerEventInfo): void;
|
|
424
|
+
/**
|
|
425
|
+
* @internal Sync portion: upsert pointer (existence, screenPos, type,
|
|
426
|
+
* isPrimary, primaryPointerId) and notify pointerDownListeners. Button
|
|
427
|
+
* mutation, action-map edges, and mouse-aggregate emit are deferred to the
|
|
428
|
+
* next drain at `Phase.EarlyUpdate` so {@link consumePointer} (or the
|
|
429
|
+
* renderer's UI hit-test) can suppress them, AND so a same-frame
|
|
430
|
+
* down+up that arrives before drain still produces the correct
|
|
431
|
+
* `MouseLeft` press/release edges (recomputing aggregate from live state
|
|
432
|
+
* after sync mutation would silently drop the transient transition).
|
|
433
|
+
*
|
|
434
|
+
* Listeners therefore observe `pointer.buttons` BEFORE this event's edge is
|
|
435
|
+
* applied. That's a documented tradeoff: the canonical event-button info
|
|
436
|
+
* is in the `FederatedPointerEvent` / `PointerEvent` the user's Pixi
|
|
437
|
+
* handler already receives, so the lossy `info.buttons` view rarely
|
|
438
|
+
* matters in practice.
|
|
439
|
+
*/
|
|
440
|
+
_enqueuePointerDown(info: PointerEventInfo): void;
|
|
441
|
+
/** @internal */
|
|
442
|
+
_enqueuePointerUp(info: PointerEventInfo): void;
|
|
443
|
+
/** @internal */
|
|
444
|
+
_enqueuePointerCancel(id: number): void;
|
|
445
|
+
/** @internal */
|
|
446
|
+
_enqueueWheel(dx: number, dy: number): void;
|
|
447
|
+
/**
|
|
448
|
+
* @internal Drain queued DOM events at `Phase.EarlyUpdate`. Each event
|
|
449
|
+
* applies its deferred state (button mutations, action-map edges,
|
|
450
|
+
* mouse-aggregate transitions). Consumed pointers are excluded from the
|
|
451
|
+
* mouse aggregate so UI-claimed presses do not propagate to gameplay
|
|
452
|
+
* actions. The renderer's optional `hitTestUI(x, y)` auto-claims a pointer
|
|
453
|
+
* whose `pointerdown` lands on a UI-marked container.
|
|
454
|
+
*/
|
|
455
|
+
_drainInputQueue(): void;
|
|
456
|
+
private drainPointerDown;
|
|
457
|
+
private drainPointerUp;
|
|
458
|
+
private drainPointerCancel;
|
|
459
|
+
private applyWheelEdges;
|
|
460
|
+
/**
|
|
461
|
+
* Add a code to `justPressedKeys` without entering `pressedKeys`. Used for
|
|
462
|
+
* discrete edges (wheel ticks) that are never "held". Listeners and
|
|
463
|
+
* `listenForNextKey` still fire as usual.
|
|
464
|
+
*/
|
|
465
|
+
private fireOneFrameEdge;
|
|
466
|
+
/**
|
|
467
|
+
* @internal Synthetic key-down. DOM-originated events must use
|
|
468
|
+
* {@link _enqueueKeyDown} so `consumePointer` and the UI hit-test fallback
|
|
469
|
+
* have a chance to run before action edges fire.
|
|
470
|
+
*/
|
|
471
|
+
_applyKeyDown(code: string): void;
|
|
472
|
+
/**
|
|
473
|
+
* @internal Synthetic key-up. DOM-originated events must use
|
|
474
|
+
* {@link _enqueueKeyUp}.
|
|
475
|
+
*/
|
|
476
|
+
_applyKeyUp(code: string): void;
|
|
477
|
+
/**
|
|
478
|
+
* @internal Synthetic pointer move. DOM-originated events must use
|
|
479
|
+
* {@link _enqueuePointerMove}.
|
|
480
|
+
*/
|
|
481
|
+
_applyPointerMove(info: PointerEventInfo): void;
|
|
482
|
+
/**
|
|
483
|
+
* @internal Synthetic pointer down. DOM-originated events must use
|
|
484
|
+
* {@link _enqueuePointerDown}. This applies all state (button mutation,
|
|
485
|
+
* mouse-aggregate emit, listener notify) synchronously.
|
|
486
|
+
*/
|
|
487
|
+
_applyPointerDown(info: PointerEventInfo): void;
|
|
488
|
+
/**
|
|
489
|
+
* @internal Synthetic pointer up. DOM-originated events must use
|
|
490
|
+
* {@link _enqueuePointerUp}.
|
|
491
|
+
*/
|
|
492
|
+
_applyPointerUp(info: PointerEventInfo): void;
|
|
493
|
+
/**
|
|
494
|
+
* @internal Synthetic pointer cancel. Clears all buttons on the pointer,
|
|
495
|
+
* fires up-listeners, and drops the entry (unless it's a mouse). Mirrors
|
|
496
|
+
* the drain-time {@link drainPointerCancel} logic.
|
|
497
|
+
*/
|
|
498
|
+
_applyPointerCancel(id: number): void;
|
|
499
|
+
private upsertPointer;
|
|
500
|
+
private removePointer;
|
|
501
|
+
/**
|
|
502
|
+
* Recompute the `MouseLeft/Middle/Right` aggregate edge for `button`.
|
|
503
|
+
* Consumed pointers are excluded so a UI-claimed press never propagates to
|
|
504
|
+
* gameplay actions, even if a second non-UI pointer simultaneously holds
|
|
505
|
+
* the same button.
|
|
506
|
+
*/
|
|
507
|
+
private recomputeMouseAggregate;
|
|
508
|
+
private notifyPointerListeners;
|
|
509
|
+
private notifyKeyListeners;
|
|
510
|
+
private notifyActionListeners;
|
|
511
|
+
/**
|
|
512
|
+
* Action names that include `code` in their bindings AND whose group is
|
|
513
|
+
* currently enabled. Used for `onAction` / `onActionReleased` listener
|
|
514
|
+
* fan-out so disabled-group suppression matches `isPressed` behavior.
|
|
515
|
+
*/
|
|
516
|
+
private actionsForCode;
|
|
517
|
+
/** @internal Clear per-frame justPressed/justReleased flags. */
|
|
518
|
+
_clearFrameState(): void;
|
|
519
|
+
/** Set camera for pointer world-coord conversion. */
|
|
520
|
+
setCamera(camera: CameraLike): void;
|
|
521
|
+
/** Clear the camera reference (e.g. on scene exit). */
|
|
522
|
+
clearCamera(): void;
|
|
523
|
+
/** Get all configured action names. */
|
|
524
|
+
getActionNames(): string[];
|
|
525
|
+
/** @internal Advance the elapsed game-time clock. Called by InputPollSystem. */
|
|
526
|
+
_advanceTime(dtMs: number): void;
|
|
527
|
+
/** @internal Sync alias — see {@link _applyKeyDown}. */
|
|
528
|
+
_onKeyDown(code: string): void;
|
|
529
|
+
/** @internal Sync alias — see {@link _applyKeyUp}. */
|
|
530
|
+
_onKeyUp(code: string): void;
|
|
531
|
+
/** @internal Sync alias — see {@link _applyPointerMove}. */
|
|
532
|
+
_onPointerMove(info: PointerEventInfo): void;
|
|
533
|
+
/** @internal Sync alias — see {@link _applyPointerDown}. */
|
|
534
|
+
_onPointerDown(info: PointerEventInfo): void;
|
|
535
|
+
/** @internal Sync alias — see {@link _applyPointerUp}. */
|
|
536
|
+
_onPointerUp(info: PointerEventInfo): void;
|
|
537
|
+
/** @internal Sync alias — see {@link _applyPointerCancel}. */
|
|
538
|
+
_onPointerCancel(id: number): void;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/** Service key for the InputManager. */
|
|
542
|
+
declare const InputManagerKey: ServiceKey<InputManager>;
|
|
543
|
+
/** Minimal camera surface needed by InputManager for pointer world-coord conversion. */
|
|
544
|
+
interface CameraLike {
|
|
545
|
+
screenToWorld(screenX: number, screenY: number): {
|
|
546
|
+
x: number;
|
|
547
|
+
y: number;
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Minimal renderer surface needed by InputPlugin for canvas access and
|
|
552
|
+
* coordinate mapping. Alias of the cross-package `RendererAdapter` contract.
|
|
553
|
+
*/
|
|
554
|
+
type RendererLike = RendererAdapter;
|
|
555
|
+
/** Configuration for the InputPlugin. */
|
|
556
|
+
interface InputConfig {
|
|
557
|
+
/** Target element for pointer events (default: canvas from renderer, or document). */
|
|
558
|
+
target?: HTMLElement;
|
|
559
|
+
/** Action map: action name -> array of physical key codes. */
|
|
560
|
+
actions?: ActionMapDefinition;
|
|
561
|
+
/** Input groups: group name -> array of action names belonging to it. */
|
|
562
|
+
groups?: Record<string, string[]>;
|
|
563
|
+
/** Key codes to call preventDefault() on (default: none). */
|
|
564
|
+
preventDefaultKeys?: string[];
|
|
565
|
+
/**
|
|
566
|
+
* Optional override for the renderer service key. When omitted, InputPlugin
|
|
567
|
+
* auto-resolves `RendererAdapterKey` — the canonical `@yagejs/renderer`
|
|
568
|
+
* plugin registers itself under that key, so pointer events target its
|
|
569
|
+
* canvas and coordinates route through `canvasToVirtual` out of the box.
|
|
570
|
+
* Set this only if you ship a custom renderer registered under a different
|
|
571
|
+
* key.
|
|
572
|
+
*/
|
|
573
|
+
rendererKey?: ServiceKey<RendererAdapter>;
|
|
574
|
+
/** Deadzone thresholds for analog inputs. */
|
|
575
|
+
deadzones?: {
|
|
576
|
+
/** Radial deadzone applied to stick magnitude (default 0.15). */
|
|
577
|
+
stick?: number;
|
|
578
|
+
/** Lower deadzone for trigger analog values (default 0.05). */
|
|
579
|
+
trigger?: number;
|
|
580
|
+
};
|
|
581
|
+
/**
|
|
582
|
+
* Trigger value at which `GamepadLT`/`GamepadRT` fire as button edges in the
|
|
583
|
+
* action map (default 0.5). Below this, the trigger remains "released" for
|
|
584
|
+
* `isPressed` purposes; the analog `getTrigger` value is unaffected.
|
|
585
|
+
*/
|
|
586
|
+
triggerThreshold?: number;
|
|
587
|
+
/**
|
|
588
|
+
* Whether to poll `navigator.getGamepads()` each frame (default `true`).
|
|
589
|
+
* Disable to use only synthetic input via `fireGamepadButton`/`fireGamepadAxis`
|
|
590
|
+
* — useful for inspector probes that want deterministic state.
|
|
591
|
+
*/
|
|
592
|
+
pollGamepads?: boolean;
|
|
593
|
+
/**
|
|
594
|
+
* Invert vertical scroll so positive `dy` means up (default `false`,
|
|
595
|
+
* matching the W3C convention where positive `deltaY` is "scroll content
|
|
596
|
+
* down"). Affects both `onWheel` callbacks and `WheelUp/Down` action edges.
|
|
597
|
+
*/
|
|
598
|
+
wheelInvertY?: boolean;
|
|
599
|
+
/**
|
|
600
|
+
* Call `preventDefault()` on incoming wheel events so the page does not
|
|
601
|
+
* scroll. Default `false` — opt in only if your game canvas should swallow
|
|
602
|
+
* scroll. The listener is attached as `{ passive: false }` when this is
|
|
603
|
+
* enabled so `preventDefault()` actually takes effect.
|
|
604
|
+
*/
|
|
605
|
+
preventDefaultWheel?: boolean;
|
|
606
|
+
}
|
|
607
|
+
/** Information about a connected gamepad. */
|
|
608
|
+
interface GamepadInfo {
|
|
609
|
+
/** Index in `navigator.getGamepads()`. May change if pads are hot-swapped. */
|
|
610
|
+
index: number;
|
|
611
|
+
/** Browser-reported gamepad identifier (vendor + product). */
|
|
612
|
+
id: string;
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* Named gamepad analog axis. Sticks are exposed per axis (`leftX`/`leftY`,
|
|
616
|
+
* etc.); triggers (`leftTrigger`/`rightTrigger`) carry the W3C
|
|
617
|
+
* `GamepadButton.value` for buttons 6/7 under standard mapping.
|
|
618
|
+
*/
|
|
619
|
+
type GamepadAxisKey = "leftX" | "leftY" | "rightX" | "rightY" | "leftTrigger" | "rightTrigger";
|
|
620
|
+
/**
|
|
621
|
+
* Class of physical pointer device. Sourced from `PointerEvent.pointerType` on
|
|
622
|
+
* real input; defaults to `"mouse"` for synthetic injection.
|
|
623
|
+
*/
|
|
624
|
+
type PointerType = "mouse" | "pen" | "touch";
|
|
625
|
+
/**
|
|
626
|
+
* Read-only view of a tracked pointer. Returned from {@link InputManager.getPointers}
|
|
627
|
+
* and the per-pointer event hooks. Treat as immutable — fields reflect the
|
|
628
|
+
* pointer's state at query time and are not retained between frames.
|
|
629
|
+
*/
|
|
630
|
+
interface PointerInfo {
|
|
631
|
+
/** Browser-assigned `PointerEvent.pointerId`, or the synthetic id passed via `firePointer*`. */
|
|
632
|
+
readonly id: number;
|
|
633
|
+
/** Position in screen-space pixels (already routed through `canvasToVirtual` if available). */
|
|
634
|
+
readonly screenPos: Vec2;
|
|
635
|
+
/** Source device class. */
|
|
636
|
+
readonly type: PointerType;
|
|
637
|
+
/** Whether the browser flagged this as the primary pointer (`PointerEvent.isPrimary`). */
|
|
638
|
+
readonly isPrimary: boolean;
|
|
639
|
+
/** Currently-held button indices (0=left/primary, 1=middle, 2=right). */
|
|
640
|
+
readonly buttons: ReadonlySet<number>;
|
|
641
|
+
/** Convenience mirror of `buttons.size > 0`. */
|
|
642
|
+
readonly isDown: boolean;
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Per-event payload assembled by {@link InputPlugin} from each `PointerEvent`
|
|
646
|
+
* (or by `firePointer*` for synthetic injection) and forwarded to the manager's
|
|
647
|
+
* internal pointer handlers.
|
|
648
|
+
*
|
|
649
|
+
* @internal
|
|
650
|
+
*/
|
|
651
|
+
interface PointerEventInfo {
|
|
652
|
+
id: number;
|
|
653
|
+
screenX: number;
|
|
654
|
+
screenY: number;
|
|
655
|
+
type: PointerType;
|
|
656
|
+
isPrimary: boolean;
|
|
657
|
+
/**
|
|
658
|
+
* The button whose state changed for this event. `-1` for events that don't
|
|
659
|
+
* change button state (move-only). Down/up handlers ignore `-1`.
|
|
660
|
+
*/
|
|
661
|
+
button: number;
|
|
662
|
+
}
|
|
663
|
+
/** Maps action names to arrays of physical key codes. */
|
|
664
|
+
type ActionMapDefinition = Record<string, string[]>;
|
|
665
|
+
/** How to handle a conflict when rebinding a key already used by another action in the same group. */
|
|
666
|
+
type InputConflictPolicy = "replace" | "keep-both" | "reject";
|
|
667
|
+
/** Options for {@link InputManager.rebind}. */
|
|
668
|
+
interface RebindOptions {
|
|
669
|
+
/** Index of the binding slot to replace. Appends if the slot does not exist. */
|
|
670
|
+
slot?: number;
|
|
671
|
+
/** How to resolve conflicts with other actions in the same group(s). Default: `"reject"`. */
|
|
672
|
+
conflict?: InputConflictPolicy;
|
|
673
|
+
}
|
|
674
|
+
/** Result of a {@link InputManager.rebind} call. */
|
|
675
|
+
interface RebindResult {
|
|
676
|
+
/** Whether the rebind succeeded. */
|
|
677
|
+
ok: boolean;
|
|
678
|
+
/** Present when `ok` is false due to a conflict with `conflict: "reject"`. */
|
|
679
|
+
conflict?: {
|
|
680
|
+
action: string;
|
|
681
|
+
key: string;
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
export { type ActionMapDefinition as A, type CameraLike as C, type GamepadAxisKey as G, type InputConfig as I, type PointerInfo as P, type RebindOptions as R, type GamepadInfo as a, type InputConflictPolicy as b, InputManager as c, InputManagerKey as d, type PointerType as e, type RebindResult as f, type RendererLike as g };
|