@utsp/input 0.1.1
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 +21 -0
- package/README.md +36 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +1359 -0
- package/dist/index.mjs +1 -0
- package/package.json +69 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,1359 @@
|
|
|
1
|
+
import { Vector2, Vector3, AxisBinding, IInputSystem, ButtonBinding, InputDeviceType } from '@utsp/types';
|
|
2
|
+
export { GamepadInput, IInputSystem, InputDeviceType, KeyboardInput, MouseInput, TouchInput, Vector2, Vector3 } from '@utsp/types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Base interface for all input management systems
|
|
6
|
+
* This provides a common API for keyboard, mouse, gamepad, and touch inputs
|
|
7
|
+
*/
|
|
8
|
+
interface IInputs {
|
|
9
|
+
/**
|
|
10
|
+
* Start listening to input events
|
|
11
|
+
*/
|
|
12
|
+
start(): void;
|
|
13
|
+
/**
|
|
14
|
+
* Stop listening to input events and cleanup
|
|
15
|
+
*/
|
|
16
|
+
stop(): void;
|
|
17
|
+
/**
|
|
18
|
+
* Reset all input states to default
|
|
19
|
+
*/
|
|
20
|
+
reset(): void;
|
|
21
|
+
/**
|
|
22
|
+
* Check if the input system is currently active/listening
|
|
23
|
+
*/
|
|
24
|
+
isListening(): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Cleanup and destroy the instance, removing all event listeners
|
|
27
|
+
*/
|
|
28
|
+
destroy(): void;
|
|
29
|
+
/**
|
|
30
|
+
* Reset delta values (call at the end of each frame/update)
|
|
31
|
+
*/
|
|
32
|
+
resetDelta(): void;
|
|
33
|
+
/**
|
|
34
|
+
* Set or update event callbacks
|
|
35
|
+
*/
|
|
36
|
+
setCallbacks(callbacks: unknown): void;
|
|
37
|
+
/**
|
|
38
|
+
* Remove all event callbacks
|
|
39
|
+
*/
|
|
40
|
+
clearCallbacks(): void;
|
|
41
|
+
/**
|
|
42
|
+
* Check if a key is currently pressed (Keyboard)
|
|
43
|
+
*/
|
|
44
|
+
isKeyPressed?(key: string): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Check if left mouse button is pressed (Mouse)
|
|
47
|
+
*/
|
|
48
|
+
isLeftMousePressed?(): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Get mouse position (Mouse)
|
|
51
|
+
*/
|
|
52
|
+
getMousePosition?(): Vector2 | null;
|
|
53
|
+
/**
|
|
54
|
+
* Get mouse movement delta (Mouse)
|
|
55
|
+
*/
|
|
56
|
+
getMouseDelta?(): Vector2 | null;
|
|
57
|
+
/**
|
|
58
|
+
* Get wheel delta (Mouse)
|
|
59
|
+
*/
|
|
60
|
+
getWheelDelta?(): Vector2 | null;
|
|
61
|
+
/**
|
|
62
|
+
* Check if a button is pressed (Gamepad, TVRemote)
|
|
63
|
+
*/
|
|
64
|
+
isButtonPressed?(button: string | number): boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Get axis value (Gamepad, TVRemote)
|
|
67
|
+
*/
|
|
68
|
+
getAxis?(axis: number): number | null;
|
|
69
|
+
/**
|
|
70
|
+
* Get motion/gyroscope data (TVRemote, Mobile)
|
|
71
|
+
*/
|
|
72
|
+
getMotionData?(): MotionData | null;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Motion/Gyroscope data interface
|
|
76
|
+
*/
|
|
77
|
+
interface MotionData extends Vector3 {
|
|
78
|
+
timestamp?: number;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Common button state interface
|
|
82
|
+
*/
|
|
83
|
+
interface ButtonState {
|
|
84
|
+
pressed: boolean;
|
|
85
|
+
justPressed: boolean;
|
|
86
|
+
justReleased: boolean;
|
|
87
|
+
timestamp?: number;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Input event types enumeration
|
|
91
|
+
*/
|
|
92
|
+
declare enum InputEventType {
|
|
93
|
+
KeyDown = "keydown",
|
|
94
|
+
KeyUp = "keyup",
|
|
95
|
+
MouseDown = "mousedown",
|
|
96
|
+
MouseUp = "mouseup",
|
|
97
|
+
MouseMove = "mousemove",
|
|
98
|
+
MouseWheel = "mousewheel",
|
|
99
|
+
TouchStart = "touchstart",
|
|
100
|
+
TouchEnd = "touchend",
|
|
101
|
+
TouchMove = "touchmove",
|
|
102
|
+
GamepadConnected = "gamepadconnected",
|
|
103
|
+
GamepadDisconnected = "gamepaddisconnected",
|
|
104
|
+
GamepadButton = "gamepadbutton",
|
|
105
|
+
GamepadAxis = "gamepadaxis"
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Generic input event interface
|
|
109
|
+
*/
|
|
110
|
+
interface InputEvent<T = unknown> {
|
|
111
|
+
type: InputEventType;
|
|
112
|
+
timestamp: number;
|
|
113
|
+
data: T;
|
|
114
|
+
originalEvent?: Event;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Input device information
|
|
118
|
+
*/
|
|
119
|
+
interface InputDevice {
|
|
120
|
+
type: number;
|
|
121
|
+
id: string;
|
|
122
|
+
name?: string;
|
|
123
|
+
connected: boolean;
|
|
124
|
+
timestamp?: number;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Configuration options for input systems
|
|
128
|
+
*/
|
|
129
|
+
interface InputConfig {
|
|
130
|
+
/**
|
|
131
|
+
* Target element to attach listeners to (default: window)
|
|
132
|
+
*/
|
|
133
|
+
targetElement?: HTMLElement | Window;
|
|
134
|
+
/**
|
|
135
|
+
* Enable/disable specific input types
|
|
136
|
+
*/
|
|
137
|
+
enabled?: boolean;
|
|
138
|
+
/**
|
|
139
|
+
* Prevent default browser behaviors
|
|
140
|
+
*/
|
|
141
|
+
preventDefault?: boolean;
|
|
142
|
+
/**
|
|
143
|
+
* Stop event propagation
|
|
144
|
+
*/
|
|
145
|
+
stopPropagation?: boolean;
|
|
146
|
+
/**
|
|
147
|
+
* Enable debug logging
|
|
148
|
+
*/
|
|
149
|
+
debug?: boolean;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Abstract base class for input systems
|
|
153
|
+
* All input classes should extend this to maintain consistency
|
|
154
|
+
*/
|
|
155
|
+
declare abstract class BaseInputs implements IInputs {
|
|
156
|
+
protected isActive: boolean;
|
|
157
|
+
protected targetElement: HTMLElement | Window;
|
|
158
|
+
protected config: InputConfig;
|
|
159
|
+
protected callbacks: Record<string, ((...args: any[]) => void)[]>;
|
|
160
|
+
constructor(targetElement?: HTMLElement | Window, config?: InputConfig);
|
|
161
|
+
abstract start(): void;
|
|
162
|
+
abstract stop(): void;
|
|
163
|
+
abstract reset(): void;
|
|
164
|
+
abstract resetDelta(): void;
|
|
165
|
+
isListening(): boolean;
|
|
166
|
+
destroy(): void;
|
|
167
|
+
setCallbacks(callbacks: unknown): void;
|
|
168
|
+
clearCallbacks(): void;
|
|
169
|
+
/**
|
|
170
|
+
* Get the target element
|
|
171
|
+
*/
|
|
172
|
+
getTargetElement(): HTMLElement | Window;
|
|
173
|
+
/**
|
|
174
|
+
* Enable the input system
|
|
175
|
+
*/
|
|
176
|
+
enable(): void;
|
|
177
|
+
/**
|
|
178
|
+
* Disable the input system
|
|
179
|
+
*/
|
|
180
|
+
disable(): void;
|
|
181
|
+
/**
|
|
182
|
+
* Check if the input system is enabled
|
|
183
|
+
*/
|
|
184
|
+
isEnabled(): boolean;
|
|
185
|
+
/**
|
|
186
|
+
* Emit an event to all registered callbacks
|
|
187
|
+
*/
|
|
188
|
+
protected emit(eventType: string, ...args: unknown[]): void;
|
|
189
|
+
/**
|
|
190
|
+
* Log debug messages if debug mode is enabled
|
|
191
|
+
*/
|
|
192
|
+
protected log(...args: unknown[]): void;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Type guard to check if an object implements IInputs
|
|
196
|
+
*/
|
|
197
|
+
declare function isInputs(obj: unknown): obj is IInputs;
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* KeyboardInputs - Keyboard input management
|
|
201
|
+
* Handles keyboard events with support for vanilla JS, React, and other frameworks
|
|
202
|
+
*/
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Keyboard button state with press/release detection
|
|
206
|
+
*/
|
|
207
|
+
interface KeyButtonState {
|
|
208
|
+
pressed: boolean;
|
|
209
|
+
justPressed: boolean;
|
|
210
|
+
justReleased: boolean;
|
|
211
|
+
}
|
|
212
|
+
interface KeyState {
|
|
213
|
+
[key: string]: KeyButtonState;
|
|
214
|
+
}
|
|
215
|
+
interface KeyboardCallbacks {
|
|
216
|
+
onKeyDown?: (key: string, event: KeyboardEvent) => void;
|
|
217
|
+
onKeyUp?: (key: string, event: KeyboardEvent) => void;
|
|
218
|
+
}
|
|
219
|
+
declare class KeyboardInputs extends BaseInputs {
|
|
220
|
+
private keys;
|
|
221
|
+
private keyboardCallbacks;
|
|
222
|
+
private textInputsThisFrame;
|
|
223
|
+
private boundHandlers;
|
|
224
|
+
constructor(targetElement?: HTMLElement | Window, config?: InputConfig);
|
|
225
|
+
start(): void;
|
|
226
|
+
stop(): void;
|
|
227
|
+
reset(): void;
|
|
228
|
+
resetDelta(): void;
|
|
229
|
+
/**
|
|
230
|
+
* Poll - Reset transient states (justPressed/justReleased)
|
|
231
|
+
* Should be called once per frame AFTER collecting input
|
|
232
|
+
*/
|
|
233
|
+
poll(): void;
|
|
234
|
+
/**
|
|
235
|
+
* Get text inputs captured this frame
|
|
236
|
+
* Returns actual characters typed (handles keyboard layout, modifiers, etc.)
|
|
237
|
+
*
|
|
238
|
+
* @returns Array of character strings typed this frame
|
|
239
|
+
*
|
|
240
|
+
* @example
|
|
241
|
+
* ```typescript
|
|
242
|
+
* const textInputs = keyboard.getTextInputs();
|
|
243
|
+
* textInputs.forEach(char => chatBox.append(char));
|
|
244
|
+
* ```
|
|
245
|
+
*/
|
|
246
|
+
getTextInputs(): string[];
|
|
247
|
+
/**
|
|
248
|
+
* Check if a key is currently pressed
|
|
249
|
+
*
|
|
250
|
+
* @param key - Key code (e.g., 'Space', 'KeyA', 'ArrowUp')
|
|
251
|
+
* @returns True if key is pressed, false otherwise
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* ```typescript
|
|
255
|
+
* if (keyboard.isKeyPressed('Space')) {
|
|
256
|
+
* player.jump();
|
|
257
|
+
* }
|
|
258
|
+
*
|
|
259
|
+
* if (keyboard.isKeyPressed('KeyW')) {
|
|
260
|
+
* player.moveForward();
|
|
261
|
+
* }
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
isKeyPressed(key: string): boolean;
|
|
265
|
+
/**
|
|
266
|
+
* Check if a key was just pressed this frame
|
|
267
|
+
*
|
|
268
|
+
* @param key - Key code (e.g., 'Space', 'KeyA', 'ArrowUp')
|
|
269
|
+
* @returns True if key was just pressed (transition false→true), false otherwise
|
|
270
|
+
*
|
|
271
|
+
* @example
|
|
272
|
+
* ```typescript
|
|
273
|
+
* if (keyboard.isKeyJustPressed('Space')) {
|
|
274
|
+
* player.jump(); // Jump once per press
|
|
275
|
+
* }
|
|
276
|
+
* ```
|
|
277
|
+
*/
|
|
278
|
+
isKeyJustPressed(key: string): boolean;
|
|
279
|
+
/**
|
|
280
|
+
* Check if a key was just released this frame
|
|
281
|
+
*
|
|
282
|
+
* @param key - Key code (e.g., 'Space', 'KeyA', 'ArrowUp')
|
|
283
|
+
* @returns True if key was just released (transition true→false), false otherwise
|
|
284
|
+
*
|
|
285
|
+
* @example
|
|
286
|
+
* ```typescript
|
|
287
|
+
* if (keyboard.isKeyJustReleased('Space')) {
|
|
288
|
+
* releaseChargedShot();
|
|
289
|
+
* }
|
|
290
|
+
* ```
|
|
291
|
+
*/
|
|
292
|
+
isKeyJustReleased(key: string): boolean;
|
|
293
|
+
/**
|
|
294
|
+
* Get all currently pressed keys
|
|
295
|
+
*
|
|
296
|
+
* @returns Array of key codes currently pressed
|
|
297
|
+
*
|
|
298
|
+
* @example
|
|
299
|
+
* ```typescript
|
|
300
|
+
* const keys = keyboard.getKeysPressed();
|
|
301
|
+
* console.log('Pressed keys:', keys); // ['KeyW', 'Space']
|
|
302
|
+
* ```
|
|
303
|
+
*/
|
|
304
|
+
getKeysPressed(): string[];
|
|
305
|
+
/**
|
|
306
|
+
* Get all keys that were just pressed this frame
|
|
307
|
+
*/
|
|
308
|
+
getKeysJustPressed(): string[];
|
|
309
|
+
/**
|
|
310
|
+
* Get all keys that were just released this frame
|
|
311
|
+
*/
|
|
312
|
+
getKeysJustReleased(): string[];
|
|
313
|
+
/**
|
|
314
|
+
* Check if any key is currently pressed
|
|
315
|
+
*
|
|
316
|
+
* @returns True if at least one key is pressed, false otherwise
|
|
317
|
+
*
|
|
318
|
+
* @example
|
|
319
|
+
* ```typescript
|
|
320
|
+
* if (keyboard.isAnyKeyPressed()) {
|
|
321
|
+
* console.log('Player is active');
|
|
322
|
+
* }
|
|
323
|
+
* ```
|
|
324
|
+
*/
|
|
325
|
+
isAnyKeyPressed(): boolean;
|
|
326
|
+
/**
|
|
327
|
+
* Set keyboard-specific callbacks
|
|
328
|
+
*
|
|
329
|
+
* @param callbacks - Object containing callback functions
|
|
330
|
+
*
|
|
331
|
+
* @example
|
|
332
|
+
* ```typescript
|
|
333
|
+
* keyboard.setKeyboardCallbacks({
|
|
334
|
+
* onKeyDown: (key, event) => {
|
|
335
|
+
* console.log(`Key pressed: ${key}`);
|
|
336
|
+
* },
|
|
337
|
+
* onKeyUp: (key, event) => {
|
|
338
|
+
* console.log(`Key released: ${key}`);
|
|
339
|
+
* },
|
|
340
|
+
* });
|
|
341
|
+
* ```
|
|
342
|
+
*/
|
|
343
|
+
setKeyboardCallbacks(callbacks: KeyboardCallbacks): void;
|
|
344
|
+
clearKeyboardCallbacks(): void;
|
|
345
|
+
setCallbacks(callbacks: KeyboardCallbacks | unknown): void;
|
|
346
|
+
private isKeyboardCallbacks;
|
|
347
|
+
private handleKeyDown;
|
|
348
|
+
private handleKeyUp;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* React hook for keyboard inputs
|
|
352
|
+
*/
|
|
353
|
+
declare function useKeyboardInputs(targetElement?: HTMLElement | Window, callbacks?: KeyboardCallbacks): KeyboardInputs;
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* MouseInputs - Mouse input management
|
|
357
|
+
* Handles mouse events with support for vanilla JS, React, and other frameworks
|
|
358
|
+
*/
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Mouse button state with press/release detection
|
|
362
|
+
*/
|
|
363
|
+
interface MouseButtonState {
|
|
364
|
+
pressed: boolean;
|
|
365
|
+
justPressed: boolean;
|
|
366
|
+
justReleased: boolean;
|
|
367
|
+
}
|
|
368
|
+
interface MouseButtons {
|
|
369
|
+
left: MouseButtonState;
|
|
370
|
+
middle: MouseButtonState;
|
|
371
|
+
right: MouseButtonState;
|
|
372
|
+
}
|
|
373
|
+
interface MouseCallbacks {
|
|
374
|
+
onMouseDown?: (button: string, position: Vector2, event: MouseEvent) => void;
|
|
375
|
+
onMouseUp?: (button: string, position: Vector2, event: MouseEvent) => void;
|
|
376
|
+
onMouseMove?: (position: Vector2, delta: Vector2, event: MouseEvent) => void;
|
|
377
|
+
onMouseWheel?: (delta: number, event: WheelEvent) => void;
|
|
378
|
+
onMouseEnter?: (event: MouseEvent) => void;
|
|
379
|
+
onMouseLeave?: (event: MouseEvent) => void;
|
|
380
|
+
}
|
|
381
|
+
declare class MouseInputs extends BaseInputs {
|
|
382
|
+
private mouseButtons;
|
|
383
|
+
private mousePosition;
|
|
384
|
+
private mouseDelta;
|
|
385
|
+
private wheelDelta;
|
|
386
|
+
private mouseCallbacks;
|
|
387
|
+
private boundHandlers;
|
|
388
|
+
constructor(targetElement?: HTMLElement | Window, config?: InputConfig);
|
|
389
|
+
start(): void;
|
|
390
|
+
stop(): void;
|
|
391
|
+
reset(): void;
|
|
392
|
+
/**
|
|
393
|
+
* Poll - Reset transient states (justPressed/justReleased)
|
|
394
|
+
* Should be called once per frame AFTER collecting input
|
|
395
|
+
*/
|
|
396
|
+
poll(): void;
|
|
397
|
+
resetDelta(): void;
|
|
398
|
+
/**
|
|
399
|
+
* Check if left mouse button is pressed
|
|
400
|
+
*
|
|
401
|
+
* @returns True if left button is pressed, false otherwise
|
|
402
|
+
*
|
|
403
|
+
* @example
|
|
404
|
+
* ```typescript
|
|
405
|
+
* if (mouse.isLeftMousePressed()) {
|
|
406
|
+
* console.log('Left click detected');
|
|
407
|
+
* }
|
|
408
|
+
* ```
|
|
409
|
+
*/
|
|
410
|
+
isLeftMousePressed(): boolean;
|
|
411
|
+
/**
|
|
412
|
+
* Check if left mouse button was just pressed this frame
|
|
413
|
+
*
|
|
414
|
+
* @returns True if button was just pressed (transition false→true), false otherwise
|
|
415
|
+
*
|
|
416
|
+
* @example
|
|
417
|
+
* ```typescript
|
|
418
|
+
* if (mouse.isLeftMouseJustPressed()) {
|
|
419
|
+
* fireWeapon(); // Fires once per click
|
|
420
|
+
* }
|
|
421
|
+
* ```
|
|
422
|
+
*/
|
|
423
|
+
isLeftMouseJustPressed(): boolean;
|
|
424
|
+
/**
|
|
425
|
+
* Check if left mouse button was just released this frame
|
|
426
|
+
*
|
|
427
|
+
* @returns True if button was just released (transition true→false), false otherwise
|
|
428
|
+
*
|
|
429
|
+
* @example
|
|
430
|
+
* ```typescript
|
|
431
|
+
* if (mouse.isLeftMouseJustReleased()) {
|
|
432
|
+
* releaseChargedAttack();
|
|
433
|
+
* }
|
|
434
|
+
* ```
|
|
435
|
+
*/
|
|
436
|
+
isLeftMouseJustReleased(): boolean;
|
|
437
|
+
/**
|
|
438
|
+
* Check if right mouse button is pressed
|
|
439
|
+
*
|
|
440
|
+
* @returns True if right button is pressed, false otherwise
|
|
441
|
+
*
|
|
442
|
+
* @example
|
|
443
|
+
* ```typescript
|
|
444
|
+
* if (mouse.isRightMousePressed()) {
|
|
445
|
+
* showContextMenu();
|
|
446
|
+
* }
|
|
447
|
+
* ```
|
|
448
|
+
*/
|
|
449
|
+
isRightMousePressed(): boolean;
|
|
450
|
+
/**
|
|
451
|
+
* Check if right mouse button was just pressed this frame
|
|
452
|
+
*/
|
|
453
|
+
isRightMouseJustPressed(): boolean;
|
|
454
|
+
/**
|
|
455
|
+
* Check if right mouse button was just released this frame
|
|
456
|
+
*/
|
|
457
|
+
isRightMouseJustReleased(): boolean;
|
|
458
|
+
/**
|
|
459
|
+
* Check if middle mouse button is pressed
|
|
460
|
+
*
|
|
461
|
+
* @returns True if middle button is pressed, false otherwise
|
|
462
|
+
*/
|
|
463
|
+
isMiddleMousePressed(): boolean;
|
|
464
|
+
/**
|
|
465
|
+
* Check if middle mouse button was just pressed this frame
|
|
466
|
+
*/
|
|
467
|
+
isMiddleMouseJustPressed(): boolean;
|
|
468
|
+
/**
|
|
469
|
+
* Check if middle mouse button was just released this frame
|
|
470
|
+
*/
|
|
471
|
+
isMiddleMouseJustReleased(): boolean;
|
|
472
|
+
/**
|
|
473
|
+
* Get current mouse position
|
|
474
|
+
*
|
|
475
|
+
* @returns Vector2 with x and y coordinates in pixels
|
|
476
|
+
*
|
|
477
|
+
* @example
|
|
478
|
+
* ```typescript
|
|
479
|
+
* const pos = mouse.getMousePosition();
|
|
480
|
+
* console.log(`Mouse at (${pos.x}, ${pos.y})`);
|
|
481
|
+
* ```
|
|
482
|
+
*/
|
|
483
|
+
getMousePosition(): Vector2;
|
|
484
|
+
/**
|
|
485
|
+
* Get mouse movement delta since last frame
|
|
486
|
+
*
|
|
487
|
+
* @returns Vector2 with dx and dy in pixels
|
|
488
|
+
*
|
|
489
|
+
* @example
|
|
490
|
+
* ```typescript
|
|
491
|
+
* const delta = mouse.getMouseDelta();
|
|
492
|
+
* camera.rotate(delta.x * sensitivity, delta.y * sensitivity);
|
|
493
|
+
* ```
|
|
494
|
+
*/
|
|
495
|
+
getMouseDelta(): Vector2;
|
|
496
|
+
/**
|
|
497
|
+
* Get mouse wheel scroll delta
|
|
498
|
+
*
|
|
499
|
+
* @returns Wheel delta (positive = scroll down, negative = scroll up)
|
|
500
|
+
*
|
|
501
|
+
* @example
|
|
502
|
+
* ```typescript
|
|
503
|
+
* const wheel = mouse.getWheelDelta();
|
|
504
|
+
* if (wheel !== 0) {
|
|
505
|
+
* camera.zoom(wheel > 0 ? -1 : 1);
|
|
506
|
+
* }
|
|
507
|
+
* ```
|
|
508
|
+
*/
|
|
509
|
+
getWheelDelta(): number;
|
|
510
|
+
/**
|
|
511
|
+
* Set mouse-specific callbacks
|
|
512
|
+
*
|
|
513
|
+
* @param callbacks - Object containing callback functions
|
|
514
|
+
*
|
|
515
|
+
* @example
|
|
516
|
+
* ```typescript
|
|
517
|
+
* mouse.setMouseCallbacks({
|
|
518
|
+
* onMouseDown: (button, position, event) => {
|
|
519
|
+
* console.log(`${button} button pressed at`, position);
|
|
520
|
+
* },
|
|
521
|
+
* onMouseMove: (position, delta, event) => {
|
|
522
|
+
* console.log('Mouse moved by', delta);
|
|
523
|
+
* },
|
|
524
|
+
* onMouseWheel: (delta, event) => {
|
|
525
|
+
* console.log('Wheel scrolled:', delta);
|
|
526
|
+
* },
|
|
527
|
+
* });
|
|
528
|
+
* ```
|
|
529
|
+
*/
|
|
530
|
+
setMouseCallbacks(callbacks: MouseCallbacks): void;
|
|
531
|
+
clearMouseCallbacks(): void;
|
|
532
|
+
setCallbacks(callbacks: MouseCallbacks | unknown): void;
|
|
533
|
+
private isMouseCallbacks;
|
|
534
|
+
private handleMouseDown;
|
|
535
|
+
private handleMouseUp;
|
|
536
|
+
private handleMouseMove;
|
|
537
|
+
private handleWheel;
|
|
538
|
+
private handleMouseEnter;
|
|
539
|
+
private handleMouseLeave;
|
|
540
|
+
private handleContextMenu;
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* React hook for mouse inputs
|
|
544
|
+
*/
|
|
545
|
+
declare function useMouseInputs(targetElement?: HTMLElement | Window, callbacks?: MouseCallbacks): MouseInputs;
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* MobileInputs - Touch and mobile device input management
|
|
549
|
+
* Handles touch events with support for multi-touch, gestures, and orientation
|
|
550
|
+
*/
|
|
551
|
+
|
|
552
|
+
interface TouchPoint {
|
|
553
|
+
id: number;
|
|
554
|
+
nativeId: number;
|
|
555
|
+
position: Vector2;
|
|
556
|
+
startPosition: Vector2;
|
|
557
|
+
active: boolean;
|
|
558
|
+
justTouched: boolean;
|
|
559
|
+
justReleased: boolean;
|
|
560
|
+
}
|
|
561
|
+
interface MobileCallbacks {
|
|
562
|
+
onTouchStart?: (touches: TouchPoint[], event: TouchEvent) => void;
|
|
563
|
+
onTouchEnd?: (touches: TouchPoint[], event: TouchEvent) => void;
|
|
564
|
+
onTouchMove?: (touches: TouchPoint[], event: TouchEvent) => void;
|
|
565
|
+
onTouchCancel?: (touches: TouchPoint[], event: TouchEvent) => void;
|
|
566
|
+
onOrientationChange?: (orientation: number) => void;
|
|
567
|
+
}
|
|
568
|
+
interface MobileInputsConfig extends InputConfig {
|
|
569
|
+
/** Prevent default browser behavior (scroll, zoom) - Default: true */
|
|
570
|
+
preventDefault?: boolean;
|
|
571
|
+
/** Use passive event listeners for better performance - Default: false */
|
|
572
|
+
passive?: boolean;
|
|
573
|
+
/** Maximum number of simultaneous touches - Default: 10 */
|
|
574
|
+
maxTouches?: number;
|
|
575
|
+
}
|
|
576
|
+
declare class MobileInputs extends BaseInputs {
|
|
577
|
+
private touches;
|
|
578
|
+
private nativeToInternal;
|
|
579
|
+
private mobileCallbacks;
|
|
580
|
+
private mobileConfig;
|
|
581
|
+
private maxTouches;
|
|
582
|
+
private lastLogTime;
|
|
583
|
+
private boundHandlers;
|
|
584
|
+
constructor(targetElement?: HTMLElement | Window, config?: MobileInputsConfig);
|
|
585
|
+
start(): void;
|
|
586
|
+
stop(): void;
|
|
587
|
+
reset(): void;
|
|
588
|
+
resetDelta(): void;
|
|
589
|
+
/**
|
|
590
|
+
* Poll - Reset transient states (justTouched/justReleased)
|
|
591
|
+
* Should be called once per frame AFTER collecting input
|
|
592
|
+
*/
|
|
593
|
+
poll(): void;
|
|
594
|
+
/**
|
|
595
|
+
* Check if a touch is active (touchId 0-9)
|
|
596
|
+
*
|
|
597
|
+
* @param touchId - Touch identifier (0-9)
|
|
598
|
+
* @returns True if touch is active, false otherwise
|
|
599
|
+
*
|
|
600
|
+
* @example
|
|
601
|
+
* ```typescript
|
|
602
|
+
* if (mobile.isTouchActive(0)) {
|
|
603
|
+
* const pos = mobile.getTouchPosition(0);
|
|
604
|
+
* console.log('First touch at', pos);
|
|
605
|
+
* }
|
|
606
|
+
* ```
|
|
607
|
+
*/
|
|
608
|
+
isTouchActive(touchId: number): boolean;
|
|
609
|
+
/**
|
|
610
|
+
* Get the position of a touch (touchId 0-9)
|
|
611
|
+
*
|
|
612
|
+
* @param touchId - Touch identifier (0-9)
|
|
613
|
+
* @returns Vector2 with current position, or null if touch is not active
|
|
614
|
+
*
|
|
615
|
+
* @example
|
|
616
|
+
* ```typescript
|
|
617
|
+
* const pos = mobile.getTouchPosition(0);
|
|
618
|
+
* if (pos) {
|
|
619
|
+
* player.moveTo(pos.x, pos.y);
|
|
620
|
+
* }
|
|
621
|
+
* ```
|
|
622
|
+
*/
|
|
623
|
+
getTouchPosition(touchId: number): Vector2 | null;
|
|
624
|
+
/**
|
|
625
|
+
* Get the starting position of a touch (touchId 0-9)
|
|
626
|
+
*
|
|
627
|
+
* @param touchId - Touch identifier (0-9)
|
|
628
|
+
* @returns Vector2 with start position, or null if touch is not active
|
|
629
|
+
*
|
|
630
|
+
* @example
|
|
631
|
+
* ```typescript
|
|
632
|
+
* const start = mobile.getTouchStartPosition(0);
|
|
633
|
+
* const current = mobile.getTouchPosition(0);
|
|
634
|
+
* if (start && current) {
|
|
635
|
+
* const swipeDistance = current.subtract(start).length();
|
|
636
|
+
* if (swipeDistance > 100) {
|
|
637
|
+
* console.log('Swipe detected!');
|
|
638
|
+
* }
|
|
639
|
+
* }
|
|
640
|
+
* ```
|
|
641
|
+
*/
|
|
642
|
+
getTouchStartPosition(touchId: number): Vector2 | null;
|
|
643
|
+
/**
|
|
644
|
+
* Get the delta since the beginning of the touch
|
|
645
|
+
*
|
|
646
|
+
* @param touchId - Touch identifier (0-9)
|
|
647
|
+
* @returns Vector2 with delta from start position, or null if touch is not active
|
|
648
|
+
*
|
|
649
|
+
* @example
|
|
650
|
+
* ```typescript
|
|
651
|
+
* const delta = mobile.getTouchDelta(0);
|
|
652
|
+
* if (delta && delta.x > 50) {
|
|
653
|
+
* console.log('Swiped right!');
|
|
654
|
+
* }
|
|
655
|
+
* ```
|
|
656
|
+
*/
|
|
657
|
+
getTouchDelta(touchId: number): Vector2 | null;
|
|
658
|
+
/**
|
|
659
|
+
* Get the number of active touches
|
|
660
|
+
*
|
|
661
|
+
* @returns Number of simultaneous touches (0-10)
|
|
662
|
+
*
|
|
663
|
+
* @example
|
|
664
|
+
* ```typescript
|
|
665
|
+
* const count = mobile.getTouchCount();
|
|
666
|
+
* if (count === 2) {
|
|
667
|
+
* console.log('Pinch gesture possible');
|
|
668
|
+
* }
|
|
669
|
+
* ```
|
|
670
|
+
*/
|
|
671
|
+
getTouchCount(): number;
|
|
672
|
+
/**
|
|
673
|
+
* Check if a touch just started this frame
|
|
674
|
+
*
|
|
675
|
+
* @param touchId - Touch identifier (0-9)
|
|
676
|
+
* @returns True if touch just started, false otherwise
|
|
677
|
+
*
|
|
678
|
+
* @example
|
|
679
|
+
* ```typescript
|
|
680
|
+
* if (mobile.isTouchJustStarted(0)) {
|
|
681
|
+
* playSound('tap');
|
|
682
|
+
* }
|
|
683
|
+
* ```
|
|
684
|
+
*/
|
|
685
|
+
isTouchJustStarted(touchId: number): boolean;
|
|
686
|
+
/**
|
|
687
|
+
* Check if a touch just ended this frame
|
|
688
|
+
*
|
|
689
|
+
* @param touchId - Touch identifier (0-9)
|
|
690
|
+
* @returns True if touch just ended, false otherwise
|
|
691
|
+
*
|
|
692
|
+
* @example
|
|
693
|
+
* ```typescript
|
|
694
|
+
* if (mobile.isTouchJustReleased(0)) {
|
|
695
|
+
* releaseDragObject();
|
|
696
|
+
* }
|
|
697
|
+
* ```
|
|
698
|
+
*/
|
|
699
|
+
isTouchJustReleased(touchId: number): boolean;
|
|
700
|
+
/**
|
|
701
|
+
* Check if any touch just started this frame
|
|
702
|
+
*/
|
|
703
|
+
isAnyTouchJustStarted(): boolean;
|
|
704
|
+
/**
|
|
705
|
+
* Get all active touches
|
|
706
|
+
*
|
|
707
|
+
* @returns Array of all active TouchPoint objects
|
|
708
|
+
*
|
|
709
|
+
* @example
|
|
710
|
+
* ```typescript
|
|
711
|
+
* const touches = mobile.getAllTouches();
|
|
712
|
+
* touches.forEach(touch => {
|
|
713
|
+
* console.log(`Touch ${touch.id} at`, touch.position);
|
|
714
|
+
* });
|
|
715
|
+
* ```
|
|
716
|
+
*/
|
|
717
|
+
getAllTouches(): TouchPoint[];
|
|
718
|
+
/**
|
|
719
|
+
* Set mobile-specific callbacks
|
|
720
|
+
*
|
|
721
|
+
* @param callbacks - Object containing callback functions
|
|
722
|
+
*
|
|
723
|
+
* @example
|
|
724
|
+
* ```typescript
|
|
725
|
+
* mobile.setMobileCallbacks({
|
|
726
|
+
* onTouchStart: (touches, event) => {
|
|
727
|
+
* console.log(`${touches.length} touches started`);
|
|
728
|
+
* },
|
|
729
|
+
* onTouchMove: (touches, event) => {
|
|
730
|
+
* touches.forEach(t => console.log(`Touch ${t.id}:`, t.position));
|
|
731
|
+
* },
|
|
732
|
+
* onOrientationChange: (orientation) => {
|
|
733
|
+
* console.log('Orientation:', orientation);
|
|
734
|
+
* },
|
|
735
|
+
* });
|
|
736
|
+
* ```
|
|
737
|
+
*/
|
|
738
|
+
setMobileCallbacks(callbacks: MobileCallbacks): void;
|
|
739
|
+
clearMobileCallbacks(): void;
|
|
740
|
+
setCallbacks(callbacks: MobileCallbacks | unknown): void;
|
|
741
|
+
private isMobileCallbacks;
|
|
742
|
+
private handleTouchStart;
|
|
743
|
+
private handleTouchEnd;
|
|
744
|
+
private handleTouchMove;
|
|
745
|
+
private handleTouchCancel;
|
|
746
|
+
private handleOrientationChange;
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* React hook for mobile inputs
|
|
750
|
+
*
|
|
751
|
+
* ⚠️ IMPORTANT: This function is NOT a proper React hook!
|
|
752
|
+
* It creates a new MobileInputs instance on every render, causing memory leaks.
|
|
753
|
+
*
|
|
754
|
+
* To use correctly in React, wrap with useMemo and useEffect:
|
|
755
|
+
*
|
|
756
|
+
* @example
|
|
757
|
+
* ```typescript
|
|
758
|
+
* import { useMemo, useEffect } from 'react';
|
|
759
|
+
*
|
|
760
|
+
* const inputs = useMemo(() => new MobileInputs(canvasRef.current, config), [config]);
|
|
761
|
+
*
|
|
762
|
+
* useEffect(() => {
|
|
763
|
+
* if (callbacks) inputs.setCallbacks(callbacks);
|
|
764
|
+
* inputs.start();
|
|
765
|
+
* return () => inputs.stop();
|
|
766
|
+
* }, [inputs, callbacks]);
|
|
767
|
+
* ```
|
|
768
|
+
*
|
|
769
|
+
* @deprecated Use the pattern above instead of this function
|
|
770
|
+
*/
|
|
771
|
+
declare function useMobileInputs(targetElement?: HTMLElement | Window, callbacks?: MobileCallbacks, config?: MobileInputsConfig): MobileInputs;
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
* GamepadInputs - Gamepad/Controller input management
|
|
775
|
+
* Handles gamepad events with support for multiple controllers, buttons, axes, and vibration
|
|
776
|
+
*/
|
|
777
|
+
|
|
778
|
+
/**
|
|
779
|
+
* Gamepad button state with press detection
|
|
780
|
+
*/
|
|
781
|
+
interface GamepadButtonState {
|
|
782
|
+
pressed: boolean;
|
|
783
|
+
justPressed: boolean;
|
|
784
|
+
justReleased: boolean;
|
|
785
|
+
value: number;
|
|
786
|
+
touched: boolean;
|
|
787
|
+
}
|
|
788
|
+
/**
|
|
789
|
+
* Complete state of a single gamepad
|
|
790
|
+
*/
|
|
791
|
+
interface GamepadState {
|
|
792
|
+
id: string;
|
|
793
|
+
index: number;
|
|
794
|
+
connected: boolean;
|
|
795
|
+
buttons: GamepadButtonState[];
|
|
796
|
+
axes: number[];
|
|
797
|
+
timestamp: number;
|
|
798
|
+
mapping: GamepadMappingType;
|
|
799
|
+
hapticActuators?: GamepadHapticActuator[];
|
|
800
|
+
}
|
|
801
|
+
/**
|
|
802
|
+
* Callbacks for gamepad events
|
|
803
|
+
*/
|
|
804
|
+
interface GamepadCallbacks {
|
|
805
|
+
onGamepadConnected?: (gamepad: GamepadState) => void;
|
|
806
|
+
onGamepadDisconnected?: (index: number) => void;
|
|
807
|
+
onButtonDown?: (gamepadIndex: number, buttonIndex: number, value: number) => void;
|
|
808
|
+
onButtonUp?: (gamepadIndex: number, buttonIndex: number) => void;
|
|
809
|
+
onAxisMove?: (gamepadIndex: number, axisIndex: number, value: number) => void;
|
|
810
|
+
}
|
|
811
|
+
/**
|
|
812
|
+
* Configuration for GamepadInputs
|
|
813
|
+
*/
|
|
814
|
+
interface GamepadInputsConfig extends InputConfig {
|
|
815
|
+
/** Maximum number of gamepads to support (default: 4) */
|
|
816
|
+
maxGamepads?: number;
|
|
817
|
+
/** Deadzone for analog axes (default: 0.1) */
|
|
818
|
+
axisDeadzone?: number;
|
|
819
|
+
/** Polling interval in milliseconds (default: 16 ~= 60fps) */
|
|
820
|
+
pollingInterval?: number;
|
|
821
|
+
/** Enable automatic polling (default: true) */
|
|
822
|
+
autoPolling?: boolean;
|
|
823
|
+
}
|
|
824
|
+
declare class GamepadInputs extends BaseInputs {
|
|
825
|
+
private gamepads;
|
|
826
|
+
private previousGamepads;
|
|
827
|
+
private gamepadCallbacks;
|
|
828
|
+
private gamepadConfig;
|
|
829
|
+
private pollingIntervalId;
|
|
830
|
+
private rafId;
|
|
831
|
+
private boundHandlers;
|
|
832
|
+
constructor(config?: GamepadInputsConfig);
|
|
833
|
+
start(): void;
|
|
834
|
+
stop(): void;
|
|
835
|
+
reset(): void;
|
|
836
|
+
resetDelta(): void;
|
|
837
|
+
/**
|
|
838
|
+
* Start automatic polling of gamepad state
|
|
839
|
+
*/
|
|
840
|
+
startPolling(): void;
|
|
841
|
+
/**
|
|
842
|
+
* Stop automatic polling
|
|
843
|
+
*/
|
|
844
|
+
stopPolling(): void;
|
|
845
|
+
/**
|
|
846
|
+
* Manually poll gamepad state (call this in your game loop if autoPolling is false)
|
|
847
|
+
*
|
|
848
|
+
* @example
|
|
849
|
+
* ```typescript
|
|
850
|
+
* const gamepad = new GamepadInputs({ autoPolling: false });
|
|
851
|
+
* gamepad.start();
|
|
852
|
+
*
|
|
853
|
+
* function gameLoop() {
|
|
854
|
+
* gamepad.poll(); // Manual polling
|
|
855
|
+
* // Check inputs...
|
|
856
|
+
* requestAnimationFrame(gameLoop);
|
|
857
|
+
* }
|
|
858
|
+
* ```
|
|
859
|
+
*/
|
|
860
|
+
poll(): void;
|
|
861
|
+
/**
|
|
862
|
+
* Get the number of connected gamepads
|
|
863
|
+
*
|
|
864
|
+
* @returns Number of gamepads currently connected (0-4)
|
|
865
|
+
*
|
|
866
|
+
* @example
|
|
867
|
+
* ```typescript
|
|
868
|
+
* const count = gamepad.getConnectedGamepadCount();
|
|
869
|
+
* console.log(`${count} gamepads connected`);
|
|
870
|
+
* ```
|
|
871
|
+
*/
|
|
872
|
+
getConnectedGamepadCount(): number;
|
|
873
|
+
/**
|
|
874
|
+
* Check if a gamepad is connected at the given index
|
|
875
|
+
*
|
|
876
|
+
* @param index - Gamepad index (0-3)
|
|
877
|
+
* @returns True if gamepad is connected, false otherwise
|
|
878
|
+
*
|
|
879
|
+
* @example
|
|
880
|
+
* ```typescript
|
|
881
|
+
* if (gamepad.isGamepadConnected(0)) {
|
|
882
|
+
* console.log('Player 1 controller ready!');
|
|
883
|
+
* }
|
|
884
|
+
* ```
|
|
885
|
+
*/
|
|
886
|
+
isGamepadConnected(index: number): boolean;
|
|
887
|
+
/**
|
|
888
|
+
* Get the state of a specific gamepad
|
|
889
|
+
*/
|
|
890
|
+
getGamepadState(index: number): GamepadState | null;
|
|
891
|
+
/**
|
|
892
|
+
* Get all connected gamepads
|
|
893
|
+
*/
|
|
894
|
+
getAllGamepads(): GamepadState[];
|
|
895
|
+
/**
|
|
896
|
+
* Check if a button is currently pressed
|
|
897
|
+
*
|
|
898
|
+
* @param gamepadIndex - Gamepad index (0-3)
|
|
899
|
+
* @param buttonIndex - Button index (0-16, standard mapping)
|
|
900
|
+
* @returns True if button is pressed, false otherwise
|
|
901
|
+
* @throws {Error} If gamepadIndex or buttonIndex is invalid
|
|
902
|
+
*
|
|
903
|
+
* @example
|
|
904
|
+
* ```typescript
|
|
905
|
+
* // Check A button (Xbox) / Cross (PlayStation)
|
|
906
|
+
* if (gamepad.isButtonPressed(0, 0)) {
|
|
907
|
+
* console.log('Action button pressed!');
|
|
908
|
+
* }
|
|
909
|
+
* ```
|
|
910
|
+
*/
|
|
911
|
+
isButtonPressed(gamepadIndex: number, buttonIndex: number): boolean;
|
|
912
|
+
/**
|
|
913
|
+
* Check if a button was just pressed this frame
|
|
914
|
+
*/
|
|
915
|
+
isButtonJustPressed(gamepadIndex: number, buttonIndex: number): boolean;
|
|
916
|
+
/**
|
|
917
|
+
* Check if a button was just released this frame
|
|
918
|
+
*/
|
|
919
|
+
isButtonJustReleased(gamepadIndex: number, buttonIndex: number): boolean;
|
|
920
|
+
/**
|
|
921
|
+
* Get the analog value of a button (0.0 to 1.0)
|
|
922
|
+
*/
|
|
923
|
+
getButtonValue(gamepadIndex: number, buttonIndex: number): number;
|
|
924
|
+
/**
|
|
925
|
+
* Get the value of an axis (-1.0 to 1.0, with deadzone applied)
|
|
926
|
+
*
|
|
927
|
+
* @param gamepadIndex - Gamepad index (0-3)
|
|
928
|
+
* @param axisIndex - Axis index (0: left X, 1: left Y, 2: right X, 3: right Y)
|
|
929
|
+
* @returns Axis value from -1.0 (left/up) to 1.0 (right/down)
|
|
930
|
+
* @throws {Error} If gamepadIndex or axisIndex is invalid
|
|
931
|
+
*
|
|
932
|
+
* @example
|
|
933
|
+
* ```typescript
|
|
934
|
+
* const leftStickX = gamepad.getAxis(0, 0);
|
|
935
|
+
* const leftStickY = gamepad.getAxis(0, 1);
|
|
936
|
+
*
|
|
937
|
+
* playerX += leftStickX * speed;
|
|
938
|
+
* playerY += leftStickY * speed;
|
|
939
|
+
* ```
|
|
940
|
+
*/
|
|
941
|
+
getAxis(gamepadIndex: number, axisIndex: number): number;
|
|
942
|
+
/**
|
|
943
|
+
* Get the raw axis value without deadzone
|
|
944
|
+
*/
|
|
945
|
+
getAxisRaw(gamepadIndex: number, axisIndex: number): number;
|
|
946
|
+
/**
|
|
947
|
+
* Get left stick as a 2D vector (x: axis 0, y: axis 1)
|
|
948
|
+
*
|
|
949
|
+
* @param gamepadIndex - Gamepad index (0-3)
|
|
950
|
+
* @returns Object with x and y properties (-1.0 to 1.0)
|
|
951
|
+
*
|
|
952
|
+
* @example
|
|
953
|
+
* ```typescript
|
|
954
|
+
* const leftStick = gamepad.getLeftStick(0);
|
|
955
|
+
*
|
|
956
|
+
* if (Math.abs(leftStick.x) > 0.5) {
|
|
957
|
+
* console.log('Strong horizontal input');
|
|
958
|
+
* }
|
|
959
|
+
*
|
|
960
|
+
* // Calculate magnitude for movement
|
|
961
|
+
* const magnitude = Math.sqrt(leftStick.x ** 2 + leftStick.y ** 2);
|
|
962
|
+
* ```
|
|
963
|
+
*/
|
|
964
|
+
getLeftStick(gamepadIndex: number): {
|
|
965
|
+
x: number;
|
|
966
|
+
y: number;
|
|
967
|
+
};
|
|
968
|
+
/**
|
|
969
|
+
* Get right stick as a 2D vector (x: axis 2, y: axis 3)
|
|
970
|
+
*/
|
|
971
|
+
getRightStick(gamepadIndex: number): {
|
|
972
|
+
x: number;
|
|
973
|
+
y: number;
|
|
974
|
+
};
|
|
975
|
+
/**
|
|
976
|
+
* Set gamepad-specific callbacks
|
|
977
|
+
*
|
|
978
|
+
* @param callbacks - Object containing callback functions
|
|
979
|
+
*
|
|
980
|
+
* @example
|
|
981
|
+
* ```typescript
|
|
982
|
+
* gamepad.setGamepadCallbacks({
|
|
983
|
+
* onGamepadConnected: (state) => {
|
|
984
|
+
* console.log(`Gamepad connected: ${state.id}`);
|
|
985
|
+
* },
|
|
986
|
+
* onButtonDown: (gamepadIndex, buttonIndex, value) => {
|
|
987
|
+
* console.log(`Button ${buttonIndex} pressed with value ${value}`);
|
|
988
|
+
* },
|
|
989
|
+
* onAxisMove: (gamepadIndex, axisIndex, value) => {
|
|
990
|
+
* console.log(`Axis ${axisIndex} moved to ${value}`);
|
|
991
|
+
* },
|
|
992
|
+
* });
|
|
993
|
+
* ```
|
|
994
|
+
*/
|
|
995
|
+
setGamepadCallbacks(callbacks: GamepadCallbacks): void;
|
|
996
|
+
/**
|
|
997
|
+
* Clear all gamepad callbacks
|
|
998
|
+
*/
|
|
999
|
+
clearGamepadCallbacks(): void;
|
|
1000
|
+
setCallbacks(callbacks: GamepadCallbacks | unknown): void;
|
|
1001
|
+
private isGamepadCallbacks;
|
|
1002
|
+
private updateGamepadState;
|
|
1003
|
+
private triggerCallbacks;
|
|
1004
|
+
private handleGamepadConnected;
|
|
1005
|
+
private handleGamepadDisconnected;
|
|
1006
|
+
private applyDeadzone;
|
|
1007
|
+
private cloneGamepadState;
|
|
1008
|
+
}
|
|
1009
|
+
/**
|
|
1010
|
+
* React hook for gamepad inputs
|
|
1011
|
+
*/
|
|
1012
|
+
declare function useGamepadInputs(callbacks?: GamepadCallbacks, config?: GamepadInputsConfig): GamepadInputs;
|
|
1013
|
+
|
|
1014
|
+
/**
|
|
1015
|
+
* UnifiedInputRouter - Unified input routing system
|
|
1016
|
+
* Provides a standardized API to query input states across all devices using numeric enums
|
|
1017
|
+
*
|
|
1018
|
+
* @example
|
|
1019
|
+
* ```ts
|
|
1020
|
+
* const router = new UnifiedInputRouter();
|
|
1021
|
+
*
|
|
1022
|
+
* // Check if space key is pressed
|
|
1023
|
+
* const jump = router.getButton(InputDeviceType.Keyboard, KeyboardInput.Space);
|
|
1024
|
+
*
|
|
1025
|
+
* // Get mouse X position
|
|
1026
|
+
* const mouseX = router.getAxis(InputDeviceType.Mouse, MouseInput.PositionX);
|
|
1027
|
+
*
|
|
1028
|
+
* // Check gamepad button A
|
|
1029
|
+
* const action = router.getButton(InputDeviceType.Gamepad, GamepadInput.ButtonA);
|
|
1030
|
+
* ```
|
|
1031
|
+
*/
|
|
1032
|
+
|
|
1033
|
+
/**
|
|
1034
|
+
* Configuration options for the input router
|
|
1035
|
+
*/
|
|
1036
|
+
interface InputRouterConfig {
|
|
1037
|
+
enableKeyboardMouse?: boolean;
|
|
1038
|
+
enableGamepad?: boolean;
|
|
1039
|
+
enableMobile?: boolean;
|
|
1040
|
+
targetElement?: HTMLElement | Window;
|
|
1041
|
+
/** Separate target for mobile/touch input (default: uses targetElement) */
|
|
1042
|
+
mobileTargetElement?: HTMLElement | Window;
|
|
1043
|
+
debug?: boolean;
|
|
1044
|
+
/** Keyboard-specific config */
|
|
1045
|
+
keyboardConfig?: {
|
|
1046
|
+
preventDefault?: boolean;
|
|
1047
|
+
stopPropagation?: boolean;
|
|
1048
|
+
};
|
|
1049
|
+
/** Mouse-specific config */
|
|
1050
|
+
mouseConfig?: {
|
|
1051
|
+
preventDefault?: boolean;
|
|
1052
|
+
stopPropagation?: boolean;
|
|
1053
|
+
};
|
|
1054
|
+
/** Mobile-specific config */
|
|
1055
|
+
mobileConfig?: {
|
|
1056
|
+
preventDefault?: boolean;
|
|
1057
|
+
passive?: boolean;
|
|
1058
|
+
maxTouches?: number;
|
|
1059
|
+
};
|
|
1060
|
+
}
|
|
1061
|
+
/**
|
|
1062
|
+
* Unified input router - manages all input devices with a type-safe enum-based API
|
|
1063
|
+
* Implements IInputSystem interface for dependency injection with core
|
|
1064
|
+
*/
|
|
1065
|
+
declare class UnifiedInputRouter implements IInputSystem {
|
|
1066
|
+
private keyboard;
|
|
1067
|
+
private mouse;
|
|
1068
|
+
private gamepad;
|
|
1069
|
+
private mobile;
|
|
1070
|
+
private config;
|
|
1071
|
+
constructor(config?: InputRouterConfig);
|
|
1072
|
+
private initialize;
|
|
1073
|
+
/**
|
|
1074
|
+
* Query a button state (returns boolean)
|
|
1075
|
+
*/
|
|
1076
|
+
getButton(device: InputDeviceType, input: number): boolean;
|
|
1077
|
+
/**
|
|
1078
|
+
* Query if a button was just pressed this frame (transition false→true)
|
|
1079
|
+
*/
|
|
1080
|
+
getButtonJustPressed(device: InputDeviceType, input: number): boolean;
|
|
1081
|
+
/**
|
|
1082
|
+
* Query if a button was just released this frame (transition true→false)
|
|
1083
|
+
*/
|
|
1084
|
+
getButtonJustReleased(device: InputDeviceType, input: number): boolean;
|
|
1085
|
+
/**
|
|
1086
|
+
* Query an axis value (returns number)
|
|
1087
|
+
*/
|
|
1088
|
+
getAxis(device: InputDeviceType, input: number): number;
|
|
1089
|
+
private getKeyboardButton;
|
|
1090
|
+
private getKeyboardButtonJustPressed;
|
|
1091
|
+
private getKeyboardButtonJustReleased;
|
|
1092
|
+
private getMouseButton;
|
|
1093
|
+
private getMouseButtonJustPressed;
|
|
1094
|
+
private getMouseButtonJustReleased;
|
|
1095
|
+
private getGamepadButton;
|
|
1096
|
+
private getGamepadButtonJustPressed;
|
|
1097
|
+
private getGamepadButtonJustReleased;
|
|
1098
|
+
private getTouchButton;
|
|
1099
|
+
private getTouchButtonJustPressed;
|
|
1100
|
+
private getTouchButtonJustReleased;
|
|
1101
|
+
private getMouseAxis;
|
|
1102
|
+
private getGamepadAxis;
|
|
1103
|
+
private getTouchAxis;
|
|
1104
|
+
/**
|
|
1105
|
+
* Get mouse position (screen coordinates)
|
|
1106
|
+
*/
|
|
1107
|
+
getMousePosition(): {
|
|
1108
|
+
x: number;
|
|
1109
|
+
y: number;
|
|
1110
|
+
} | null;
|
|
1111
|
+
/**
|
|
1112
|
+
* Reconfigure mobile input target after initialization
|
|
1113
|
+
* (Used when canvas is created after InputRouter construction)
|
|
1114
|
+
* Mobile input will ONLY be activated if a valid canvas is provided
|
|
1115
|
+
*/
|
|
1116
|
+
setMobileTarget(canvas: HTMLElement | Window): void;
|
|
1117
|
+
/**
|
|
1118
|
+
* Get text inputs captured this frame from keyboard
|
|
1119
|
+
* Returns actual characters typed (handles keyboard layout, modifiers, etc.)
|
|
1120
|
+
*
|
|
1121
|
+
* @returns Array of character strings typed this frame
|
|
1122
|
+
*/
|
|
1123
|
+
getTextInputs(): string[];
|
|
1124
|
+
start(): void;
|
|
1125
|
+
stop(): void;
|
|
1126
|
+
reset(): void;
|
|
1127
|
+
/**
|
|
1128
|
+
* Poll transient states - Reset justPressed/justReleased flags
|
|
1129
|
+
* Should be called once per frame AFTER collecting input
|
|
1130
|
+
*/
|
|
1131
|
+
poll(): void;
|
|
1132
|
+
isListening(): boolean;
|
|
1133
|
+
destroy(): void;
|
|
1134
|
+
private log;
|
|
1135
|
+
private warn;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
/**
|
|
1139
|
+
* InputCollector - Adapter between UnifiedInputRouter and InputBindingRegistry
|
|
1140
|
+
*
|
|
1141
|
+
* This module bridges the gap between:
|
|
1142
|
+
* - @utsp/input (raw device inputs)
|
|
1143
|
+
* - @utsp/core (logical input evaluation with InputBindingRegistry)
|
|
1144
|
+
*
|
|
1145
|
+
* InputCollector's sole responsibility is to read raw values from IInputSystem
|
|
1146
|
+
* and prepare them as Map<sourceId, value> for InputBindingRegistry.evaluateAxis/Button.
|
|
1147
|
+
*
|
|
1148
|
+
* @example
|
|
1149
|
+
* ```typescript
|
|
1150
|
+
* // Collect raw source values
|
|
1151
|
+
* const axisSources = InputCollector.collectAxisSources(axisBindings, inputRouter);
|
|
1152
|
+
* const buttonSources = InputCollector.collectButtonSources(buttonBindings, inputRouter);
|
|
1153
|
+
*
|
|
1154
|
+
* // Let InputBindingRegistry handle scale/sensitivity/invert/OR logic
|
|
1155
|
+
* axisBindings.forEach(binding => {
|
|
1156
|
+
* const value = registry.evaluateAxis(binding.bindingId, axisSources);
|
|
1157
|
+
* user.setAxis(binding.name, value);
|
|
1158
|
+
* });
|
|
1159
|
+
* ```
|
|
1160
|
+
*/
|
|
1161
|
+
|
|
1162
|
+
/**
|
|
1163
|
+
* Button state with transition detection (pressed, justPressed, justReleased)
|
|
1164
|
+
*/
|
|
1165
|
+
interface ButtonStateWithTransitions {
|
|
1166
|
+
pressed: boolean;
|
|
1167
|
+
justPressed: boolean;
|
|
1168
|
+
justReleased: boolean;
|
|
1169
|
+
}
|
|
1170
|
+
/**
|
|
1171
|
+
* Input collection utilities
|
|
1172
|
+
*
|
|
1173
|
+
* Provides static methods to collect raw input values from an IInputSystem
|
|
1174
|
+
* and prepare them for InputBindingRegistry evaluation.
|
|
1175
|
+
*/
|
|
1176
|
+
declare class InputCollector {
|
|
1177
|
+
/**
|
|
1178
|
+
* Collects raw source values for all axis bindings
|
|
1179
|
+
*
|
|
1180
|
+
* Returns a Map where:
|
|
1181
|
+
* - Key: sourceId (from AxisBinding.sources)
|
|
1182
|
+
* - Value: raw axis value from the input router
|
|
1183
|
+
*
|
|
1184
|
+
* This method reads raw device values (keyboard -1/0/+1, mouse delta, gamepad stick, touch position)
|
|
1185
|
+
* WITHOUT applying scale/sensitivity/invert. InputBindingRegistry.evaluateAxis() will handle that.
|
|
1186
|
+
*
|
|
1187
|
+
* @param bindings - Axis bindings from InputBindingRegistry
|
|
1188
|
+
* @param router - Input system (typically UnifiedInputRouter)
|
|
1189
|
+
* @returns Map of sourceId → raw value
|
|
1190
|
+
*
|
|
1191
|
+
* @example
|
|
1192
|
+
* ```typescript
|
|
1193
|
+
* const registry = user.getInputBindingRegistry();
|
|
1194
|
+
* const axisBindings = registry.getAllAxes();
|
|
1195
|
+
* const sourceValues = InputCollector.collectAxisSources(axisBindings, inputRouter);
|
|
1196
|
+
*
|
|
1197
|
+
* // Then use InputBindingRegistry to evaluate with scale/sensitivity/invert:
|
|
1198
|
+
* axisBindings.forEach(binding => {
|
|
1199
|
+
* const finalValue = registry.evaluateAxis(binding.bindingId, sourceValues);
|
|
1200
|
+
* user.setAxis(binding.name, finalValue);
|
|
1201
|
+
* });
|
|
1202
|
+
* ```
|
|
1203
|
+
*/
|
|
1204
|
+
static collectAxisSources(bindings: AxisBinding[], router: IInputSystem): Map<number, number>;
|
|
1205
|
+
/**
|
|
1206
|
+
* Collects raw source states for all button bindings
|
|
1207
|
+
*
|
|
1208
|
+
* Returns a Map where:
|
|
1209
|
+
* - Key: sourceId (from ButtonBinding.sources)
|
|
1210
|
+
* - Value: raw button state (pressed/released) from the input router
|
|
1211
|
+
*
|
|
1212
|
+
* This method reads raw device button states WITHOUT applying OR logic.
|
|
1213
|
+
* InputBindingRegistry.evaluateButton() will handle the OR logic across all sources.
|
|
1214
|
+
*
|
|
1215
|
+
* @param bindings - Button bindings from InputBindingRegistry
|
|
1216
|
+
* @param router - Input system (typically UnifiedInputRouter)
|
|
1217
|
+
* @returns Map of sourceId → pressed state
|
|
1218
|
+
*
|
|
1219
|
+
* @example
|
|
1220
|
+
* ```typescript
|
|
1221
|
+
* const registry = user.getInputBindingRegistry();
|
|
1222
|
+
* const buttonBindings = registry.getAllButtons();
|
|
1223
|
+
* const sourceStates = InputCollector.collectButtonSources(buttonBindings, inputRouter);
|
|
1224
|
+
*
|
|
1225
|
+
* // Then use InputBindingRegistry to evaluate with OR logic:
|
|
1226
|
+
* buttonBindings.forEach(binding => {
|
|
1227
|
+
* const pressed = registry.evaluateButton(binding.bindingId, sourceStates);
|
|
1228
|
+
* user.setButton(binding.name, pressed);
|
|
1229
|
+
* });
|
|
1230
|
+
* ```
|
|
1231
|
+
*/
|
|
1232
|
+
static collectButtonSources(bindings: ButtonBinding[], router: IInputSystem): Map<number, boolean>;
|
|
1233
|
+
/**
|
|
1234
|
+
* Collects raw source states with transition detection for all button bindings
|
|
1235
|
+
*
|
|
1236
|
+
* Returns a Map where:
|
|
1237
|
+
* - Key: sourceId (from ButtonBinding.sources)
|
|
1238
|
+
* - Value: ButtonStateWithTransitions { pressed, justPressed, justReleased }
|
|
1239
|
+
*
|
|
1240
|
+
* This method reads raw device button states including transition flags.
|
|
1241
|
+
* Use this to collect justPressed/justReleased states in addition to pressed.
|
|
1242
|
+
*
|
|
1243
|
+
* @param bindings - Button bindings from InputBindingRegistry
|
|
1244
|
+
* @param router - Input system (typically UnifiedInputRouter with getButtonJustPressed/Released)
|
|
1245
|
+
* @returns Map of sourceId → ButtonStateWithTransitions
|
|
1246
|
+
*
|
|
1247
|
+
* @example
|
|
1248
|
+
* ```typescript
|
|
1249
|
+
* const registry = user.getInputBindingRegistry();
|
|
1250
|
+
* const buttonBindings = registry.getAllButtons();
|
|
1251
|
+
* const sourceStates = InputCollector.collectButtonSourcesWithTransitions(buttonBindings, inputRouter);
|
|
1252
|
+
*
|
|
1253
|
+
* buttonBindings.forEach(binding => {
|
|
1254
|
+
* // Evaluate each state independently (OR across sources)
|
|
1255
|
+
* const pressed = registry.evaluateButton(binding.bindingId, new Map([...sourceStates].map(([k,v]) => [k, v.pressed])));
|
|
1256
|
+
* const justPressed = registry.evaluateButton(binding.bindingId, new Map([...sourceStates].map(([k,v]) => [k, v.justPressed])));
|
|
1257
|
+
* const justReleased = registry.evaluateButton(binding.bindingId, new Map([...sourceStates].map(([k,v]) => [k, v.justReleased])));
|
|
1258
|
+
*
|
|
1259
|
+
* user.setButton(binding.name, pressed);
|
|
1260
|
+
* user.setButton(\`\${binding.name}_justPressed\`, justPressed);
|
|
1261
|
+
* user.setButton(\`\${binding.name}_justReleased\`, justReleased);
|
|
1262
|
+
* });
|
|
1263
|
+
* ```
|
|
1264
|
+
*/
|
|
1265
|
+
static collectButtonSourcesWithTransitions(bindings: ButtonBinding[], router: IInputSystem): Map<number, ButtonStateWithTransitions>;
|
|
1266
|
+
/**
|
|
1267
|
+
* Calculate mouse position in grid coordinates
|
|
1268
|
+
*
|
|
1269
|
+
* Converts screen-space mouse position to grid cell coordinates (column/row).
|
|
1270
|
+
* Handles canvas scaling and provides an "over" flag for out-of-bounds detection.
|
|
1271
|
+
*
|
|
1272
|
+
* @param router - Input system (typically UnifiedInputRouter)
|
|
1273
|
+
* @param canvas - Canvas element to calculate relative position
|
|
1274
|
+
* @param gridWidth - Number of columns in the grid
|
|
1275
|
+
* @param gridHeight - Number of rows in the grid
|
|
1276
|
+
* @param rendererOffsets - Optional renderer content offsets (for centered rendering)
|
|
1277
|
+
* @returns Grid position {x: column, y: row, over: boolean}
|
|
1278
|
+
*
|
|
1279
|
+
* @example
|
|
1280
|
+
* ```typescript
|
|
1281
|
+
* const offsets = renderer.getOffsets?.() || { offsetX: 0, offsetY: 0 };
|
|
1282
|
+
* const mousePos = InputCollector.collectMousePosition(
|
|
1283
|
+
* inputRouter,
|
|
1284
|
+
* renderer.getCanvas(),
|
|
1285
|
+
* 80, // columns
|
|
1286
|
+
* 24, // rows
|
|
1287
|
+
* offsets
|
|
1288
|
+
* );
|
|
1289
|
+
* user.setMousePosition(mousePos.x, mousePos.y, mousePos.over, 0);
|
|
1290
|
+
* ```
|
|
1291
|
+
*/
|
|
1292
|
+
static collectMousePosition(router: IInputSystem, canvas: HTMLCanvasElement, gridWidth: number, gridHeight: number, rendererOffsets?: {
|
|
1293
|
+
offsetX: number;
|
|
1294
|
+
offsetY: number;
|
|
1295
|
+
}): {
|
|
1296
|
+
x: number;
|
|
1297
|
+
y: number;
|
|
1298
|
+
over: boolean;
|
|
1299
|
+
};
|
|
1300
|
+
/**
|
|
1301
|
+
* Calculate touch positions in grid coordinates
|
|
1302
|
+
*
|
|
1303
|
+
* Converts screen-space touch positions to grid cell coordinates for all active touches.
|
|
1304
|
+
* Handles canvas scaling and provides an "over" flag for out-of-bounds detection.
|
|
1305
|
+
*
|
|
1306
|
+
* @param router - Input system (typically UnifiedInputRouter)
|
|
1307
|
+
* @param canvas - Canvas element to calculate relative position
|
|
1308
|
+
* @param gridWidth - Number of columns in the grid
|
|
1309
|
+
* @param gridHeight - Number of rows in the grid
|
|
1310
|
+
* @param maxTouches - Maximum number of touches to check (default: 10)
|
|
1311
|
+
* @param rendererOffsets - Optional renderer content offsets (for centered rendering)
|
|
1312
|
+
* @returns Array of touch positions {id, x: column, y: row, over: boolean}
|
|
1313
|
+
*
|
|
1314
|
+
* @example
|
|
1315
|
+
* ```typescript
|
|
1316
|
+
* const offsets = renderer.getOffsets?.() || { offsetX: 0, offsetY: 0 };
|
|
1317
|
+
* const touches = InputCollector.collectTouchPositions(
|
|
1318
|
+
* inputRouter,
|
|
1319
|
+
* renderer.getCanvas(),
|
|
1320
|
+
* 80, // columns
|
|
1321
|
+
* 24, // rows
|
|
1322
|
+
* 10, // max touches
|
|
1323
|
+
* offsets
|
|
1324
|
+
* );
|
|
1325
|
+
* touches.forEach(touch => {
|
|
1326
|
+
* user.setTouchPosition(touch.id, touch.x, touch.y, touch.over, 0);
|
|
1327
|
+
* });
|
|
1328
|
+
* ```
|
|
1329
|
+
*/
|
|
1330
|
+
static collectTouchPositions(router: IInputSystem, canvas: HTMLCanvasElement, gridWidth: number, gridHeight: number, maxTouches?: number, rendererOffsets?: {
|
|
1331
|
+
offsetX: number;
|
|
1332
|
+
offsetY: number;
|
|
1333
|
+
}): Array<{
|
|
1334
|
+
id: number;
|
|
1335
|
+
x: number;
|
|
1336
|
+
y: number;
|
|
1337
|
+
over: boolean;
|
|
1338
|
+
}>;
|
|
1339
|
+
/**
|
|
1340
|
+
* Collects text input events from keyboard
|
|
1341
|
+
*
|
|
1342
|
+
* Returns array of character strings typed this frame.
|
|
1343
|
+
* Uses event.key to capture actual characters (handles keyboard layout automatically).
|
|
1344
|
+
*
|
|
1345
|
+
* @param router - Input system (typically UnifiedInputRouter)
|
|
1346
|
+
* @returns Array of character strings typed this frame
|
|
1347
|
+
*
|
|
1348
|
+
* @example
|
|
1349
|
+
* ```typescript
|
|
1350
|
+
* const textInputs = InputCollector.collectTextInputs(inputRouter);
|
|
1351
|
+
* // textInputs might be: ['a', 'b', 'c', 'é', '@', ' ']
|
|
1352
|
+
* // Pass to network encoder or process locally
|
|
1353
|
+
* ```
|
|
1354
|
+
*/
|
|
1355
|
+
static collectTextInputs(router: IInputSystem): string[];
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
export { BaseInputs, GamepadInputs, InputCollector, InputEventType, KeyboardInputs, MobileInputs, MouseInputs, UnifiedInputRouter, isInputs, useGamepadInputs, useKeyboardInputs, useMobileInputs, useMouseInputs };
|
|
1359
|
+
export type { ButtonState, GamepadButtonState, GamepadCallbacks, GamepadInputsConfig, GamepadState, IInputs, InputConfig, InputDevice, InputEvent, InputRouterConfig, KeyState, KeyboardCallbacks, MobileCallbacks, MobileInputsConfig, MotionData, MouseButtonState, MouseButtons, MouseCallbacks, TouchPoint };
|