@utsp/input 0.10.0-nightly.20251211194839.e68c16e → 0.10.0-nightly.20251213135145.115c488
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core.cjs +1 -0
- package/dist/core.d.ts +200 -0
- package/dist/core.mjs +1 -0
- package/dist/desktop.cjs +1 -0
- package/dist/desktop.d.ts +540 -0
- package/dist/desktop.mjs +1 -0
- package/dist/gamepad.cjs +1 -0
- package/dist/gamepad.d.ts +563 -0
- package/dist/gamepad.mjs +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +369 -5
- package/dist/index.mjs +1 -1
- package/dist/keyboard.cjs +1 -0
- package/dist/keyboard.d.ts +341 -0
- package/dist/keyboard.mjs +1 -0
- package/dist/mouse.cjs +1 -0
- package/dist/mouse.d.ts +376 -0
- package/dist/mouse.mjs +1 -0
- package/dist/touch.cjs +1 -0
- package/dist/touch.d.ts +572 -0
- package/dist/touch.mjs +1 -0
- package/package.json +54 -2
package/dist/touch.d.ts
ADDED
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
import { Vector2, Vector3, IMobileVibrationProcessor, VibrationPattern } from '@utsp/types';
|
|
2
|
+
export { InputDeviceType, TouchInput, Vector2, VibrationPattern } 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
|
+
* Configuration options for input systems
|
|
109
|
+
*/
|
|
110
|
+
interface InputConfig {
|
|
111
|
+
/**
|
|
112
|
+
* Target element to attach listeners to (default: window)
|
|
113
|
+
*/
|
|
114
|
+
targetElement?: HTMLElement | Window;
|
|
115
|
+
/**
|
|
116
|
+
* Enable/disable specific input types
|
|
117
|
+
*/
|
|
118
|
+
enabled?: boolean;
|
|
119
|
+
/**
|
|
120
|
+
* Prevent default browser behaviors
|
|
121
|
+
*/
|
|
122
|
+
preventDefault?: boolean;
|
|
123
|
+
/**
|
|
124
|
+
* Stop event propagation
|
|
125
|
+
*/
|
|
126
|
+
stopPropagation?: boolean;
|
|
127
|
+
/**
|
|
128
|
+
* Enable debug logging
|
|
129
|
+
*/
|
|
130
|
+
debug?: boolean;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Abstract base class for input systems
|
|
134
|
+
* All input classes should extend this to maintain consistency
|
|
135
|
+
*/
|
|
136
|
+
declare abstract class BaseInputs implements IInputs {
|
|
137
|
+
protected isActive: boolean;
|
|
138
|
+
protected targetElement: HTMLElement | Window;
|
|
139
|
+
protected config: InputConfig;
|
|
140
|
+
protected callbacks: Record<string, ((...args: any[]) => void)[]>;
|
|
141
|
+
constructor(targetElement?: HTMLElement | Window, config?: InputConfig);
|
|
142
|
+
abstract start(): void;
|
|
143
|
+
abstract stop(): void;
|
|
144
|
+
abstract reset(): void;
|
|
145
|
+
abstract resetDelta(): void;
|
|
146
|
+
isListening(): boolean;
|
|
147
|
+
destroy(): void;
|
|
148
|
+
setCallbacks(callbacks: unknown): void;
|
|
149
|
+
clearCallbacks(): void;
|
|
150
|
+
/**
|
|
151
|
+
* Get the target element
|
|
152
|
+
*/
|
|
153
|
+
getTargetElement(): HTMLElement | Window;
|
|
154
|
+
/**
|
|
155
|
+
* Enable the input system
|
|
156
|
+
*/
|
|
157
|
+
enable(): void;
|
|
158
|
+
/**
|
|
159
|
+
* Disable the input system
|
|
160
|
+
*/
|
|
161
|
+
disable(): void;
|
|
162
|
+
/**
|
|
163
|
+
* Check if the input system is enabled
|
|
164
|
+
*/
|
|
165
|
+
isEnabled(): boolean;
|
|
166
|
+
/**
|
|
167
|
+
* Emit an event to all registered callbacks
|
|
168
|
+
*/
|
|
169
|
+
protected emit(eventType: string, ...args: unknown[]): void;
|
|
170
|
+
/**
|
|
171
|
+
* Log debug messages if debug mode is enabled
|
|
172
|
+
*/
|
|
173
|
+
protected log(...args: unknown[]): void;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* MobileInputs - Touch and mobile device input management
|
|
178
|
+
* Handles touch events with support for multi-touch, gestures, and orientation
|
|
179
|
+
*/
|
|
180
|
+
|
|
181
|
+
interface TouchPoint {
|
|
182
|
+
id: number;
|
|
183
|
+
nativeId: number;
|
|
184
|
+
position: Vector2;
|
|
185
|
+
startPosition: Vector2;
|
|
186
|
+
active: boolean;
|
|
187
|
+
justTouched: boolean;
|
|
188
|
+
justReleased: boolean;
|
|
189
|
+
}
|
|
190
|
+
interface MobileCallbacks {
|
|
191
|
+
onTouchStart?: (touches: TouchPoint[], event: TouchEvent) => void;
|
|
192
|
+
onTouchEnd?: (touches: TouchPoint[], event: TouchEvent) => void;
|
|
193
|
+
onTouchMove?: (touches: TouchPoint[], event: TouchEvent) => void;
|
|
194
|
+
onTouchCancel?: (touches: TouchPoint[], event: TouchEvent) => void;
|
|
195
|
+
onOrientationChange?: (orientation: number) => void;
|
|
196
|
+
}
|
|
197
|
+
interface MobileInputsConfig extends InputConfig {
|
|
198
|
+
/** Prevent default browser behavior (scroll, zoom) - Default: true */
|
|
199
|
+
preventDefault?: boolean;
|
|
200
|
+
/** Use passive event listeners for better performance - Default: false */
|
|
201
|
+
passive?: boolean;
|
|
202
|
+
/** Maximum number of simultaneous touches - Default: 10 */
|
|
203
|
+
maxTouches?: number;
|
|
204
|
+
}
|
|
205
|
+
declare class MobileInputs extends BaseInputs {
|
|
206
|
+
private touches;
|
|
207
|
+
private nativeToInternal;
|
|
208
|
+
private mobileCallbacks;
|
|
209
|
+
private mobileConfig;
|
|
210
|
+
private maxTouches;
|
|
211
|
+
private lastLogTime;
|
|
212
|
+
private boundHandlers;
|
|
213
|
+
constructor(targetElement?: HTMLElement | Window, config?: MobileInputsConfig);
|
|
214
|
+
start(): void;
|
|
215
|
+
stop(): void;
|
|
216
|
+
reset(): void;
|
|
217
|
+
resetDelta(): void;
|
|
218
|
+
/**
|
|
219
|
+
* Poll - Reset transient states (justTouched/justReleased)
|
|
220
|
+
* Should be called once per frame AFTER collecting input
|
|
221
|
+
*/
|
|
222
|
+
poll(): void;
|
|
223
|
+
/**
|
|
224
|
+
* Check if a touch is active (touchId 0-9)
|
|
225
|
+
*
|
|
226
|
+
* @param touchId - Touch identifier (0-9)
|
|
227
|
+
* @returns True if touch is active, false otherwise
|
|
228
|
+
*
|
|
229
|
+
* @example
|
|
230
|
+
* ```typescript
|
|
231
|
+
* if (mobile.isTouchActive(0)) {
|
|
232
|
+
* const pos = mobile.getTouchPosition(0);
|
|
233
|
+
* console.log('First touch at', pos);
|
|
234
|
+
* }
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
isTouchActive(touchId: number): boolean;
|
|
238
|
+
/**
|
|
239
|
+
* Get the position of a touch (touchId 0-9)
|
|
240
|
+
*
|
|
241
|
+
* @param touchId - Touch identifier (0-9)
|
|
242
|
+
* @returns Vector2 with current position, or null if touch is not active
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* ```typescript
|
|
246
|
+
* const pos = mobile.getTouchPosition(0);
|
|
247
|
+
* if (pos) {
|
|
248
|
+
* player.moveTo(pos.x, pos.y);
|
|
249
|
+
* }
|
|
250
|
+
* ```
|
|
251
|
+
*/
|
|
252
|
+
getTouchPosition(touchId: number): Vector2 | null;
|
|
253
|
+
/**
|
|
254
|
+
* Get the starting position of a touch (touchId 0-9)
|
|
255
|
+
*
|
|
256
|
+
* @param touchId - Touch identifier (0-9)
|
|
257
|
+
* @returns Vector2 with start position, or null if touch is not active
|
|
258
|
+
*
|
|
259
|
+
* @example
|
|
260
|
+
* ```typescript
|
|
261
|
+
* const start = mobile.getTouchStartPosition(0);
|
|
262
|
+
* const current = mobile.getTouchPosition(0);
|
|
263
|
+
* if (start && current) {
|
|
264
|
+
* const swipeDistance = current.subtract(start).length();
|
|
265
|
+
* if (swipeDistance > 100) {
|
|
266
|
+
* console.log('Swipe detected!');
|
|
267
|
+
* }
|
|
268
|
+
* }
|
|
269
|
+
* ```
|
|
270
|
+
*/
|
|
271
|
+
getTouchStartPosition(touchId: number): Vector2 | null;
|
|
272
|
+
/**
|
|
273
|
+
* Get the delta since the beginning of the touch
|
|
274
|
+
*
|
|
275
|
+
* @param touchId - Touch identifier (0-9)
|
|
276
|
+
* @returns Vector2 with delta from start position, or null if touch is not active
|
|
277
|
+
*
|
|
278
|
+
* @example
|
|
279
|
+
* ```typescript
|
|
280
|
+
* const delta = mobile.getTouchDelta(0);
|
|
281
|
+
* if (delta && delta.x > 50) {
|
|
282
|
+
* console.log('Swiped right!');
|
|
283
|
+
* }
|
|
284
|
+
* ```
|
|
285
|
+
*/
|
|
286
|
+
getTouchDelta(touchId: number): Vector2 | null;
|
|
287
|
+
/**
|
|
288
|
+
* Get the number of active touches
|
|
289
|
+
*
|
|
290
|
+
* @returns Number of simultaneous touches (0-10)
|
|
291
|
+
*
|
|
292
|
+
* @example
|
|
293
|
+
* ```typescript
|
|
294
|
+
* const count = mobile.getTouchCount();
|
|
295
|
+
* if (count === 2) {
|
|
296
|
+
* console.log('Pinch gesture possible');
|
|
297
|
+
* }
|
|
298
|
+
* ```
|
|
299
|
+
*/
|
|
300
|
+
getTouchCount(): number;
|
|
301
|
+
/**
|
|
302
|
+
* Check if a touch just started this frame
|
|
303
|
+
*
|
|
304
|
+
* @param touchId - Touch identifier (0-9)
|
|
305
|
+
* @returns True if touch just started, false otherwise
|
|
306
|
+
*
|
|
307
|
+
* @example
|
|
308
|
+
* ```typescript
|
|
309
|
+
* if (mobile.isTouchJustStarted(0)) {
|
|
310
|
+
* playSound('tap');
|
|
311
|
+
* }
|
|
312
|
+
* ```
|
|
313
|
+
*/
|
|
314
|
+
isTouchJustStarted(touchId: number): boolean;
|
|
315
|
+
/**
|
|
316
|
+
* Check if a touch just ended this frame
|
|
317
|
+
*
|
|
318
|
+
* @param touchId - Touch identifier (0-9)
|
|
319
|
+
* @returns True if touch just ended, false otherwise
|
|
320
|
+
*
|
|
321
|
+
* @example
|
|
322
|
+
* ```typescript
|
|
323
|
+
* if (mobile.isTouchJustReleased(0)) {
|
|
324
|
+
* releaseDragObject();
|
|
325
|
+
* }
|
|
326
|
+
* ```
|
|
327
|
+
*/
|
|
328
|
+
isTouchJustReleased(touchId: number): boolean;
|
|
329
|
+
/**
|
|
330
|
+
* Check if any touch just started this frame
|
|
331
|
+
*/
|
|
332
|
+
isAnyTouchJustStarted(): boolean;
|
|
333
|
+
/**
|
|
334
|
+
* Get all active touches
|
|
335
|
+
*
|
|
336
|
+
* @returns Array of all active TouchPoint objects
|
|
337
|
+
*
|
|
338
|
+
* @example
|
|
339
|
+
* ```typescript
|
|
340
|
+
* const touches = mobile.getAllTouches();
|
|
341
|
+
* touches.forEach(touch => {
|
|
342
|
+
* console.log(`Touch ${touch.id} at`, touch.position);
|
|
343
|
+
* });
|
|
344
|
+
* ```
|
|
345
|
+
*/
|
|
346
|
+
getAllTouches(): TouchPoint[];
|
|
347
|
+
/**
|
|
348
|
+
* Set mobile-specific callbacks
|
|
349
|
+
*
|
|
350
|
+
* @param callbacks - Object containing callback functions
|
|
351
|
+
*
|
|
352
|
+
* @example
|
|
353
|
+
* ```typescript
|
|
354
|
+
* mobile.setMobileCallbacks({
|
|
355
|
+
* onTouchStart: (touches, event) => {
|
|
356
|
+
* console.log(`${touches.length} touches started`);
|
|
357
|
+
* },
|
|
358
|
+
* onTouchMove: (touches, event) => {
|
|
359
|
+
* touches.forEach(t => console.log(`Touch ${t.id}:`, t.position));
|
|
360
|
+
* },
|
|
361
|
+
* onOrientationChange: (orientation) => {
|
|
362
|
+
* console.log('Orientation:', orientation);
|
|
363
|
+
* },
|
|
364
|
+
* });
|
|
365
|
+
* ```
|
|
366
|
+
*/
|
|
367
|
+
setMobileCallbacks(callbacks: MobileCallbacks): void;
|
|
368
|
+
clearMobileCallbacks(): void;
|
|
369
|
+
setCallbacks(callbacks: MobileCallbacks | unknown): void;
|
|
370
|
+
private isMobileCallbacks;
|
|
371
|
+
private handleTouchStart;
|
|
372
|
+
private handleTouchEnd;
|
|
373
|
+
private handleTouchMove;
|
|
374
|
+
private handleTouchCancel;
|
|
375
|
+
private handleOrientationChange;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* React hook for mobile inputs
|
|
379
|
+
*
|
|
380
|
+
* ⚠️ IMPORTANT: This function is NOT a proper React hook!
|
|
381
|
+
* It creates a new MobileInputs instance on every render, causing memory leaks.
|
|
382
|
+
*
|
|
383
|
+
* To use correctly in React, wrap with useMemo and useEffect:
|
|
384
|
+
*
|
|
385
|
+
* @example
|
|
386
|
+
* ```typescript
|
|
387
|
+
* import { useMemo, useEffect } from 'react';
|
|
388
|
+
*
|
|
389
|
+
* const inputs = useMemo(() => new MobileInputs(canvasRef.current, config), [config]);
|
|
390
|
+
*
|
|
391
|
+
* useEffect(() => {
|
|
392
|
+
* if (callbacks) inputs.setCallbacks(callbacks);
|
|
393
|
+
* inputs.start();
|
|
394
|
+
* return () => inputs.stop();
|
|
395
|
+
* }, [inputs, callbacks]);
|
|
396
|
+
* ```
|
|
397
|
+
*
|
|
398
|
+
* @deprecated Use the pattern above instead of this function
|
|
399
|
+
*/
|
|
400
|
+
declare function useMobileInputs(targetElement?: HTMLElement | Window, callbacks?: MobileCallbacks, config?: MobileInputsConfig): MobileInputs;
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* MobileVibration - Vibration feedback for mobile devices
|
|
404
|
+
*
|
|
405
|
+
* Provides vibration feedback using the Navigator Vibration API.
|
|
406
|
+
* Requires user interaction before first use (browser security requirement).
|
|
407
|
+
*
|
|
408
|
+
* @example
|
|
409
|
+
* ```typescript
|
|
410
|
+
* const vibration = new MobileVibration();
|
|
411
|
+
*
|
|
412
|
+
* // Simple vibration
|
|
413
|
+
* vibration.vibrate(100); // 100ms vibration
|
|
414
|
+
*
|
|
415
|
+
* // Pattern vibration
|
|
416
|
+
* vibration.vibrate([100, 50, 100]); // vibrate 100ms, pause 50ms, vibrate 100ms
|
|
417
|
+
*
|
|
418
|
+
* // Predefined patterns
|
|
419
|
+
* vibration.tap(); // Light tap feedback
|
|
420
|
+
* vibration.success(); // Success confirmation
|
|
421
|
+
* vibration.error(); // Error notification
|
|
422
|
+
* vibration.warning(); // Warning notification
|
|
423
|
+
* ```
|
|
424
|
+
*/
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Configuration options for MobileVibration
|
|
428
|
+
*/
|
|
429
|
+
interface MobileVibrationConfig {
|
|
430
|
+
/** Enable vibration (default: true) */
|
|
431
|
+
enabled?: boolean;
|
|
432
|
+
/** Enable debug logging (default: false) */
|
|
433
|
+
debug?: boolean;
|
|
434
|
+
/** Global intensity multiplier 0.0-1.0 (default: 1.0) */
|
|
435
|
+
intensity?: number;
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Predefined vibration patterns for common use cases
|
|
439
|
+
*/
|
|
440
|
+
declare const VibrationPatterns: {
|
|
441
|
+
/** Light tap - single short pulse */
|
|
442
|
+
readonly tap: 10;
|
|
443
|
+
/** Medium tap - slightly longer pulse */
|
|
444
|
+
readonly mediumTap: 25;
|
|
445
|
+
/** Heavy tap - strong pulse */
|
|
446
|
+
readonly heavyTap: 50;
|
|
447
|
+
/** Success - two quick pulses */
|
|
448
|
+
readonly success: readonly [30, 50, 30];
|
|
449
|
+
/** Error - three rapid pulses */
|
|
450
|
+
readonly error: readonly [50, 30, 50, 30, 50];
|
|
451
|
+
/** Warning - one long pulse */
|
|
452
|
+
readonly warning: readonly [100];
|
|
453
|
+
/** Selection change - very light feedback */
|
|
454
|
+
readonly selection: 5;
|
|
455
|
+
/** Impact light */
|
|
456
|
+
readonly impactLight: 15;
|
|
457
|
+
/** Impact medium */
|
|
458
|
+
readonly impactMedium: 30;
|
|
459
|
+
/** Impact heavy */
|
|
460
|
+
readonly impactHeavy: 50;
|
|
461
|
+
/** Notification - attention-grabbing pattern */
|
|
462
|
+
readonly notification: readonly [100, 100, 100, 100, 100];
|
|
463
|
+
/** SOS pattern in Morse code */
|
|
464
|
+
readonly sos: readonly [100, 30, 100, 30, 100, 30, 200, 30, 200, 30, 200, 30, 100, 30, 100, 30, 100];
|
|
465
|
+
};
|
|
466
|
+
/**
|
|
467
|
+
* MobileVibration manager - implements IMobileVibrationProcessor
|
|
468
|
+
*/
|
|
469
|
+
declare class MobileVibration implements IMobileVibrationProcessor {
|
|
470
|
+
private config;
|
|
471
|
+
private supported;
|
|
472
|
+
private userActivated;
|
|
473
|
+
constructor(config?: MobileVibrationConfig);
|
|
474
|
+
/**
|
|
475
|
+
* Check if vibration is supported on this device
|
|
476
|
+
*/
|
|
477
|
+
isSupported(): boolean;
|
|
478
|
+
/**
|
|
479
|
+
* Check if vibration is enabled
|
|
480
|
+
*/
|
|
481
|
+
isEnabled(): boolean;
|
|
482
|
+
/**
|
|
483
|
+
* Enable or disable vibration
|
|
484
|
+
*/
|
|
485
|
+
setEnabled(enabled: boolean): void;
|
|
486
|
+
/**
|
|
487
|
+
* Set global intensity multiplier (0.0 to 1.0)
|
|
488
|
+
* This scales the duration of all vibrations
|
|
489
|
+
*/
|
|
490
|
+
setIntensity(intensity: number): void;
|
|
491
|
+
/**
|
|
492
|
+
* Get current intensity setting
|
|
493
|
+
*/
|
|
494
|
+
getIntensity(): number;
|
|
495
|
+
/**
|
|
496
|
+
* Vibrate with a pattern or duration
|
|
497
|
+
*
|
|
498
|
+
* @param pattern - Duration in ms, or array of [vibrate, pause, vibrate, pause, ...]
|
|
499
|
+
* @returns true if vibration was triggered, false otherwise
|
|
500
|
+
*
|
|
501
|
+
* @example
|
|
502
|
+
* ```typescript
|
|
503
|
+
* vibration.vibrate(100); // Vibrate for 100ms
|
|
504
|
+
* vibration.vibrate([100, 50, 100]); // Vibrate, pause, vibrate
|
|
505
|
+
* ```
|
|
506
|
+
*/
|
|
507
|
+
vibrate(pattern: VibrationPattern): boolean;
|
|
508
|
+
/**
|
|
509
|
+
* Stop any ongoing vibration
|
|
510
|
+
*/
|
|
511
|
+
cancel(): void;
|
|
512
|
+
/**
|
|
513
|
+
* Check if user has activated vibration (first successful vibration)
|
|
514
|
+
* This can be useful for UI feedback
|
|
515
|
+
*/
|
|
516
|
+
hasUserActivation(): boolean;
|
|
517
|
+
/**
|
|
518
|
+
* Light tap feedback - for button presses, selections
|
|
519
|
+
*/
|
|
520
|
+
tap(): boolean;
|
|
521
|
+
/**
|
|
522
|
+
* Medium tap feedback
|
|
523
|
+
*/
|
|
524
|
+
mediumTap(): boolean;
|
|
525
|
+
/**
|
|
526
|
+
* Heavy tap feedback - for important actions
|
|
527
|
+
*/
|
|
528
|
+
heavyTap(): boolean;
|
|
529
|
+
/**
|
|
530
|
+
* Success feedback - for completed actions
|
|
531
|
+
*/
|
|
532
|
+
success(): boolean;
|
|
533
|
+
/**
|
|
534
|
+
* Error feedback - for failed actions
|
|
535
|
+
*/
|
|
536
|
+
error(): boolean;
|
|
537
|
+
/**
|
|
538
|
+
* Warning feedback - for important notices
|
|
539
|
+
*/
|
|
540
|
+
warning(): boolean;
|
|
541
|
+
/**
|
|
542
|
+
* Selection feedback - very light, for UI navigation
|
|
543
|
+
*/
|
|
544
|
+
selection(): boolean;
|
|
545
|
+
/**
|
|
546
|
+
* Light impact feedback
|
|
547
|
+
*/
|
|
548
|
+
impactLight(): boolean;
|
|
549
|
+
/**
|
|
550
|
+
* Medium impact feedback
|
|
551
|
+
*/
|
|
552
|
+
impactMedium(): boolean;
|
|
553
|
+
/**
|
|
554
|
+
* Heavy impact feedback
|
|
555
|
+
*/
|
|
556
|
+
impactHeavy(): boolean;
|
|
557
|
+
/**
|
|
558
|
+
* Notification feedback - attention-grabbing pattern
|
|
559
|
+
*/
|
|
560
|
+
notification(): boolean;
|
|
561
|
+
/**
|
|
562
|
+
* Scale a vibration pattern by intensity
|
|
563
|
+
*/
|
|
564
|
+
private scalePattern;
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Get the default MobileVibration instance (singleton)
|
|
568
|
+
*/
|
|
569
|
+
declare function getMobileVibration(): MobileVibration;
|
|
570
|
+
|
|
571
|
+
export { BaseInputs, InputEventType, MobileInputs, MobileVibration, VibrationPatterns, getMobileVibration, useMobileInputs };
|
|
572
|
+
export type { ButtonState, IInputs, InputConfig, MobileCallbacks, MobileInputsConfig, MobileVibrationConfig, MotionData, TouchPoint };
|
package/dist/touch.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var M=Object.defineProperty;var w=(l,o,e)=>o in l?M(l,o,{enumerable:!0,configurable:!0,writable:!0,value:e}):l[o]=e;var h=(l,o)=>M(l,"name",{value:o,configurable:!0});var a=(l,o,e)=>(w(l,typeof o!="symbol"?o+"":o,e),e);import{Vector2 as W}from"@utsp/types";import{InputDeviceType as U,TouchInput as B}from"@utsp/types";var E=(c=>(c.KeyDown="keydown",c.KeyUp="keyup",c.MouseDown="mousedown",c.MouseUp="mouseup",c.MouseMove="mousemove",c.MouseWheel="mousewheel",c.TouchStart="touchstart",c.TouchEnd="touchend",c.TouchMove="touchmove",c.GamepadConnected="gamepadconnected",c.GamepadDisconnected="gamepaddisconnected",c.GamepadButton="gamepadbutton",c.GamepadAxis="gamepadaxis",c))(E||{}),v=class v{constructor(o=window,e={}){a(this,"isActive",!1);a(this,"targetElement");a(this,"config");a(this,"callbacks",{});this.targetElement=o,this.config={enabled:!0,preventDefault:!1,stopPropagation:!1,debug:!1,...e}}isListening(){return this.isActive}destroy(){this.stop(),this.clearCallbacks()}setCallbacks(o){typeof o=="object"&&o!==null&&Object.assign(this.callbacks,o)}clearCallbacks(){this.callbacks={}}getTargetElement(){return this.targetElement}enable(){this.config.enabled=!0,this.isActive||this.start()}disable(){this.config.enabled=!1,this.isActive&&this.stop()}isEnabled(){return this.config.enabled??!0}emit(o,...e){this.callbacks[o]&&this.callbacks[o].forEach(t=>{try{t(...e)}catch(n){this.config.debug&&console.error(`Error in ${o} callback:`,n)}})}log(...o){this.config.debug&&console.warn("[InputSystem]",...o)}};h(v,"BaseInputs");var b=v;import{Vector2 as y}from"@utsp/types";var m=class m extends b{constructor(e=window,t={}){super(e,t);a(this,"touches",new Map);a(this,"nativeToInternal",new Map);a(this,"mobileCallbacks",{});a(this,"mobileConfig");a(this,"maxTouches",10);a(this,"lastLogTime",0);a(this,"boundHandlers");this.mobileConfig={targetElement:e,preventDefault:t.preventDefault??!0,passive:t.passive??!1,maxTouches:t.maxTouches??10,enabled:t.enabled??!0,debug:t.debug??!1,stopPropagation:t.stopPropagation??!1},this.maxTouches=this.mobileConfig.maxTouches,this.mobileConfig.preventDefault&&this.mobileConfig.passive&&(console.warn("[MobileInputs] passive=true prevents preventDefault() from working! Setting passive=false."),this.mobileConfig.passive=!1),this.boundHandlers={touchStart:this.handleTouchStart.bind(this),touchEnd:this.handleTouchEnd.bind(this),touchMove:this.handleTouchMove.bind(this),touchCancel:this.handleTouchCancel.bind(this),orientationChange:this.handleOrientationChange.bind(this)}}start(){if(this.isActive)return;let e={passive:!this.mobileConfig.preventDefault&&this.mobileConfig.passive};this.targetElement.addEventListener("touchstart",this.boundHandlers.touchStart,e),this.targetElement.addEventListener("touchend",this.boundHandlers.touchEnd,e),this.targetElement.addEventListener("touchmove",this.boundHandlers.touchMove,e),this.targetElement.addEventListener("touchcancel",this.boundHandlers.touchCancel,e),window.addEventListener("orientationchange",this.boundHandlers.orientationChange),this.isActive=!0}stop(){this.isActive&&(this.targetElement.removeEventListener("touchstart",this.boundHandlers.touchStart),this.targetElement.removeEventListener("touchend",this.boundHandlers.touchEnd),this.targetElement.removeEventListener("touchmove",this.boundHandlers.touchMove),this.targetElement.removeEventListener("touchcancel",this.boundHandlers.touchCancel),window.removeEventListener("orientationchange",this.boundHandlers.orientationChange),this.isActive=!1)}reset(){this.touches.clear(),this.nativeToInternal.clear()}resetDelta(){}poll(){for(let e of this.touches.values())e.justTouched=!1,e.justReleased=!1}isTouchActive(e){return e<0||e>=this.maxTouches?!1:this.touches.has(e)}getTouchPosition(e){if(e<0||e>=this.maxTouches)return null;let t=this.touches.get(e);return t?t.position.clone():null}getTouchStartPosition(e){if(e<0||e>=this.maxTouches)return null;let t=this.touches.get(e);return t?t.startPosition.clone():null}getTouchDelta(e){if(e<0||e>=this.maxTouches)return null;let t=this.touches.get(e);return t?t.position.subtract(t.startPosition):null}getTouchCount(){return this.touches.size}isTouchJustStarted(e){if(e<0||e>=this.maxTouches)return!1;let t=this.touches.get(e);return t?t.justTouched:!1}isTouchJustReleased(e){if(e<0||e>=this.maxTouches)return!1;let t=this.touches.get(e);return t?t.justReleased:!1}isAnyTouchJustStarted(){for(let e of this.touches.values())if(e.justTouched)return!0;return!1}getAllTouches(){return Array.from(this.touches.values())}setMobileCallbacks(e){this.mobileCallbacks={...this.mobileCallbacks,...e}}clearMobileCallbacks(){this.mobileCallbacks={}}setCallbacks(e){this.isMobileCallbacks(e)&&this.setMobileCallbacks(e)}isMobileCallbacks(e){return typeof e=="object"&&e!==null&&("onTouchStart"in e||"onTouchEnd"in e||"onTouchMove"in e||"onTouchCancel"in e||"onOrientationChange"in e)}handleTouchStart(e){try{this.mobileConfig.preventDefault&&e.preventDefault();let t=Array.from(e.changedTouches),n=[];for(let s of t){if(this.touches.size>=this.maxTouches)break;let i=-1;for(let d=0;d<this.maxTouches;d++)if(!this.touches.has(d)){i=d;break}if(i===-1)continue;let r=new y(s.clientX,s.clientY),C={id:i,nativeId:s.identifier,position:r.clone(),startPosition:r.clone(),active:!0,justTouched:!0,justReleased:!1};this.touches.set(i,C),this.nativeToInternal.set(s.identifier,i),n.push(C),console.warn(`\u{1F446} Touch START - ID: ${i}`)}this.mobileCallbacks.onTouchStart?.(n,e)}catch(t){console.error("Error in touch start handler:",t)}}handleTouchEnd(e){try{this.mobileConfig.preventDefault&&e.preventDefault();let t=Array.from(e.changedTouches),n=[];for(let s of t){let i=this.nativeToInternal.get(s.identifier);if(i!==void 0){let r=this.touches.get(i);r&&(r.justReleased=!0,r.justTouched=!1,n.push({...r}))}}for(let s of t){let i=this.nativeToInternal.get(s.identifier);i!==void 0&&(this.touches.delete(i),this.nativeToInternal.delete(s.identifier),console.warn(`\u{1F447} Touch END - ID: ${i}`))}this.mobileCallbacks.onTouchEnd?.(n,e)}catch(t){console.error("Error in touch end handler:",t)}}handleTouchMove(e){try{let t=Array.from(e.changedTouches);this.mobileConfig.debug&&(!this.lastLogTime||Date.now()-this.lastLogTime>200)&&(console.warn(`\u{1F504} TouchMove event - ${t.length} touches changed`),this.lastLogTime=Date.now());for(let n of t){let s=this.nativeToInternal.get(n.identifier);if(s!==void 0){let i=this.touches.get(s);if(i){let r=i.position.clone();i.position=new y(n.clientX,n.clientY),this.mobileConfig.debug&&(!this.lastLogTime||Date.now()-this.lastLogTime>200)&&console.warn(`\u{1F504} Updated touch ${i.id} (native ${n.identifier}) - ${r.x.toFixed(1)},${r.y.toFixed(1)} \u2192 ${n.clientX.toFixed(1)},${n.clientY.toFixed(1)}`)}}else this.mobileConfig.debug&&console.warn(`\u26A0\uFE0F Touch move for unknown native ID ${n.identifier}`)}this.mobileCallbacks.onTouchMove?.(this.getAllTouches(),e)}catch(t){console.error("Error in touch move handler:",t)}}handleTouchCancel(e){try{this.mobileConfig.preventDefault&&e.preventDefault();let t=[],n=Array.from(e.changedTouches);for(let s of n){let i=this.nativeToInternal.get(s.identifier);if(i!==void 0){let r=this.touches.get(i);r&&(r.justReleased=!0,r.justTouched=!1,t.push({...r}))}}for(let s of n){let i=this.nativeToInternal.get(s.identifier);i!==void 0&&(this.touches.delete(i),this.nativeToInternal.delete(s.identifier),this.mobileConfig.debug&&console.warn(`\u274C Touch CANCEL - ID: ${i}, nativeId: ${s.identifier}`))}this.mobileCallbacks.onTouchCancel?.(t,e)}catch(t){console.error("Error in touch cancel handler:",t)}}handleOrientationChange(e){try{let t=(window.screen.orientation&&window.screen.orientation.angle)??window.orientation??0;this.mobileCallbacks.onOrientationChange?.(t)}catch(t){console.error("Error in orientation change handler:",t)}}};h(m,"MobileInputs");var p=m;function x(l,o,e){console.warn("[MobileInputs] useMobileInputs() is deprecated and causes memory leaks. Use useMemo + useEffect instead.");let t=new p(l,e);return o&&t.setCallbacks(o),t.start(),t}h(x,"useMobileInputs");var u={tap:10,mediumTap:25,heavyTap:50,success:[30,50,30],error:[50,30,50,30,50],warning:[100],selection:5,impactLight:15,impactMedium:30,impactHeavy:50,notification:[100,100,100,100,100],sos:[100,30,100,30,100,30,200,30,200,30,200,30,100,30,100,30,100]},T=class T{constructor(o={}){a(this,"config");a(this,"supported",!1);a(this,"userActivated",!1);this.config={enabled:o.enabled??!0,debug:o.debug??!1,intensity:Math.max(0,Math.min(1,o.intensity??1))},this.supported=typeof navigator<"u"&&"vibrate"in navigator,this.config.debug&&console.log(`[MobileVibration] Vibration API supported: ${this.supported}`)}isSupported(){return this.supported}isEnabled(){return this.config.enabled&&this.supported}setEnabled(o){this.config.enabled=o,this.config.debug&&console.log(`[MobileVibration] Enabled: ${o}`)}setIntensity(o){this.config.intensity=Math.max(0,Math.min(1,o)),this.config.debug&&console.log(`[MobileVibration] Intensity set to: ${this.config.intensity}`)}getIntensity(){return this.config.intensity}vibrate(o){if(!this.isEnabled())return!1;try{let e=this.scalePattern(o),t=typeof e=="number"?e:[...e],n=navigator.vibrate(t);return this.config.debug&&console.log(`[MobileVibration] Vibrate: ${JSON.stringify(e)} -> ${n}`),n&&(this.userActivated=!0),n}catch(e){return this.config.debug&&console.error("[MobileVibration] Vibration failed:",e),!1}}cancel(){this.supported&&(navigator.vibrate(0),this.config.debug&&console.log("[MobileVibration] Vibration cancelled"))}hasUserActivation(){return this.userActivated}tap(){return this.vibrate(u.tap)}mediumTap(){return this.vibrate(u.mediumTap)}heavyTap(){return this.vibrate(u.heavyTap)}success(){return this.vibrate(u.success)}error(){return this.vibrate(u.error)}warning(){return this.vibrate(u.warning)}selection(){return this.vibrate(u.selection)}impactLight(){return this.vibrate(u.impactLight)}impactMedium(){return this.vibrate(u.impactMedium)}impactHeavy(){return this.vibrate(u.impactHeavy)}notification(){return this.vibrate(u.notification)}scalePattern(o){return this.config.intensity===1?o:typeof o=="number"?Math.round(o*this.config.intensity):o.map((e,t)=>t%2===0?Math.round(e*this.config.intensity):e)}};h(T,"MobileVibration");var f=T,g=null;function k(){return g||(g=new f),g}h(k,"getMobileVibration");export{b as BaseInputs,U as InputDeviceType,E as InputEventType,p as MobileInputs,f as MobileVibration,B as TouchInput,W as Vector2,u as VibrationPatterns,k as getMobileVibration,x as useMobileInputs};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@utsp/input",
|
|
3
|
-
"version": "0.10.0-nightly.
|
|
3
|
+
"version": "0.10.0-nightly.20251213135145.115c488",
|
|
4
4
|
"description": "Comprehensive input management system for UTSP - keyboard, mouse, gamepad, and touch support with unified routing",
|
|
5
5
|
"author": "THP Software",
|
|
6
6
|
"license": "MIT",
|
|
@@ -13,6 +13,58 @@
|
|
|
13
13
|
"types": "./dist/index.d.ts",
|
|
14
14
|
"import": "./dist/index.mjs",
|
|
15
15
|
"require": "./dist/index.cjs"
|
|
16
|
+
},
|
|
17
|
+
"./core": {
|
|
18
|
+
"types": "./dist/core.d.ts",
|
|
19
|
+
"import": "./dist/core.mjs",
|
|
20
|
+
"require": "./dist/core.cjs"
|
|
21
|
+
},
|
|
22
|
+
"./keyboard": {
|
|
23
|
+
"types": "./dist/keyboard.d.ts",
|
|
24
|
+
"import": "./dist/keyboard.mjs",
|
|
25
|
+
"require": "./dist/keyboard.cjs"
|
|
26
|
+
},
|
|
27
|
+
"./mouse": {
|
|
28
|
+
"types": "./dist/mouse.d.ts",
|
|
29
|
+
"import": "./dist/mouse.mjs",
|
|
30
|
+
"require": "./dist/mouse.cjs"
|
|
31
|
+
},
|
|
32
|
+
"./touch": {
|
|
33
|
+
"types": "./dist/touch.d.ts",
|
|
34
|
+
"import": "./dist/touch.mjs",
|
|
35
|
+
"require": "./dist/touch.cjs"
|
|
36
|
+
},
|
|
37
|
+
"./gamepad": {
|
|
38
|
+
"types": "./dist/gamepad.d.ts",
|
|
39
|
+
"import": "./dist/gamepad.mjs",
|
|
40
|
+
"require": "./dist/gamepad.cjs"
|
|
41
|
+
},
|
|
42
|
+
"./desktop": {
|
|
43
|
+
"types": "./dist/desktop.d.ts",
|
|
44
|
+
"import": "./dist/desktop.mjs",
|
|
45
|
+
"require": "./dist/desktop.cjs"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"typesVersions": {
|
|
49
|
+
"*": {
|
|
50
|
+
"core": [
|
|
51
|
+
"./dist/core.d.ts"
|
|
52
|
+
],
|
|
53
|
+
"keyboard": [
|
|
54
|
+
"./dist/keyboard.d.ts"
|
|
55
|
+
],
|
|
56
|
+
"mouse": [
|
|
57
|
+
"./dist/mouse.d.ts"
|
|
58
|
+
],
|
|
59
|
+
"touch": [
|
|
60
|
+
"./dist/touch.d.ts"
|
|
61
|
+
],
|
|
62
|
+
"gamepad": [
|
|
63
|
+
"./dist/gamepad.d.ts"
|
|
64
|
+
],
|
|
65
|
+
"desktop": [
|
|
66
|
+
"./dist/desktop.d.ts"
|
|
67
|
+
]
|
|
16
68
|
}
|
|
17
69
|
},
|
|
18
70
|
"keywords": [
|
|
@@ -52,7 +104,7 @@
|
|
|
52
104
|
"access": "public"
|
|
53
105
|
},
|
|
54
106
|
"dependencies": {
|
|
55
|
-
"@utsp/types": "0.10.0-nightly.
|
|
107
|
+
"@utsp/types": "0.10.0-nightly.20251213135145.115c488"
|
|
56
108
|
},
|
|
57
109
|
"devDependencies": {
|
|
58
110
|
"typescript": "^5.6.3"
|