@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.
@@ -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 };