@forgeax/engine-input 0.1.2
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/LICENSE +202 -0
- package/README.md +312 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/__tests__/browser-backend-dual-instance.test.d.ts +2 -0
- package/dist/__tests__/browser-backend-dual-instance.test.d.ts.map +1 -0
- package/dist/__tests__/browser-backend-focus-loss.test.d.ts +2 -0
- package/dist/__tests__/browser-backend-focus-loss.test.d.ts.map +1 -0
- package/dist/__tests__/browser-backend-lock-error.test.d.ts +2 -0
- package/dist/__tests__/browser-backend-lock-error.test.d.ts.map +1 -0
- package/dist/__tests__/browser-backend-lock-gate.test.d.ts +2 -0
- package/dist/__tests__/browser-backend-lock-gate.test.d.ts.map +1 -0
- package/dist/__tests__/browser-backend-lock-release.test.d.ts +2 -0
- package/dist/__tests__/browser-backend-lock-release.test.d.ts.map +1 -0
- package/dist/__tests__/browser-backend-lock-state.test.d.ts +2 -0
- package/dist/__tests__/browser-backend-lock-state.test.d.ts.map +1 -0
- package/dist/__tests__/canvas-input-boundary.test.d.ts +2 -0
- package/dist/__tests__/canvas-input-boundary.test.d.ts.map +1 -0
- package/dist/__tests__/canvas-input-owner.test-d.d.ts +2 -0
- package/dist/__tests__/canvas-input-owner.test-d.d.ts.map +1 -0
- package/dist/__tests__/composite-backend.test.d.ts +2 -0
- package/dist/__tests__/composite-backend.test.d.ts.map +1 -0
- package/dist/__tests__/controller-platform-owner.test-d.d.ts +2 -0
- package/dist/__tests__/controller-platform-owner.test-d.d.ts.map +1 -0
- package/dist/__tests__/input-snapshot.test-d.d.ts +2 -0
- package/dist/__tests__/input-snapshot.test-d.d.ts.map +1 -0
- package/dist/__tests__/input-snapshot.test.d.ts +2 -0
- package/dist/__tests__/input-snapshot.test.d.ts.map +1 -0
- package/dist/__tests__/swipe-direction-owner.test-d.d.ts +2 -0
- package/dist/__tests__/swipe-direction-owner.test-d.d.ts.map +1 -0
- package/dist/__tests__/ui-input-matrix.test.d.ts +2 -0
- package/dist/__tests__/ui-input-matrix.test.d.ts.map +1 -0
- package/dist/__tests__/ui-ownership-edge.test.d.ts +2 -0
- package/dist/__tests__/ui-ownership-edge.test.d.ts.map +1 -0
- package/dist/__tests__/ui-ownership.test.d.ts +2 -0
- package/dist/__tests__/ui-ownership.test.d.ts.map +1 -0
- package/dist/__tests__/ui-reset-idempotence.test.d.ts +2 -0
- package/dist/__tests__/ui-reset-idempotence.test.d.ts.map +1 -0
- package/dist/__tests__/ui-reset.test.d.ts +2 -0
- package/dist/__tests__/ui-reset.test.d.ts.map +1 -0
- package/dist/action-state.d.ts +146 -0
- package/dist/action-state.d.ts.map +1 -0
- package/dist/browser-backend.d.ts +121 -0
- package/dist/browser-backend.d.ts.map +1 -0
- package/dist/canvas-input-boundary.d.ts +13 -0
- package/dist/canvas-input-boundary.d.ts.map +1 -0
- package/dist/composite-backend.d.ts +34 -0
- package/dist/composite-backend.d.ts.map +1 -0
- package/dist/controller-db-data.d.ts +5 -0
- package/dist/controller-db-data.d.ts.map +1 -0
- package/dist/controller-db-data.mjs +12 -0
- package/dist/controller-db-data.mjs.map +1 -0
- package/dist/controller-db.d.ts +70 -0
- package/dist/controller-db.d.ts.map +1 -0
- package/dist/controller-db.mjs +119 -0
- package/dist/controller-db.mjs.map +1 -0
- package/dist/frame-start-scan-system.d.ts +37 -0
- package/dist/frame-start-scan-system.d.ts.map +1 -0
- package/dist/gamepad-frame.d.ts +42 -0
- package/dist/gamepad-frame.d.ts.map +1 -0
- package/dist/gesture-recognizer.d.ts +145 -0
- package/dist/gesture-recognizer.d.ts.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +1502 -0
- package/dist/index.mjs.map +1 -0
- package/dist/input-snapshot.d.ts +420 -0
- package/dist/input-snapshot.d.ts.map +1 -0
- package/dist/plugin-service.d.ts +11 -0
- package/dist/plugin-service.d.ts.map +1 -0
- package/dist/ui-ownership.d.ts +17 -0
- package/dist/ui-ownership.d.ts.map +1 -0
- package/dist/virtual-joystick.d.ts +39 -0
- package/dist/virtual-joystick.d.ts.map +1 -0
- package/package.json +72 -0
- package/src/__tests__/browser-backend-dual-instance.test.ts +379 -0
- package/src/__tests__/browser-backend-focus-loss.test.ts +239 -0
- package/src/__tests__/browser-backend-lock-error.test.ts +425 -0
- package/src/__tests__/browser-backend-lock-gate.test.ts +283 -0
- package/src/__tests__/browser-backend-lock-release.test.ts +641 -0
- package/src/__tests__/browser-backend-lock-state.test.ts +604 -0
- package/src/__tests__/canvas-input-boundary.test.ts +65 -0
- package/src/__tests__/canvas-input-owner.test-d.ts +39 -0
- package/src/__tests__/composite-backend.test.ts +299 -0
- package/src/__tests__/controller-platform-owner.test-d.ts +46 -0
- package/src/__tests__/input-snapshot.test-d.ts +78 -0
- package/src/__tests__/input-snapshot.test.ts +96 -0
- package/src/__tests__/swipe-direction-owner.test-d.ts +45 -0
- package/src/__tests__/ui-input-matrix.test.ts +31 -0
- package/src/__tests__/ui-ownership-edge.test.ts +33 -0
- package/src/__tests__/ui-ownership.test.ts +35 -0
- package/src/__tests__/ui-reset-idempotence.test.ts +17 -0
- package/src/__tests__/ui-reset.test.ts +25 -0
- package/src/action-state.ts +380 -0
- package/src/browser-backend.ts +884 -0
- package/src/canvas-input-boundary.ts +81 -0
- package/src/composite-backend.ts +189 -0
- package/src/controller-db-data.ts +25 -0
- package/src/controller-db.ts +218 -0
- package/src/frame-start-scan-system.ts +93 -0
- package/src/gamepad-frame.ts +259 -0
- package/src/gesture-recognizer.ts +495 -0
- package/src/index.ts +101 -0
- package/src/input-snapshot.ts +732 -0
- package/src/plugin-service.ts +31 -0
- package/src/ui-ownership.ts +61 -0
- package/src/virtual-joystick.ts +103 -0
- package/vendor/gamecontrollerdb.txt +2114 -0
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
import type { ActionConfig, ActionState, GetVectorOptions } from './action-state';
|
|
2
|
+
import type { GestureEvent, GestureState } from './gesture-recognizer';
|
|
3
|
+
export type PointerType = 'mouse' | 'pen' | 'touch';
|
|
4
|
+
/** Standard-layout gamepad button index (0-16 per W3C Gamepad spec). */
|
|
5
|
+
export type GamepadButtonIndex = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16;
|
|
6
|
+
/** Standard-layout gamepad axis index (0-3 per W3C Gamepad spec). */
|
|
7
|
+
export type GamepadAxisIndex = 0 | 1 | 2 | 3;
|
|
8
|
+
/** W3C MouseEvent.button index (0=primary, 1=auxiliary, 2=secondary). */
|
|
9
|
+
export type MouseButtonIndex = 0 | 1 | 2;
|
|
10
|
+
/** Per-slot gamepad frame data produced by `sample()`. */
|
|
11
|
+
export interface GamepadSlotSample {
|
|
12
|
+
readonly index: number;
|
|
13
|
+
/**
|
|
14
|
+
* True when the browser reports a standard mapping OR the SDL controller
|
|
15
|
+
* DB has normalized a non-standard layout at the acquisition layer (M3
|
|
16
|
+
* D-1 redefinition). The Feat1 meaning ("browser-reported standard
|
|
17
|
+
* mapping only") is widened here: a non-standard pad whose GUID matches
|
|
18
|
+
* gamecontrollerdb.txt is re-projected onto the standard layout and
|
|
19
|
+
* reported as standardMapping=true, so bindings and direct reads see a
|
|
20
|
+
* uniform standard button/axis space. A non-standard pad with no DB match
|
|
21
|
+
* (or before the DB has loaded) keeps standardMapping=false + empty
|
|
22
|
+
* readpoints (graceful degradation).
|
|
23
|
+
*/
|
|
24
|
+
readonly standardMapping: boolean;
|
|
25
|
+
readonly pressed: ReadonlySet<number>;
|
|
26
|
+
readonly justPressed: ReadonlySet<number>;
|
|
27
|
+
readonly justReleased: ReadonlySet<number>;
|
|
28
|
+
readonly buttonValues: ReadonlyMap<number, number>;
|
|
29
|
+
readonly axes: readonly [number, number, number, number];
|
|
30
|
+
}
|
|
31
|
+
/** Per-pointer live state (active contacts tracked by pointerId).
|
|
32
|
+
*
|
|
33
|
+
* D-5 / E-10: `pointerType` is a 3-literal union. `'mouse'` is the default
|
|
34
|
+
* placeholder for inactive pointers — when `active=false`, `pointerType` is
|
|
35
|
+
* always `'mouse'`. The semantic "no pointer" is carried by the `active`
|
|
36
|
+
* field, never by a sentinel string value.
|
|
37
|
+
*/
|
|
38
|
+
export interface PointerSample {
|
|
39
|
+
readonly pointerId: number;
|
|
40
|
+
readonly x: number;
|
|
41
|
+
readonly y: number;
|
|
42
|
+
readonly pressure: number;
|
|
43
|
+
readonly pointerType: PointerType;
|
|
44
|
+
readonly active: boolean;
|
|
45
|
+
readonly delta: {
|
|
46
|
+
readonly x: number;
|
|
47
|
+
readonly y: number;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/** Per-frame phase event (down/move/up/cancel queue, one-frame lifecycle). */
|
|
51
|
+
export interface PointerPhaseEvent {
|
|
52
|
+
readonly pointerId: number;
|
|
53
|
+
readonly phase: 'down' | 'move' | 'up' | 'cancel';
|
|
54
|
+
readonly x: number;
|
|
55
|
+
readonly y: number;
|
|
56
|
+
readonly pressure: number;
|
|
57
|
+
readonly pointerType: PointerType;
|
|
58
|
+
}
|
|
59
|
+
/** Per-frame virtual axis output (named joystick derived from pointer input). */
|
|
60
|
+
export interface VirtualAxisSample {
|
|
61
|
+
readonly name: string;
|
|
62
|
+
readonly x: number;
|
|
63
|
+
readonly y: number;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Configuration for an on-screen virtual joystick (M3). Consumed by
|
|
67
|
+
* attachBrowserInputBackend and passed through to deriveVirtualAxes.
|
|
68
|
+
*
|
|
69
|
+
* Fixed mode: origin is config.anchor (or region center if anchor omitted).
|
|
70
|
+
* Floating mode: origin is the first pointerdown position within the region.
|
|
71
|
+
*/
|
|
72
|
+
export interface VirtualJoystickConfig {
|
|
73
|
+
readonly name: string;
|
|
74
|
+
readonly mode: 'fixed' | 'floating';
|
|
75
|
+
/** Canvas-pixel region where touches are eligible to bind this joystick. */
|
|
76
|
+
readonly region: {
|
|
77
|
+
readonly x: number;
|
|
78
|
+
readonly y: number;
|
|
79
|
+
readonly width: number;
|
|
80
|
+
readonly height: number;
|
|
81
|
+
};
|
|
82
|
+
/** Fixed-mode origin anchor. Defaults to region center when omitted. */
|
|
83
|
+
readonly anchor?: {
|
|
84
|
+
readonly x: number;
|
|
85
|
+
readonly y: number;
|
|
86
|
+
} | undefined;
|
|
87
|
+
/** Max drag radius in canvas pixels. Vector is clamped then normalized to radius. */
|
|
88
|
+
readonly radius: number;
|
|
89
|
+
/** Normalized deadzone (0..1). |vec| < deadzone → zero vector output. */
|
|
90
|
+
readonly deadzone: number;
|
|
91
|
+
}
|
|
92
|
+
/** Capability snapshot (frozen at backend attach time). */
|
|
93
|
+
export interface Capabilities {
|
|
94
|
+
readonly gamepad: boolean;
|
|
95
|
+
readonly pointer: boolean;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Frozen value-shape view exposed to user systems via the `InputSnapshot`
|
|
99
|
+
* Resource. The methods are pure reads; calling them does not mutate any
|
|
100
|
+
* accumulator (charter P3 -- no observable side effects from the accessor
|
|
101
|
+
* surface). A fresh `InputSnapshot` instance is constructed by the
|
|
102
|
+
* frame-start scan system once per `world.update()` and replaces the
|
|
103
|
+
* previous Resource value.
|
|
104
|
+
*/
|
|
105
|
+
export interface InputSnapshot {
|
|
106
|
+
/** Keyboard view (held state plus frame edges). */
|
|
107
|
+
readonly keyboard: {
|
|
108
|
+
/**
|
|
109
|
+
* `true` while `key` is currently held. `key` matches the value the
|
|
110
|
+
* backend records (KeyboardEvent.key for the browser backend). When
|
|
111
|
+
* the key is not in the held set, returns `false` -- never throws
|
|
112
|
+
* (charter P3: empty signal is the signal).
|
|
113
|
+
*/
|
|
114
|
+
down(key: string): boolean;
|
|
115
|
+
/** `true` for the first frame in which `key` becomes held. */
|
|
116
|
+
justPressed(key: string): boolean;
|
|
117
|
+
/**
|
|
118
|
+
* `true` for one frame after the key was released (the up-edge). The
|
|
119
|
+
* edge collapses on the following `world.update()`. `key` not in the
|
|
120
|
+
* up-edge set returns `false`.
|
|
121
|
+
*/
|
|
122
|
+
up(key: string): boolean;
|
|
123
|
+
/** Code-key equivalent of `down`, using KeyboardEvent.code identity. */
|
|
124
|
+
downCode(code: string): boolean;
|
|
125
|
+
/** Code-key equivalent of `justPressed`. */
|
|
126
|
+
justPressedCode(code: string): boolean;
|
|
127
|
+
/** Code-key equivalent of `up`. */
|
|
128
|
+
upCode(code: string): boolean;
|
|
129
|
+
};
|
|
130
|
+
/** Mouse view (charter F2 minimal surface: position + movementDelta + button + wheelDelta). */
|
|
131
|
+
readonly mouse: {
|
|
132
|
+
/**
|
|
133
|
+
* Latest canvas-pixel cursor position. This is available during hover;
|
|
134
|
+
* it does not require a button press or pointer capture. The position is
|
|
135
|
+
* frozen with the rest of the frame-start snapshot.
|
|
136
|
+
*/
|
|
137
|
+
readonly position: {
|
|
138
|
+
readonly x: number;
|
|
139
|
+
readonly y: number;
|
|
140
|
+
} | undefined;
|
|
141
|
+
/**
|
|
142
|
+
* PointerLock-style accumulated movement since the previous frame.
|
|
143
|
+
* Value is frozen at frame-start; reading it does not clear the
|
|
144
|
+
* accumulator. The next `world.update()` produces a fresh delta
|
|
145
|
+
* (zero if no movement events arrived).
|
|
146
|
+
*/
|
|
147
|
+
readonly movementDelta: {
|
|
148
|
+
readonly x: number;
|
|
149
|
+
readonly y: number;
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* Merged pointer-lock state: true when either W3C pointer-lock
|
|
153
|
+
* (pointerLockElement === this backend's canvas) OR the lockProvider
|
|
154
|
+
* path has engaged. Consumers read this to decide whether to consume
|
|
155
|
+
* movementDelta for look/camera rotation. Required field, alongside
|
|
156
|
+
* movementDelta -- both facts sit at the same attribute path for
|
|
157
|
+
* single-point indexing (charter F1).
|
|
158
|
+
*/
|
|
159
|
+
readonly pointerLocked: boolean;
|
|
160
|
+
/**
|
|
161
|
+
* `true` while the W3C MouseEvent.button slot `i` is held. `i` is
|
|
162
|
+
* narrowed to the literal `0 | 1 | 2` so out-of-range indices are
|
|
163
|
+
* rejected at compile time (charter P3 explicit failure: TS literal
|
|
164
|
+
* narrowing replaces a runtime bounds-clamp).
|
|
165
|
+
*
|
|
166
|
+
* - 0 -- primary button (left)
|
|
167
|
+
* - 1 -- auxiliary button (middle)
|
|
168
|
+
* - 2 -- secondary button (right)
|
|
169
|
+
*/
|
|
170
|
+
button(i: MouseButtonIndex): boolean;
|
|
171
|
+
/** `true` for the first frame in which button `i` becomes held. */
|
|
172
|
+
justPressed(i: MouseButtonIndex): boolean;
|
|
173
|
+
/** `true` for the frame in which button `i` is released. */
|
|
174
|
+
justReleased(i: MouseButtonIndex): boolean;
|
|
175
|
+
/**
|
|
176
|
+
* Discrete wheel notches accumulated since the previous frame.
|
|
177
|
+
* Plan-strategy D-5 sign-discrete: each `WheelEvent` contributes
|
|
178
|
+
* `Math.sign(event.deltaY)` to the per-frame accumulator regardless
|
|
179
|
+
* of `deltaMode` (PIXEL / LINE / PAGE all collapse). Sign convention
|
|
180
|
+
* follows W3C `WheelEvent.deltaY`: positive = scroll down / away
|
|
181
|
+
* from user, negative = scroll up / toward user.
|
|
182
|
+
*
|
|
183
|
+
* Value is frozen at frame-start; reading it does not clear the
|
|
184
|
+
* accumulator. The next `world.update()` produces a fresh delta
|
|
185
|
+
* (zero when no wheel events arrived).
|
|
186
|
+
*
|
|
187
|
+
* Trade-off (plan-strategy R-7): trackpad high-resolution wheel
|
|
188
|
+
* events collapse to one notch per event, losing sub-notch fidelity.
|
|
189
|
+
* AI users who need analog magnitude must opt in via a future
|
|
190
|
+
* unitful surface (OOS-7 ScrollSnapshot is the deferred shape).
|
|
191
|
+
*/
|
|
192
|
+
readonly wheelDelta: number;
|
|
193
|
+
};
|
|
194
|
+
/**
|
|
195
|
+
* Per-slot gamepad reader. Returns a reader object for the gamepad at
|
|
196
|
+
* slot `i` regardless of connection state: disconnected or out-of-range
|
|
197
|
+
* slots report `connected=false`, all button/axis readpoints return
|
|
198
|
+
* `false`/`0` (charter P3 empty signal). The slot index is intentionally
|
|
199
|
+
* not narrowed — platform slot counts vary, and bounds handling is a
|
|
200
|
+
* runtime concern.
|
|
201
|
+
*/
|
|
202
|
+
gamepad(i: number): {
|
|
203
|
+
readonly connected: boolean;
|
|
204
|
+
readonly standardMapping: boolean;
|
|
205
|
+
button(b: GamepadButtonIndex): boolean;
|
|
206
|
+
buttonValue(b: GamepadButtonIndex): number;
|
|
207
|
+
justPressed(b: GamepadButtonIndex): boolean;
|
|
208
|
+
justReleased(b: GamepadButtonIndex): boolean;
|
|
209
|
+
axis(a: GamepadAxisIndex): number;
|
|
210
|
+
};
|
|
211
|
+
/**
|
|
212
|
+
* Frozen capabilities snapshot, determined once at backend attach time.
|
|
213
|
+
* Consumers use this to decide whether gamepad/pointer readpoints will
|
|
214
|
+
* ever carry live data, without probing per-frame.
|
|
215
|
+
*/
|
|
216
|
+
readonly capabilities: Capabilities;
|
|
217
|
+
/**
|
|
218
|
+
* Per-pointerId reader. Returns `{ active: true/false, x, y, pressure,
|
|
219
|
+
* pointerType, delta }` for the given pointerId. Unknown pointerIds
|
|
220
|
+
* return `{ active: false, ... }` without throwing.
|
|
221
|
+
*/
|
|
222
|
+
pointer(id: number): PointerSample & {
|
|
223
|
+
readonly delta: {
|
|
224
|
+
readonly x: number;
|
|
225
|
+
readonly y: number;
|
|
226
|
+
};
|
|
227
|
+
};
|
|
228
|
+
/**
|
|
229
|
+
* Named virtual axis reader (joystick-derived). Returns `{ x, y }` for
|
|
230
|
+
* the given joystick config name. Unknown names return the zero-vector
|
|
231
|
+
* `{ x: 0, y: 0 }` without throwing.
|
|
232
|
+
*/
|
|
233
|
+
virtualAxis(name: string): {
|
|
234
|
+
readonly x: number;
|
|
235
|
+
readonly y: number;
|
|
236
|
+
};
|
|
237
|
+
/**
|
|
238
|
+
* Per-frame phase event queue (down/move/up/cancel). One-frame
|
|
239
|
+
* lifecycle; drained by `sample()` at frame end. Empty array when no
|
|
240
|
+
* pointer events occurred this frame.
|
|
241
|
+
*/
|
|
242
|
+
readonly pointerEvents: readonly PointerPhaseEvent[];
|
|
243
|
+
/**
|
|
244
|
+
* Continuous gesture values (pinch scale + rotation angle) for the
|
|
245
|
+
* active dual-finger gesture. Returns the identity empty signal
|
|
246
|
+
* (`pinchScale=1`, `rotationAngle=0`) when no gesture is active (AC-12);
|
|
247
|
+
* an active gesture retains its value on idle frames (fingers held still
|
|
248
|
+
* are not a gesture end). AC-11: reading the same frame's snapshot twice
|
|
249
|
+
* returns the identical object.
|
|
250
|
+
*/
|
|
251
|
+
readonly gesture: GestureState;
|
|
252
|
+
/**
|
|
253
|
+
* Per-frame gesture lifecycle + instantaneous event queue (begin / end /
|
|
254
|
+
* cancel / swipe / long-press / double-tap). One-frame lifecycle, same
|
|
255
|
+
* pattern as `pointerEvents` (charter P4). Empty array when no gesture
|
|
256
|
+
* activity occurred this frame. Closed discriminant union (AC-13): a
|
|
257
|
+
* consumer exhaustively switches on `kind` without a default branch.
|
|
258
|
+
*/
|
|
259
|
+
readonly gestureEvents: readonly GestureEvent[];
|
|
260
|
+
/**
|
|
261
|
+
* Action mapping readpoint. Returns a frozen reader for the named action.
|
|
262
|
+
* When `name` is registered in the InputMap, `isPressed()` / `justPressed()`
|
|
263
|
+
* / `justReleased()` / `strength` reflect the derived state. Unregistered
|
|
264
|
+
* action names return empty signal (false / 0 / false / false / 0) without
|
|
265
|
+
* throwing (charter P3: empty signal is the signal). AC-11: calling
|
|
266
|
+
* action() multiple times in the same frame returns identical values.
|
|
267
|
+
*/
|
|
268
|
+
action(name: string): {
|
|
269
|
+
readonly isPressed: () => boolean;
|
|
270
|
+
readonly justPressed: () => boolean;
|
|
271
|
+
readonly justReleased: () => boolean;
|
|
272
|
+
readonly strength: number;
|
|
273
|
+
};
|
|
274
|
+
/**
|
|
275
|
+
* Compose a 1D axis value from two opposing actions.
|
|
276
|
+
*
|
|
277
|
+
* Returns `strength(pos) - strength(neg)`, range [-1, 1].
|
|
278
|
+
* Both registered: combines normally. One unregistered: contributes 0
|
|
279
|
+
* (E-3). Same action for both ends: always 0 (E-12).
|
|
280
|
+
*
|
|
281
|
+
* @param neg - Action name for the negative direction (e.g. 'moveLeft').
|
|
282
|
+
* @param pos - Action name for the positive direction (e.g. 'moveRight').
|
|
283
|
+
*/
|
|
284
|
+
getAxis(neg: string, pos: string): number;
|
|
285
|
+
/**
|
|
286
|
+
* Compose a 2D vector from four directional actions with a single radial
|
|
287
|
+
* deadzone (Godot input.cpp three-branch formula). Uses `raw` (not
|
|
288
|
+
* `strength`) to avoid per-axis deadzone stacking into a square deadzone
|
|
289
|
+
* (AC-06).
|
|
290
|
+
*
|
|
291
|
+
* @param negX - Action name for negative X (e.g. 'moveLeft').
|
|
292
|
+
* @param posX - Action name for positive X (e.g. 'moveRight').
|
|
293
|
+
* @param negY - Action name for negative Y (e.g. 'moveUp').
|
|
294
|
+
* @param posY - Action name for positive Y (e.g. 'moveDown').
|
|
295
|
+
* @param opts - Optional override (deadzone).
|
|
296
|
+
*/
|
|
297
|
+
getVector(negX: string, posX: string, negY: string, posY: string, opts?: GetVectorOptions): {
|
|
298
|
+
readonly x: number;
|
|
299
|
+
readonly y: number;
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Backend protocol consumed by the frame-start scan system. The browser
|
|
304
|
+
* implementation (`browser-backend.ts`) is the production producer;
|
|
305
|
+
* tests inject fakes that emit synthetic samples.
|
|
306
|
+
*/
|
|
307
|
+
export interface InputBackend {
|
|
308
|
+
/**
|
|
309
|
+
* Produce one frame's worth of input data and reset the per-frame
|
|
310
|
+
* accumulators (movement delta + up-edge set). Held-key state and
|
|
311
|
+
* held-button state survive across calls.
|
|
312
|
+
*
|
|
313
|
+
* Contract notes:
|
|
314
|
+
* - `downKeys` is the held-key set as of the call (held across frames)
|
|
315
|
+
* - `upKeys` is the up-edge set since the previous sample (cleared
|
|
316
|
+
* after the call so the edge appears in exactly one frame)
|
|
317
|
+
* - `buttons` is the held-button slot tuple `[b0, b1, b2]`
|
|
318
|
+
* - `movementX` / `movementY` are the accumulated PointerLock delta
|
|
319
|
+
* since the previous sample (cleared after the call)
|
|
320
|
+
* - `focused` mirrors `document.hasFocus()` so the scan system can
|
|
321
|
+
* suppress spurious up-edges across alt-tab transitions
|
|
322
|
+
*/
|
|
323
|
+
sample(): InputBackendSample;
|
|
324
|
+
/**
|
|
325
|
+
* Command-set game gate for pointer-lock. When set to `false`, the
|
|
326
|
+
* backend will not request pointer-lock on click AND will immediately
|
|
327
|
+
* release any currently active lock (W3C path: `exitPointerLock`;
|
|
328
|
+
* provider path: `exitLock()`). When `true` (default), pointer-lock
|
|
329
|
+
* can be requested through the normal gate logic.
|
|
330
|
+
*
|
|
331
|
+
* Optional -- backends without pointer-lock support omit this method.
|
|
332
|
+
*/
|
|
333
|
+
setPointerLockAllowed?(allowed: boolean): void;
|
|
334
|
+
/**
|
|
335
|
+
* Atomically discard acquired state without detaching listeners. A host calls
|
|
336
|
+
* this when it revokes a control lease so held keys/buttons, contacts, frame
|
|
337
|
+
* edges, deltas and pointer lock cannot bleed into a later consumer. Optional
|
|
338
|
+
* keeps synthetic backends source-compatible.
|
|
339
|
+
*/
|
|
340
|
+
clear?(): void;
|
|
341
|
+
/** Detach DOM listeners; called when the engine shuts down. */
|
|
342
|
+
detach(): void;
|
|
343
|
+
}
|
|
344
|
+
/** Snapshot value returned by `InputBackend.sample()` (POD). */
|
|
345
|
+
export interface InputBackendSample {
|
|
346
|
+
readonly downKeys: ReadonlySet<string>;
|
|
347
|
+
readonly upKeys: ReadonlySet<string>;
|
|
348
|
+
/** Physical code identity (KeyboardEvent.code), when the producer has it. */
|
|
349
|
+
readonly downCodes?: ReadonlySet<string>;
|
|
350
|
+
/** One-frame physical code release edges, when the producer has them. */
|
|
351
|
+
readonly upCodes?: ReadonlySet<string>;
|
|
352
|
+
readonly buttons: readonly [boolean, boolean, boolean];
|
|
353
|
+
readonly movementX: number;
|
|
354
|
+
readonly movementY: number;
|
|
355
|
+
/** Latest canvas-pixel mouse position; absent for non-pointer backends. */
|
|
356
|
+
readonly mouseX?: number;
|
|
357
|
+
readonly mouseY?: number;
|
|
358
|
+
/**
|
|
359
|
+
* Sign-discrete wheel notch accumulator since the previous sample
|
|
360
|
+
* (plan-strategy D-5). Browser backend writes `Math.sign(deltaY)` per
|
|
361
|
+
* `WheelEvent`; sample() drains the value and resets the producer
|
|
362
|
+
* accumulator (mirrors movementX/Y semantics).
|
|
363
|
+
*/
|
|
364
|
+
readonly wheelDelta: number;
|
|
365
|
+
/** True for the first sample after blur/hidden state reset. */
|
|
366
|
+
readonly focusReset?: boolean;
|
|
367
|
+
readonly focused: boolean;
|
|
368
|
+
/** M1+ gamepad per-slot frame data (optional — absent when backend lacks gamepad support). */
|
|
369
|
+
readonly gamepads?: readonly GamepadSlotSample[];
|
|
370
|
+
/** M1+ frozen capability snapshot (optional — absent for pre-M1 backends). */
|
|
371
|
+
readonly capabilities?: Capabilities;
|
|
372
|
+
/** M2+ active pointer contacts (optional — absent for keyboard-only backends). */
|
|
373
|
+
readonly pointers?: readonly PointerSample[];
|
|
374
|
+
/** M2+ per-frame phase event queue (optional — absent when no pointer events occurred). */
|
|
375
|
+
readonly pointerEvents?: readonly PointerPhaseEvent[];
|
|
376
|
+
/** M3+ virtual joystick axis outputs (optional — absent when no virtual joysticks configured). */
|
|
377
|
+
readonly virtualAxes?: readonly VirtualAxisSample[];
|
|
378
|
+
/** M5+ continuous gesture values (optional — absent when no gesture is active). */
|
|
379
|
+
readonly gestures?: GestureState;
|
|
380
|
+
/** M5+ per-frame gesture event queue (optional — absent when no gesture activity occurred). */
|
|
381
|
+
readonly gestureEvents?: readonly GestureEvent[];
|
|
382
|
+
/**
|
|
383
|
+
* Merged pointer-lock state: true when either W3C pointer-lock is active
|
|
384
|
+
* (pointerLockElement === this backend's canvas) OR the lockProvider path
|
|
385
|
+
* has engaged (requestLock() was called and not yet released). Required
|
|
386
|
+
* field -- always present, defaults to false when no lock is active.
|
|
387
|
+
*/
|
|
388
|
+
readonly pointerLocked: boolean;
|
|
389
|
+
}
|
|
390
|
+
/** Build the neutral backend sample used before or outside an active consumer. */
|
|
391
|
+
export declare function createEmptyInputBackendSample(): InputBackendSample;
|
|
392
|
+
/**
|
|
393
|
+
* Build an `InputSnapshot` from a backend sample.
|
|
394
|
+
*
|
|
395
|
+
* @param sample - One frame's raw input backend sample (POD).
|
|
396
|
+
* @param actionStates - Optional per-frame derived action states from
|
|
397
|
+
* deriveActionStates(). When provided, snap.action(name) returns mapped
|
|
398
|
+
* values; when absent or empty, all action readpoints return empty signal
|
|
399
|
+
* (charter P3: false/0, never throws). AC-11: actionStates is frozen into
|
|
400
|
+
* the snapshot so same-frame re-reads return identical values.
|
|
401
|
+
*/
|
|
402
|
+
export declare function snapshotFromSample(sample: InputBackendSample, actionStates?: readonly ActionState[], inputMap?: readonly ActionConfig[], previousSnapshot?: InputSnapshot): InputSnapshot;
|
|
403
|
+
/**
|
|
404
|
+
* @internal Read previously derived action states from a snapshot for edge diff.
|
|
405
|
+
* Used by the frame-start scan system (D-6: prev snapshot = edge baseline).
|
|
406
|
+
*/
|
|
407
|
+
export declare function readActionStatesForEdgeDiff(snap: InputSnapshot): readonly ActionState[] | undefined;
|
|
408
|
+
/**
|
|
409
|
+
* Construct an empty snapshot for the pre-start window
|
|
410
|
+
* (`engine.run()` has not yet attached a backend). Returns the full
|
|
411
|
+
* multi-device shape as `snapshotFromSample`, with every accessor
|
|
412
|
+
* returning `false` / `0` / zero-vector. AI users can put this into the
|
|
413
|
+
* Resource store to satisfy `world.getResource('InputSnapshot')` calls
|
|
414
|
+
* in fixtures or unit tests (charter P3: empty signal is the signal).
|
|
415
|
+
* The underlying 7-field POD sample contract is unchanged (D-9).
|
|
416
|
+
*/
|
|
417
|
+
export declare function createInputSnapshot(): InputSnapshot;
|
|
418
|
+
/** Stable Resource key for `world.insertResource` / `world.getResource`. */
|
|
419
|
+
export declare const INPUT_SNAPSHOT_RESOURCE_KEY = "InputSnapshot";
|
|
420
|
+
//# sourceMappingURL=input-snapshot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-snapshot.d.ts","sourceRoot":"","sources":["../src/input-snapshot.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElF,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAOvE,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,KAAK,GAAG,OAAO,CAAC;AAEpD,wEAAwE;AACxE,MAAM,MAAM,kBAAkB,GAC1B,CAAC,GACD,CAAC,GACD,CAAC,GACD,CAAC,GACD,CAAC,GACD,CAAC,GACD,CAAC,GACD,CAAC,GACD,CAAC,GACD,CAAC,GACD,EAAE,GACF,EAAE,GACF,EAAE,GACF,EAAE,GACF,EAAE,GACF,EAAE,GACF,EAAE,CAAC;AAEP,qEAAqE;AACrE,MAAM,MAAM,gBAAgB,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAE7C,yEAAyE;AACzE,MAAM,MAAM,gBAAgB,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAEzC,0DAA0D;AAC1D,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACtC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1C,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC3C,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnD,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1D;AAED;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5D;AAED,8EAA8E;AAC9E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,QAAQ,CAAC;IAClD,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;CACnC;AAED,iFAAiF;AACjF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU,CAAC;IACpC,4EAA4E;IAC5E,QAAQ,CAAC,MAAM,EAAE;QACf,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,wEAAwE;IACxE,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IACzE,qFAAqF;IACrF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,2DAA2D;AAC3D,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC5B,mDAAmD;IACnD,QAAQ,CAAC,QAAQ,EAAE;QACjB;;;;;WAKG;QACH,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAC3B,8DAA8D;QAC9D,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAClC;;;;WAIG;QACH,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QACzB,wEAAwE;QACxE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAChC,4CAA4C;QAC5C,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QACvC,mCAAmC;QACnC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;KAC/B,CAAC;IACF,+FAA+F;IAC/F,QAAQ,CAAC,KAAK,EAAE;QACd;;;;WAIG;QACH,QAAQ,CAAC,QAAQ,EAAE;YAAE,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAA;SAAE,GAAG,SAAS,CAAC;QAC1E;;;;;WAKG;QACH,QAAQ,CAAC,aAAa,EAAE;YAAE,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QACnE;;;;;;;WAOG;QACH,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;QAChC;;;;;;;;;WASG;QACH,MAAM,CAAC,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC;QACrC,mEAAmE;QACnE,WAAW,CAAC,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC;QAC1C,4DAA4D;QAC5D,YAAY,CAAC,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC;QAC3C;;;;;;;;;;;;;;;;WAgBG;QACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;KAC7B,CAAC;IACF;;;;;;;OAOG;IACH,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG;QAClB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;QAC5B,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;QAClC,MAAM,CAAC,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC;QACvC,WAAW,CAAC,CAAC,EAAE,kBAAkB,GAAG,MAAM,CAAC;QAC3C,WAAW,CAAC,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC;QAC5C,YAAY,CAAC,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC;QAC7C,IAAI,CAAC,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAAC;KACnC,CAAC;IACF;;;;OAIG;IACH,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC;;;;OAIG;IACH,OAAO,CACL,EAAE,EAAE,MAAM,GACT,aAAa,GAAG;QAAE,QAAQ,CAAC,KAAK,EAAE;YAAE,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;IAClF;;;;OAIG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACtE;;;;OAIG;IACH,QAAQ,CAAC,aAAa,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACrD;;;;;;;OAOG;IACH,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B;;;;;;OAMG;IACH,QAAQ,CAAC,aAAa,EAAE,SAAS,YAAY,EAAE,CAAC;IAChD;;;;;;;OAOG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG;QACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,OAAO,CAAC;QAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,OAAO,CAAC;QACpC,QAAQ,CAAC,YAAY,EAAE,MAAM,OAAO,CAAC;QACrC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;KAC3B,CAAC;IACF;;;;;;;;;OASG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1C;;;;;;;;;;;OAWG;IACH,SAAS,CACP,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,gBAAgB,GACtB;QAAE,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/C;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;;;;;;;;;OAcG;IACH,MAAM,IAAI,kBAAkB,CAAC;IAC7B;;;;;;;;OAQG;IACH,qBAAqB,CAAC,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAC/C;;;;;OAKG;IACH,KAAK,CAAC,IAAI,IAAI,CAAC;IACf,+DAA+D;IAC/D,MAAM,IAAI,IAAI,CAAC;CAChB;AAED,gEAAgE;AAChE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACrC,6EAA6E;IAC7E,QAAQ,CAAC,SAAS,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACzC,yEAAyE;IACzE,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IACvD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,+DAA+D;IAC/D,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,8FAA8F;IAC9F,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACjD,8EAA8E;IAC9E,QAAQ,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IACrC,kFAAkF;IAClF,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;IAC7C,2FAA2F;IAC3F,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACtD,kGAAkG;IAClG,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACpD,mFAAmF;IACnF,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC;IACjC,+FAA+F;IAC/F,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IACjD;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;CACjC;AAED,kFAAkF;AAClF,wBAAgB,6BAA6B,IAAI,kBAAkB,CAWlE;AAiED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,kBAAkB,EAC1B,YAAY,CAAC,EAAE,SAAS,WAAW,EAAE,EACrC,QAAQ,CAAC,EAAE,SAAS,YAAY,EAAE,EAClC,gBAAgB,CAAC,EAAE,aAAa,GAC/B,aAAa,CAoLf;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,aAAa,GAClB,SAAS,WAAW,EAAE,GAAG,SAAS,CAEpC;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,IAAI,aAAa,CAEnD;AAED,4EAA4E;AAC5E,eAAO,MAAM,2BAA2B,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Plugin } from '@forgeax/engine-plugin';
|
|
2
|
+
import type { InputBackend } from './input-snapshot';
|
|
3
|
+
declare module '@forgeax/engine-plugin' {
|
|
4
|
+
interface EngineContextServices {
|
|
5
|
+
input?: InputBackend;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
export declare function inputBackendPlugin(backend: InputBackend): Plugin;
|
|
9
|
+
/** Provide an App-acquired input backend and release its Host listeners with the Fiber. */
|
|
10
|
+
export declare function ownedInputBackendPlugin(backend: InputBackend, dispose: () => void): Plugin;
|
|
11
|
+
//# sourceMappingURL=plugin-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-service.d.ts","sourceRoot":"","sources":["../src/plugin-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAErD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,QAAQ,wBAAwB,CAAC;IACtC,UAAU,qBAAqB;QAC7B,KAAK,CAAC,EAAE,YAAY,CAAC;KACtB;CACF;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAQhE;AAED,2FAA2F;AAC3F,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,MAAM,CAS1F"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Event-path ownership and lifecycle reset primitives for browser hosts. */
|
|
2
|
+
export interface UiOwnershipResult {
|
|
3
|
+
readonly owned: boolean;
|
|
4
|
+
readonly source: 'composed-path' | 'target-fallback' | 'unknown';
|
|
5
|
+
}
|
|
6
|
+
export interface UiInputResetBoundaryOptions {
|
|
7
|
+
readonly clear: () => void;
|
|
8
|
+
readonly signal?: AbortSignal;
|
|
9
|
+
}
|
|
10
|
+
export interface UiInputResetBoundary {
|
|
11
|
+
readonly reset: () => void;
|
|
12
|
+
readonly dispose: () => void;
|
|
13
|
+
}
|
|
14
|
+
export declare function resolveUiOwnership(event: Event, host: Node): UiOwnershipResult;
|
|
15
|
+
export declare function isUiOwnedEvent(event: Event, host: Node): boolean;
|
|
16
|
+
export declare function createUiInputResetBoundary(options: UiInputResetBoundaryOptions): UiInputResetBoundary;
|
|
17
|
+
//# sourceMappingURL=ui-ownership.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-ownership.d.ts","sourceRoot":"","sources":["../src/ui-ownership.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAE7E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,eAAe,GAAG,iBAAiB,GAAG,SAAS,CAAC;CAClE;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;CAC9B;AAOD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,GAAG,iBAAiB,CAe9E;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAEhE;AAED,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,2BAA2B,GACnC,oBAAoB,CAetB"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { VirtualAxisSample, VirtualJoystickConfig } from './input-snapshot';
|
|
2
|
+
/**
|
|
3
|
+
* Per-joystick binding state. The backend closure owns a
|
|
4
|
+
* Map<string, BindState> keyed by joystick config name.
|
|
5
|
+
*/
|
|
6
|
+
export interface BindState {
|
|
7
|
+
/** bound pointerId, or undefined if unbound */
|
|
8
|
+
pointerId?: number | undefined;
|
|
9
|
+
/** origin in canvas pixels (anchor for fixed, first-touch for floating) */
|
|
10
|
+
originX: number;
|
|
11
|
+
originY: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Derive one frame of virtual axis outputs from live pointer state and
|
|
15
|
+
* per-joystick binding state.
|
|
16
|
+
*
|
|
17
|
+
* Pure function: no DOM access. The backend closure is the SSOT for
|
|
18
|
+
* per-joystick state; binding + origin selection happens in
|
|
19
|
+
* browser-backend.ts onPointerDown. This function only reads bindState
|
|
20
|
+
* and computes per-frame vectors.
|
|
21
|
+
*
|
|
22
|
+
* Unbound joysticks always produce the zero vector.
|
|
23
|
+
*
|
|
24
|
+
* @param configs - configured virtual joysticks
|
|
25
|
+
* @param pointerMap - live pointer positions keyed by pointerId
|
|
26
|
+
* @param bindState - per-joystick binding state (read-only)
|
|
27
|
+
* @returns one VirtualAxisSample per configured joystick
|
|
28
|
+
*/
|
|
29
|
+
export declare function deriveVirtualAxes(configs: readonly VirtualJoystickConfig[], pointerMap: Map<number, {
|
|
30
|
+
readonly x: number;
|
|
31
|
+
readonly y: number;
|
|
32
|
+
}>, bindState: Map<string, BindState>): VirtualAxisSample[];
|
|
33
|
+
/**
|
|
34
|
+
* Unbind a joystick when its bound pointer goes up or is cancelled.
|
|
35
|
+
* Sets pointerId to undefined; the next deriveVirtualAxes call will
|
|
36
|
+
* produce a zero vector for the unbound joystick.
|
|
37
|
+
*/
|
|
38
|
+
export declare function handleVirtualJoystickUnbind(bindState: Map<string, BindState>, pointerId: number): void;
|
|
39
|
+
//# sourceMappingURL=virtual-joystick.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"virtual-joystick.d.ts","sourceRoot":"","sources":["../src/virtual-joystick.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAEjF;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,2EAA2E;IAC3E,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAqBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,SAAS,qBAAqB,EAAE,EACzC,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE;IAAE,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,EACnE,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,GAChC,iBAAiB,EAAE,CAyBrB;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,EACjC,SAAS,EAAE,MAAM,GAChB,IAAI,CAMN"}
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@forgeax/engine-input",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"description": "Frame-start scanned, frozen InputSnapshot Resource (logical keyboard key and physical code held/press/release edges + mouse.position/movementDelta + mouse.button(0|1|2)) + browser PointerLock backend for forgeax-engine.",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.mjs"
|
|
13
|
+
},
|
|
14
|
+
"./controller-db": {
|
|
15
|
+
"types": "./dist/controller-db.d.ts",
|
|
16
|
+
"import": "./dist/controller-db.mjs"
|
|
17
|
+
},
|
|
18
|
+
"./controller-db-data": {
|
|
19
|
+
"types": "./dist/controller-db-data.d.ts",
|
|
20
|
+
"import": "./dist/controller-db-data.mjs"
|
|
21
|
+
},
|
|
22
|
+
"./package.json": "./package.json"
|
|
23
|
+
},
|
|
24
|
+
"main": "./dist/index.mjs",
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"src",
|
|
29
|
+
"vendor",
|
|
30
|
+
"README.md",
|
|
31
|
+
"LICENSE"
|
|
32
|
+
],
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@forgeax/engine-ecs": "0.1.2",
|
|
35
|
+
"@forgeax/engine-plugin": "0.1.2"
|
|
36
|
+
},
|
|
37
|
+
"forgeax": {
|
|
38
|
+
"metrics": {
|
|
39
|
+
"bundle-size": {
|
|
40
|
+
"enabled": true,
|
|
41
|
+
"path": "dist/index.mjs",
|
|
42
|
+
"compression": "gzip",
|
|
43
|
+
"baseline": {
|
|
44
|
+
"source": "b2ea70919",
|
|
45
|
+
"threshold": 13280
|
|
46
|
+
},
|
|
47
|
+
"reason": "dist/index.mjs = 12069 B gzip after the normalized input snapshot and action/gesture readpoints. Threshold 13280 B = approximately 10% headroom over measured gzip. Prior baseline 10899 B gzip @ b2ea70919 (threshold 11990). Includes: action-state.ts (deriveActionStates + getAxis/getVector), gesture-recognizer.ts (5 state machines), gamepad-frame.ts (DB remap), browser-backend.ts (recognizer wiring + lazy-load), composite-backend.ts (per-key-yield merge decorator), input-snapshot.ts (keyboard/mouse/action/gesture readpoints + PointerType narrowing), index.ts (barrel). The SDL controller DB sub-export (dist/controller-db.mjs, ~1.5 KB gzip) and data sub-export (dist/controller-db-data.mjs, ~45 KB gzip / 545 KB raw) are opt-in lazy dynamic-imports and are NOT in the main-entry path (path=dist/index.mjs)."
|
|
48
|
+
},
|
|
49
|
+
"fps": {
|
|
50
|
+
"enabled": false,
|
|
51
|
+
"reason": "library package, no runtime canvas; fps is reported by hello-* / learn-render apps that consume engine.input.snapshot()"
|
|
52
|
+
},
|
|
53
|
+
"bench": {
|
|
54
|
+
"enabled": false,
|
|
55
|
+
"reason": "frame-start scan path is O(events-since-last-tick); not a perf-critical surface for the MVP"
|
|
56
|
+
},
|
|
57
|
+
"gate": {
|
|
58
|
+
"enabled": false,
|
|
59
|
+
"reason": "no package-level binary gate; AC-07 surface coverage runs as part of pnpm test:unit + tsc -b"
|
|
60
|
+
},
|
|
61
|
+
"spike-report": {
|
|
62
|
+
"enabled": false,
|
|
63
|
+
"reason": "not a spike package; this is a production MVP per plan-strategy D-5 (input internalisation minimal surface)"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"scripts": {
|
|
68
|
+
"build": "tsup",
|
|
69
|
+
"test": "vitest run",
|
|
70
|
+
"typecheck": "tsc -b"
|
|
71
|
+
}
|
|
72
|
+
}
|