@kelnishi/satmouse-client 0.10.9 → 0.12.3
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/{chunk-RNM322RZ.js → chunk-RE4PNORY.js} +18 -11
- package/dist/chunk-RE4PNORY.js.map +1 -0
- package/dist/{chunk-JTG5GEIB.cjs → chunk-Y75556IA.cjs} +18 -11
- package/dist/chunk-Y75556IA.cjs.map +1 -0
- package/dist/{connection-DQxI5qib.d.cts → connection-iUlge6Er.d.cts} +9 -1
- package/dist/{connection-DQxI5qib.d.ts → connection-iUlge6Er.d.ts} +9 -1
- package/dist/core/index.d.cts +2 -2
- package/dist/core/index.d.ts +2 -2
- package/dist/elements/index.cjs +138 -14
- package/dist/elements/index.cjs.map +1 -1
- package/dist/elements/index.d.cts +2 -1
- package/dist/elements/index.d.ts +2 -1
- package/dist/elements/index.js +136 -12
- package/dist/elements/index.js.map +1 -1
- package/dist/react/index.cjs +59 -15
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.js +59 -15
- package/dist/react/index.js.map +1 -1
- package/dist/utils/index.cjs +52 -15
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.d.cts +35 -11
- package/dist/utils/index.d.ts +35 -11
- package/dist/utils/index.js +46 -9
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-JTG5GEIB.cjs.map +0 -1
- package/dist/chunk-RNM322RZ.js.map +0 -1
package/dist/utils/index.cjs
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkI5MEZZOT_cjs = require('../chunk-I5MEZZOT.cjs');
|
|
4
|
-
var
|
|
4
|
+
var chunkY75556IA_cjs = require('../chunk-Y75556IA.cjs');
|
|
5
5
|
|
|
6
6
|
// src/utils/config.ts
|
|
7
7
|
var DEFAULT_CONFIG = {
|
|
8
|
-
routes:
|
|
9
|
-
|
|
8
|
+
routes: chunkY75556IA_cjs.DEFAULT_ROUTES,
|
|
9
|
+
buttonRoutes: [],
|
|
10
|
+
translateScale: 1e-3,
|
|
11
|
+
rotateScale: 1e-3,
|
|
12
|
+
wScale: 1e-3,
|
|
10
13
|
deadZone: 0,
|
|
11
14
|
dominant: false,
|
|
12
15
|
lockPosition: false,
|
|
@@ -40,6 +43,7 @@ function mergeConfig(base, partial) {
|
|
|
40
43
|
...base,
|
|
41
44
|
...partial,
|
|
42
45
|
routes: partial.routes ?? [...base.routes],
|
|
46
|
+
buttonRoutes: partial.buttonRoutes ?? [...base.buttonRoutes],
|
|
43
47
|
devices: { ...base.devices }
|
|
44
48
|
};
|
|
45
49
|
if (partial.devices) {
|
|
@@ -65,7 +69,10 @@ function resolveDeviceConfig(config, deviceId) {
|
|
|
65
69
|
return {
|
|
66
70
|
...config,
|
|
67
71
|
routes: deviceOverride.routes ?? config.routes,
|
|
68
|
-
|
|
72
|
+
buttonRoutes: deviceOverride.buttonRoutes ?? config.buttonRoutes,
|
|
73
|
+
translateScale: deviceOverride.translateScale ?? config.translateScale,
|
|
74
|
+
rotateScale: deviceOverride.rotateScale ?? config.rotateScale,
|
|
75
|
+
wScale: deviceOverride.wScale ?? config.wScale,
|
|
69
76
|
deadZone: deviceOverride.deadZone ?? config.deadZone,
|
|
70
77
|
dominant: deviceOverride.dominant ?? config.dominant
|
|
71
78
|
};
|
|
@@ -169,7 +176,10 @@ var InputManager = class extends chunkI5MEZZOT_cjs.TypedEmitter {
|
|
|
169
176
|
const resolved = resolveDeviceConfig(this._config, deviceId);
|
|
170
177
|
return {
|
|
171
178
|
routes: resolved.routes,
|
|
172
|
-
|
|
179
|
+
buttonRoutes: resolved.buttonRoutes,
|
|
180
|
+
translateScale: resolved.translateScale,
|
|
181
|
+
rotateScale: resolved.rotateScale,
|
|
182
|
+
wScale: resolved.wScale,
|
|
173
183
|
deadZone: resolved.deadZone,
|
|
174
184
|
dominant: resolved.dominant
|
|
175
185
|
};
|
|
@@ -217,11 +227,15 @@ var InputManager = class extends chunkI5MEZZOT_cjs.TypedEmitter {
|
|
|
217
227
|
tz: processed.translation.z,
|
|
218
228
|
rx: processed.rotation.x,
|
|
219
229
|
ry: processed.rotation.y,
|
|
220
|
-
rz: processed.rotation.z
|
|
230
|
+
rz: processed.rotation.z,
|
|
231
|
+
w: processed.w ?? 0
|
|
221
232
|
});
|
|
222
233
|
this.accDirty = true;
|
|
223
234
|
});
|
|
224
|
-
connection.on("buttonEvent", (event) =>
|
|
235
|
+
connection.on("buttonEvent", (event) => {
|
|
236
|
+
this.dispatchButtonKeys(event);
|
|
237
|
+
this.emit("buttonEvent", event);
|
|
238
|
+
});
|
|
225
239
|
connection.on("stateChange", (state, proto) => {
|
|
226
240
|
this._state = state;
|
|
227
241
|
this._protocol = proto;
|
|
@@ -235,7 +249,7 @@ var InputManager = class extends chunkI5MEZZOT_cjs.TypedEmitter {
|
|
|
235
249
|
}
|
|
236
250
|
flushAccumulator() {
|
|
237
251
|
if (!this.accDirty) return;
|
|
238
|
-
const merged = { tx: 0, ty: 0, tz: 0, rx: 0, ry: 0, rz: 0 };
|
|
252
|
+
const merged = { tx: 0, ty: 0, tz: 0, rx: 0, ry: 0, rz: 0, w: 0 };
|
|
239
253
|
for (const acc of this.deviceAccumulators.values()) {
|
|
240
254
|
merged.tx += acc.tx;
|
|
241
255
|
merged.ty += acc.ty;
|
|
@@ -243,12 +257,14 @@ var InputManager = class extends chunkI5MEZZOT_cjs.TypedEmitter {
|
|
|
243
257
|
merged.rx += acc.rx;
|
|
244
258
|
merged.ry += acc.ry;
|
|
245
259
|
merged.rz += acc.rz;
|
|
260
|
+
merged.w += acc.w;
|
|
246
261
|
}
|
|
247
262
|
this.deviceAccumulators.clear();
|
|
248
263
|
this.accDirty = false;
|
|
249
264
|
let data = {
|
|
250
265
|
translation: { x: merged.tx, y: merged.ty, z: merged.tz },
|
|
251
266
|
rotation: { x: merged.rx, y: merged.ry, z: merged.rz },
|
|
267
|
+
w: merged.w || void 0,
|
|
252
268
|
timestamp: performance.now() * 1e3
|
|
253
269
|
};
|
|
254
270
|
if (this._config.lockPosition) {
|
|
@@ -289,7 +305,7 @@ var InputManager = class extends chunkI5MEZZOT_cjs.TypedEmitter {
|
|
|
289
305
|
}
|
|
290
306
|
const device = this.knownDevices.get(deviceId);
|
|
291
307
|
const deviceRoutes = this.resolveRoutes(deviceId, device);
|
|
292
|
-
data =
|
|
308
|
+
data = chunkY75556IA_cjs.applyRoutes(data, deviceRoutes, cfg.translateScale, cfg.rotateScale, cfg.wScale);
|
|
293
309
|
return data;
|
|
294
310
|
}
|
|
295
311
|
/** Get the effective routes for a device: device config override > device axes metadata > global default */
|
|
@@ -301,26 +317,47 @@ var InputManager = class extends chunkI5MEZZOT_cjs.TypedEmitter {
|
|
|
301
317
|
if (cfg.routes && Array.isArray(cfg.routes)) return cfg.routes;
|
|
302
318
|
}
|
|
303
319
|
}
|
|
304
|
-
if (device?.axes) return
|
|
305
|
-
return
|
|
320
|
+
if (device?.axes) return chunkY75556IA_cjs.buildRoutes(device.axes);
|
|
321
|
+
return chunkY75556IA_cjs.DEFAULT_ROUTES;
|
|
322
|
+
}
|
|
323
|
+
/** Dispatch KeyboardEvents for button routes matching this button event */
|
|
324
|
+
dispatchButtonKeys(event) {
|
|
325
|
+
if (typeof document === "undefined") return;
|
|
326
|
+
const allRoutes = this.collectButtonRoutes();
|
|
327
|
+
for (const route of allRoutes) {
|
|
328
|
+
if (route.button === event.button) {
|
|
329
|
+
document.dispatchEvent(new KeyboardEvent(
|
|
330
|
+
event.pressed ? "keydown" : "keyup",
|
|
331
|
+
{ key: route.key, code: route.code ?? "", bubbles: true }
|
|
332
|
+
));
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
/** Gather all button routes from global config + all device configs */
|
|
337
|
+
collectButtonRoutes() {
|
|
338
|
+
const routes = [...this._config.buttonRoutes];
|
|
339
|
+
for (const devCfg of Object.values(this._config.devices)) {
|
|
340
|
+
if (devCfg.buttonRoutes) routes.push(...devCfg.buttonRoutes);
|
|
341
|
+
}
|
|
342
|
+
return routes;
|
|
306
343
|
}
|
|
307
344
|
};
|
|
308
345
|
|
|
309
346
|
Object.defineProperty(exports, "DEFAULT_ROUTES", {
|
|
310
347
|
enumerable: true,
|
|
311
|
-
get: function () { return
|
|
348
|
+
get: function () { return chunkY75556IA_cjs.DEFAULT_ROUTES; }
|
|
312
349
|
});
|
|
313
350
|
Object.defineProperty(exports, "FULL_AXES", {
|
|
314
351
|
enumerable: true,
|
|
315
|
-
get: function () { return
|
|
352
|
+
get: function () { return chunkY75556IA_cjs.FULL_AXES; }
|
|
316
353
|
});
|
|
317
354
|
Object.defineProperty(exports, "applyRoutes", {
|
|
318
355
|
enumerable: true,
|
|
319
|
-
get: function () { return
|
|
356
|
+
get: function () { return chunkY75556IA_cjs.applyRoutes; }
|
|
320
357
|
});
|
|
321
358
|
Object.defineProperty(exports, "buildRoutes", {
|
|
322
359
|
enumerable: true,
|
|
323
|
-
get: function () { return
|
|
360
|
+
get: function () { return chunkY75556IA_cjs.buildRoutes; }
|
|
324
361
|
});
|
|
325
362
|
exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
|
|
326
363
|
exports.InputManager = InputManager;
|
package/dist/utils/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/config.ts","../../src/utils/persistence.ts","../../src/utils/input-manager.ts"],"names":["DEFAULT_ROUTES","TypedEmitter","applyRoutes","buildRoutes"],"mappings":"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","file":"index.cjs","sourcesContent":["import { DEFAULT_ROUTES, type AxisRoute } from \"./action-map.js\";\n\n/** Per-device configuration */\nexport interface DeviceConfig {\n /** Axis routing — each entry maps a device input to an output with optional flip */\n routes?: AxisRoute[];\n /** Scale multiplier applied to all axes (default: 1) */\n scale?: number;\n /** Dead zone threshold (0-1). Values below this are zeroed. */\n deadZone?: number;\n /** Only pass the strongest axis, zero all others */\n dominant?: boolean;\n}\n\n/** Global configuration */\nexport interface InputConfig {\n /** Default axis routes (used when device has no override) */\n routes: AxisRoute[];\n /** Default scale */\n scale: number;\n /** Dead zone threshold */\n deadZone: number;\n /** Dominant axis mode */\n dominant: boolean;\n /** Lock translation to zero */\n lockPosition: boolean;\n /** Lock rotation to zero */\n lockRotation: boolean;\n /** Per-device overrides keyed by device ID or pattern (e.g., \"cnx-*\") */\n devices: Record<string, DeviceConfig>;\n}\n\nexport const DEFAULT_CONFIG: InputConfig = {\n routes: DEFAULT_ROUTES,\n scale: 0.001,\n deadZone: 0,\n dominant: false,\n lockPosition: false,\n lockRotation: false,\n devices: {\n \"cnx-*\": {\n routes: [\n { source: \"tx\", target: \"tx\" },\n { source: \"ty\", target: \"ty\", flip: true },\n { source: \"tz\", target: \"tz\", flip: true },\n { source: \"rx\", target: \"rx\" },\n { source: \"ry\", target: \"ry\", flip: true },\n { source: \"rz\", target: \"rz\", flip: true },\n ],\n },\n // PlayStation: L2 (ty) → TY, R2 (ry) → TY flipped (push-pull)\n \"hid-54c-*\": {\n routes: [\n { source: \"tx\", target: \"tx\" },\n { source: \"tz\", target: \"tz\" },\n { source: \"rz\", target: \"rz\" },\n { source: \"rx\", target: \"rx\" },\n { source: \"ty\", target: \"ty\" },\n { source: \"ry\", target: \"ty\", flip: true },\n ],\n },\n },\n};\n\nexport function mergeConfig(base: InputConfig, partial: Partial<InputConfig>): InputConfig {\n const merged = {\n ...base,\n ...partial,\n routes: partial.routes ?? [...base.routes],\n devices: { ...base.devices },\n };\n\n if (partial.devices) {\n for (const [key, devCfg] of Object.entries(partial.devices)) {\n merged.devices[key] = { ...merged.devices[key], ...devCfg };\n }\n }\n\n return merged;\n}\n\n/** Resolve the effective config for a specific device */\nexport function resolveDeviceConfig(config: InputConfig, deviceId: string): InputConfig {\n let deviceOverride: DeviceConfig | undefined;\n\n if (config.devices[deviceId]) {\n deviceOverride = config.devices[deviceId];\n } else {\n for (const [pattern, cfg] of Object.entries(config.devices)) {\n if (pattern.endsWith(\"*\") && deviceId.startsWith(pattern.slice(0, -1))) {\n deviceOverride = cfg;\n break;\n }\n }\n }\n\n if (!deviceOverride) return config;\n\n return {\n ...config,\n routes: deviceOverride.routes ?? config.routes,\n scale: deviceOverride.scale ?? config.scale,\n deadZone: deviceOverride.deadZone ?? config.deadZone,\n dominant: deviceOverride.dominant ?? config.dominant,\n };\n}\n","import type { InputConfig } from \"./config.js\";\n\nexport interface StorageAdapter {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n}\n\nconst STORAGE_KEY = \"satmouse:settings\";\n\nfunction getStorage(storage?: StorageAdapter): StorageAdapter | null {\n if (storage) return storage;\n try {\n return globalThis.localStorage ?? null;\n } catch {\n return null;\n }\n}\n\nexport function saveSettings(config: InputConfig, storage?: StorageAdapter): void {\n const s = getStorage(storage);\n if (!s) return;\n s.setItem(STORAGE_KEY, JSON.stringify(config));\n}\n\nexport function clearSettings(storage?: StorageAdapter): void {\n const s = getStorage(storage);\n if (!s) return;\n s.setItem(STORAGE_KEY, \"{}\");\n}\n\nexport function loadSettings(storage?: StorageAdapter): Partial<InputConfig> | null {\n const s = getStorage(storage);\n if (!s) return null;\n const raw = s.getItem(STORAGE_KEY);\n if (!raw) return null;\n try {\n return JSON.parse(raw) as Partial<InputConfig>;\n } catch {\n return null;\n }\n}\n","import { TypedEmitter } from \"../core/emitter.js\";\nimport type { SatMouseConnection } from \"../core/connection.js\";\nimport type { SpatialData, ButtonEvent, DeviceInfo, ConnectionState, TransportProtocol } from \"../core/types.js\";\nimport type { InputConfig, DeviceConfig } from \"./config.js\";\nimport { DEFAULT_CONFIG, mergeConfig, resolveDeviceConfig } from \"./config.js\";\nimport { loadSettings, saveSettings, clearSettings, type StorageAdapter } from \"./persistence.js\";\nimport { applyRoutes, buildRoutes, DEFAULT_ROUTES, type AxisRoute } from \"./action-map.js\";\n\nexport interface InputManagerEvents {\n spatialData: (data: SpatialData) => void;\n rawSpatialData: (data: SpatialData) => void;\n buttonEvent: (data: ButtonEvent) => void;\n stateChange: (state: ConnectionState, protocol: TransportProtocol) => void;\n deviceStatus: (event: \"connected\" | \"disconnected\", device: DeviceInfo) => void;\n configChange: (config: InputConfig) => void;\n}\n\nexport interface DeviceWithConfig {\n device: DeviceInfo;\n config: DeviceConfig;\n}\n\nexport class InputManager extends TypedEmitter<InputManagerEvents> {\n private connections: SatMouseConnection[] = [];\n private storage?: StorageAdapter;\n private knownDevices = new Map<string, DeviceInfo>();\n\n private deviceAccumulators = new Map<string, { tx: number; ty: number; tz: number; rx: number; ry: number; rz: number }>();\n private accDirty = false;\n private flushTimer: ReturnType<typeof setInterval> | null = null;\n\n private _config: InputConfig;\n private _state: ConnectionState = \"disconnected\";\n private _protocol: TransportProtocol = \"none\";\n\n get config(): InputConfig {\n return this._config;\n }\n\n get state(): ConnectionState {\n return this._state;\n }\n\n get protocol(): TransportProtocol {\n return this._protocol;\n }\n\n constructor(config?: Partial<InputConfig>, storage?: StorageAdapter) {\n super();\n this.storage = storage;\n const persisted = loadSettings(storage);\n this._config = mergeConfig(DEFAULT_CONFIG, { ...config, ...persisted });\n this.flushTimer = setInterval(() => this.flushAccumulator(), 16);\n }\n\n addConnection(connection: SatMouseConnection): void {\n this.connections.push(connection);\n this.wireConnection(connection);\n }\n\n /** Reset retry count and reconnect all failed connections. */\n retry(): void {\n for (const c of this.connections) c.retry();\n }\n\n removeConnection(connection: SatMouseConnection): void {\n const idx = this.connections.indexOf(connection);\n if (idx !== -1) this.connections.splice(idx, 1);\n connection.removeAllListeners();\n }\n\n async connect(): Promise<void> {\n await Promise.all(this.connections.map((c) => c.connect()));\n }\n\n disconnect(): void {\n for (const c of this.connections) c.disconnect();\n if (this.flushTimer) { clearInterval(this.flushTimer); this.flushTimer = null; }\n }\n\n async fetchDeviceInfo(): Promise<DeviceInfo[]> {\n const results = await Promise.all(this.connections.map((c) => c.fetchDeviceInfo()));\n const devices = results.flat();\n for (const d of devices) this.knownDevices.set(d.id, d);\n return devices;\n }\n\n getDevicesWithConfig(): DeviceWithConfig[] {\n return Array.from(this.knownDevices.values()).map((device) => ({\n device,\n config: this.getDeviceConfig(device.id),\n }));\n }\n\n getDeviceConfig(deviceId: string): DeviceConfig {\n const resolved = resolveDeviceConfig(this._config, deviceId);\n return {\n routes: resolved.routes,\n scale: resolved.scale,\n deadZone: resolved.deadZone,\n dominant: resolved.dominant,\n };\n }\n\n updateConfig(partial: Partial<InputConfig>, persist = true): void {\n this._config = mergeConfig(this._config, partial);\n if (persist) saveSettings(this._config, this.storage);\n this.emit(\"configChange\", this._config);\n }\n\n updateDeviceConfig(deviceId: string, partial: DeviceConfig, persist = true): void {\n const existing = this._config.devices[deviceId] ?? {};\n this._config = mergeConfig(this._config, {\n devices: { [deviceId]: { ...existing, ...partial } },\n });\n if (persist) saveSettings(this._config, this.storage);\n this.emit(\"configChange\", this._config);\n }\n\n resetDeviceConfig(deviceId: string, persist = true): void {\n const { [deviceId]: _, ...rest } = this._config.devices;\n this._config = { ...this._config, devices: rest };\n if (persist) saveSettings(this._config, this.storage);\n this.emit(\"configChange\", this._config);\n }\n\n resetAllConfig(): void {\n clearSettings(this.storage);\n this._config = { ...DEFAULT_CONFIG };\n this.emit(\"configChange\", this._config);\n }\n\n onSpatialData(callback: (data: SpatialData) => void): () => void {\n this.on(\"spatialData\", callback);\n return () => this.off(\"spatialData\", callback);\n }\n\n onButtonEvent(callback: (data: ButtonEvent) => void): () => void {\n this.on(\"buttonEvent\", callback);\n return () => this.off(\"buttonEvent\", callback);\n }\n\n private wireConnection(connection: SatMouseConnection): void {\n connection.on(\"spatialData\", (raw) => {\n this.emit(\"rawSpatialData\", raw);\n\n const id = raw.deviceId ?? \"_default\";\n const processed = this.processPerDevice(raw, id);\n\n this.deviceAccumulators.set(id, {\n tx: processed.translation.x,\n ty: processed.translation.y,\n tz: processed.translation.z,\n rx: processed.rotation.x,\n ry: processed.rotation.y,\n rz: processed.rotation.z,\n });\n this.accDirty = true;\n });\n\n connection.on(\"buttonEvent\", (event) => this.emit(\"buttonEvent\", event));\n connection.on(\"stateChange\", (state, proto) => {\n this._state = state;\n this._protocol = proto;\n this.emit(\"stateChange\", state, proto);\n });\n connection.on(\"deviceStatus\", (event, device) => {\n if (event === \"connected\") this.knownDevices.set(device.id, device);\n else this.knownDevices.delete(device.id);\n this.emit(\"deviceStatus\", event, device);\n });\n }\n\n private flushAccumulator(): void {\n if (!this.accDirty) return;\n\n const merged = { tx: 0, ty: 0, tz: 0, rx: 0, ry: 0, rz: 0 };\n for (const acc of this.deviceAccumulators.values()) {\n merged.tx += acc.tx;\n merged.ty += acc.ty;\n merged.tz += acc.tz;\n merged.rx += acc.rx;\n merged.ry += acc.ry;\n merged.rz += acc.rz;\n }\n\n this.deviceAccumulators.clear();\n this.accDirty = false;\n\n let data: SpatialData = {\n translation: { x: merged.tx, y: merged.ty, z: merged.tz },\n rotation: { x: merged.rx, y: merged.ry, z: merged.rz },\n timestamp: performance.now() * 1000,\n };\n\n if (this._config.lockPosition) {\n data = { ...data, translation: { x: 0, y: 0, z: 0 } };\n }\n if (this._config.lockRotation) {\n data = { ...data, rotation: { x: 0, y: 0, z: 0 } };\n }\n\n this.emit(\"spatialData\", data);\n }\n\n /** Per-device: deadZone → dominant → routes (flip + scale + remap in one pass) */\n private processPerDevice(raw: SpatialData, deviceId: string): SpatialData {\n const cfg = resolveDeviceConfig(this._config, deviceId);\n let data = raw;\n\n // Dead zone\n if (cfg.deadZone > 0) {\n const dz = (v: number) => (Math.abs(v) < cfg.deadZone ? 0 : v);\n data = {\n ...data,\n translation: { x: dz(data.translation.x), y: dz(data.translation.y), z: dz(data.translation.z) },\n rotation: { x: dz(data.rotation.x), y: dz(data.rotation.y), z: dz(data.rotation.z) },\n };\n }\n\n // Dominant axis\n if (cfg.dominant) {\n const axes = [\n { g: \"t\" as const, k: \"x\" as const, v: Math.abs(data.translation.x) },\n { g: \"t\" as const, k: \"y\" as const, v: Math.abs(data.translation.y) },\n { g: \"t\" as const, k: \"z\" as const, v: Math.abs(data.translation.z) },\n { g: \"r\" as const, k: \"x\" as const, v: Math.abs(data.rotation.x) },\n { g: \"r\" as const, k: \"y\" as const, v: Math.abs(data.rotation.y) },\n { g: \"r\" as const, k: \"z\" as const, v: Math.abs(data.rotation.z) },\n ];\n const max = axes.reduce((a, b) => (b.v > a.v ? b : a));\n const t = { x: 0, y: 0, z: 0 };\n const r = { x: 0, y: 0, z: 0 };\n if (max.g === \"t\") t[max.k] = data.translation[max.k];\n else r[max.k] = data.rotation[max.k];\n data = { ...data, translation: t, rotation: r };\n }\n\n // Routes: flip + scale + remap in one pass\n // Use device-specific routes if configured, otherwise build from device axes metadata\n const device = this.knownDevices.get(deviceId);\n const deviceRoutes = this.resolveRoutes(deviceId, device);\n data = applyRoutes(data, deviceRoutes, cfg.scale);\n\n return data;\n }\n\n /** Get the effective routes for a device: device config override > device axes metadata > global default */\n private resolveRoutes(deviceId: string, device?: DeviceInfo): AxisRoute[] {\n // Check for explicit device config (exact match or pattern)\n const devCfg = this._config.devices[deviceId];\n if (devCfg?.routes && Array.isArray(devCfg.routes)) return devCfg.routes;\n\n // Check pattern matches\n for (const [pattern, cfg] of Object.entries(this._config.devices)) {\n if (pattern.endsWith(\"*\") && deviceId.startsWith(pattern.slice(0, -1))) {\n if (cfg.routes && Array.isArray(cfg.routes)) return cfg.routes;\n }\n }\n\n // Build from device axes metadata\n if (device?.axes) return buildRoutes(device.axes);\n\n // Global fallback\n return DEFAULT_ROUTES;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/config.ts","../../src/utils/persistence.ts","../../src/utils/input-manager.ts"],"names":["DEFAULT_ROUTES","TypedEmitter","applyRoutes","buildRoutes"],"mappings":"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","file":"index.cjs","sourcesContent":["import { DEFAULT_ROUTES, type AxisRoute } from \"./action-map.js\";\n\n/** Maps a device button to a keyboard key */\nexport interface ButtonRoute {\n /** Device button index */\n button: number;\n /** Keyboard key value (KeyboardEvent.key, e.g., \"a\", \"Shift\", \"ArrowUp\") */\n key: string;\n /** Keyboard code (KeyboardEvent.code, e.g., \"KeyA\", \"ShiftLeft\"). Optional. */\n code?: string;\n}\n\n/** Per-device configuration */\nexport interface DeviceConfig {\n /** Axis routing — each entry maps a device input to an output with optional flip */\n routes?: AxisRoute[];\n /** Button-to-key mappings */\n buttonRoutes?: ButtonRoute[];\n /** Scale multiplier for translation axes (tx, ty, tz) */\n translateScale?: number;\n /** Scale multiplier for rotation axes (rx, ry, rz) */\n rotateScale?: number;\n /** Scale multiplier for W axis */\n wScale?: number;\n /** Dead zone threshold (0-1). Values below this are zeroed. */\n deadZone?: number;\n /** Only pass the strongest axis, zero all others */\n dominant?: boolean;\n}\n\n/** Global configuration */\nexport interface InputConfig {\n /** Default axis routes (used when device has no override) */\n routes: AxisRoute[];\n /** Default button-to-key mappings */\n buttonRoutes: ButtonRoute[];\n /** Scale multiplier for translation axes */\n translateScale: number;\n /** Scale multiplier for rotation axes */\n rotateScale: number;\n /** Scale multiplier for W axis */\n wScale: number;\n /** Dead zone threshold */\n deadZone: number;\n /** Dominant axis mode */\n dominant: boolean;\n /** Lock translation to zero */\n lockPosition: boolean;\n /** Lock rotation to zero */\n lockRotation: boolean;\n /** Per-device overrides keyed by device ID or pattern (e.g., \"cnx-*\") */\n devices: Record<string, DeviceConfig>;\n}\n\nexport const DEFAULT_CONFIG: InputConfig = {\n routes: DEFAULT_ROUTES,\n buttonRoutes: [],\n translateScale: 0.001,\n rotateScale: 0.001,\n wScale: 0.001,\n deadZone: 0,\n dominant: false,\n lockPosition: false,\n lockRotation: false,\n devices: {\n \"cnx-*\": {\n routes: [\n { source: \"tx\", target: \"tx\" },\n { source: \"ty\", target: \"ty\", flip: true },\n { source: \"tz\", target: \"tz\", flip: true },\n { source: \"rx\", target: \"rx\" },\n { source: \"ry\", target: \"ry\", flip: true },\n { source: \"rz\", target: \"rz\", flip: true },\n ],\n },\n // PlayStation: L2 (ty) → TY, R2 (ry) → TY flipped (push-pull)\n \"hid-54c-*\": {\n routes: [\n { source: \"tx\", target: \"tx\" },\n { source: \"tz\", target: \"tz\" },\n { source: \"rz\", target: \"rz\" },\n { source: \"rx\", target: \"rx\" },\n { source: \"ty\", target: \"ty\" },\n { source: \"ry\", target: \"ty\", flip: true },\n ],\n },\n },\n};\n\nexport function mergeConfig(base: InputConfig, partial: Partial<InputConfig>): InputConfig {\n const merged = {\n ...base,\n ...partial,\n routes: partial.routes ?? [...base.routes],\n buttonRoutes: partial.buttonRoutes ?? [...base.buttonRoutes],\n devices: { ...base.devices },\n };\n\n if (partial.devices) {\n for (const [key, devCfg] of Object.entries(partial.devices)) {\n merged.devices[key] = { ...merged.devices[key], ...devCfg };\n }\n }\n\n return merged;\n}\n\n/** Resolve the effective config for a specific device */\nexport function resolveDeviceConfig(config: InputConfig, deviceId: string): InputConfig {\n let deviceOverride: DeviceConfig | undefined;\n\n if (config.devices[deviceId]) {\n deviceOverride = config.devices[deviceId];\n } else {\n for (const [pattern, cfg] of Object.entries(config.devices)) {\n if (pattern.endsWith(\"*\") && deviceId.startsWith(pattern.slice(0, -1))) {\n deviceOverride = cfg;\n break;\n }\n }\n }\n\n if (!deviceOverride) return config;\n\n return {\n ...config,\n routes: deviceOverride.routes ?? config.routes,\n buttonRoutes: deviceOverride.buttonRoutes ?? config.buttonRoutes,\n translateScale: deviceOverride.translateScale ?? config.translateScale,\n rotateScale: deviceOverride.rotateScale ?? config.rotateScale,\n wScale: deviceOverride.wScale ?? config.wScale,\n deadZone: deviceOverride.deadZone ?? config.deadZone,\n dominant: deviceOverride.dominant ?? config.dominant,\n };\n}\n","import type { InputConfig } from \"./config.js\";\n\nexport interface StorageAdapter {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n}\n\nconst STORAGE_KEY = \"satmouse:settings\";\n\nfunction getStorage(storage?: StorageAdapter): StorageAdapter | null {\n if (storage) return storage;\n try {\n return globalThis.localStorage ?? null;\n } catch {\n return null;\n }\n}\n\nexport function saveSettings(config: InputConfig, storage?: StorageAdapter): void {\n const s = getStorage(storage);\n if (!s) return;\n s.setItem(STORAGE_KEY, JSON.stringify(config));\n}\n\nexport function clearSettings(storage?: StorageAdapter): void {\n const s = getStorage(storage);\n if (!s) return;\n s.setItem(STORAGE_KEY, \"{}\");\n}\n\nexport function loadSettings(storage?: StorageAdapter): Partial<InputConfig> | null {\n const s = getStorage(storage);\n if (!s) return null;\n const raw = s.getItem(STORAGE_KEY);\n if (!raw) return null;\n try {\n return JSON.parse(raw) as Partial<InputConfig>;\n } catch {\n return null;\n }\n}\n","import { TypedEmitter } from \"../core/emitter.js\";\nimport type { SatMouseConnection } from \"../core/connection.js\";\nimport type { SpatialData, ButtonEvent, DeviceInfo, ConnectionState, TransportProtocol } from \"../core/types.js\";\nimport type { InputConfig, DeviceConfig } from \"./config.js\";\nimport { DEFAULT_CONFIG, mergeConfig, resolveDeviceConfig } from \"./config.js\";\nimport { loadSettings, saveSettings, clearSettings, type StorageAdapter } from \"./persistence.js\";\nimport { applyRoutes, buildRoutes, DEFAULT_ROUTES, type AxisRoute } from \"./action-map.js\";\n\nexport interface InputManagerEvents {\n spatialData: (data: SpatialData) => void;\n rawSpatialData: (data: SpatialData) => void;\n buttonEvent: (data: ButtonEvent) => void;\n stateChange: (state: ConnectionState, protocol: TransportProtocol) => void;\n deviceStatus: (event: \"connected\" | \"disconnected\", device: DeviceInfo) => void;\n configChange: (config: InputConfig) => void;\n}\n\nexport interface DeviceWithConfig {\n device: DeviceInfo;\n config: DeviceConfig;\n}\n\nexport class InputManager extends TypedEmitter<InputManagerEvents> {\n private connections: SatMouseConnection[] = [];\n private storage?: StorageAdapter;\n private knownDevices = new Map<string, DeviceInfo>();\n\n private deviceAccumulators = new Map<string, { tx: number; ty: number; tz: number; rx: number; ry: number; rz: number; w: number }>();\n private accDirty = false;\n private flushTimer: ReturnType<typeof setInterval> | null = null;\n\n private _config: InputConfig;\n private _state: ConnectionState = \"disconnected\";\n private _protocol: TransportProtocol = \"none\";\n\n get config(): InputConfig {\n return this._config;\n }\n\n get state(): ConnectionState {\n return this._state;\n }\n\n get protocol(): TransportProtocol {\n return this._protocol;\n }\n\n constructor(config?: Partial<InputConfig>, storage?: StorageAdapter) {\n super();\n this.storage = storage;\n const persisted = loadSettings(storage);\n this._config = mergeConfig(DEFAULT_CONFIG, { ...config, ...persisted });\n this.flushTimer = setInterval(() => this.flushAccumulator(), 16);\n }\n\n addConnection(connection: SatMouseConnection): void {\n this.connections.push(connection);\n this.wireConnection(connection);\n }\n\n /** Reset retry count and reconnect all failed connections. */\n retry(): void {\n for (const c of this.connections) c.retry();\n }\n\n removeConnection(connection: SatMouseConnection): void {\n const idx = this.connections.indexOf(connection);\n if (idx !== -1) this.connections.splice(idx, 1);\n connection.removeAllListeners();\n }\n\n async connect(): Promise<void> {\n await Promise.all(this.connections.map((c) => c.connect()));\n }\n\n disconnect(): void {\n for (const c of this.connections) c.disconnect();\n if (this.flushTimer) { clearInterval(this.flushTimer); this.flushTimer = null; }\n }\n\n async fetchDeviceInfo(): Promise<DeviceInfo[]> {\n const results = await Promise.all(this.connections.map((c) => c.fetchDeviceInfo()));\n const devices = results.flat();\n for (const d of devices) this.knownDevices.set(d.id, d);\n return devices;\n }\n\n getDevicesWithConfig(): DeviceWithConfig[] {\n return Array.from(this.knownDevices.values()).map((device) => ({\n device,\n config: this.getDeviceConfig(device.id),\n }));\n }\n\n getDeviceConfig(deviceId: string): DeviceConfig {\n const resolved = resolveDeviceConfig(this._config, deviceId);\n return {\n routes: resolved.routes,\n buttonRoutes: resolved.buttonRoutes,\n translateScale: resolved.translateScale,\n rotateScale: resolved.rotateScale,\n wScale: resolved.wScale,\n deadZone: resolved.deadZone,\n dominant: resolved.dominant,\n };\n }\n\n updateConfig(partial: Partial<InputConfig>, persist = true): void {\n this._config = mergeConfig(this._config, partial);\n if (persist) saveSettings(this._config, this.storage);\n this.emit(\"configChange\", this._config);\n }\n\n updateDeviceConfig(deviceId: string, partial: DeviceConfig, persist = true): void {\n const existing = this._config.devices[deviceId] ?? {};\n this._config = mergeConfig(this._config, {\n devices: { [deviceId]: { ...existing, ...partial } },\n });\n if (persist) saveSettings(this._config, this.storage);\n this.emit(\"configChange\", this._config);\n }\n\n resetDeviceConfig(deviceId: string, persist = true): void {\n const { [deviceId]: _, ...rest } = this._config.devices;\n this._config = { ...this._config, devices: rest };\n if (persist) saveSettings(this._config, this.storage);\n this.emit(\"configChange\", this._config);\n }\n\n resetAllConfig(): void {\n clearSettings(this.storage);\n this._config = { ...DEFAULT_CONFIG };\n this.emit(\"configChange\", this._config);\n }\n\n onSpatialData(callback: (data: SpatialData) => void): () => void {\n this.on(\"spatialData\", callback);\n return () => this.off(\"spatialData\", callback);\n }\n\n onButtonEvent(callback: (data: ButtonEvent) => void): () => void {\n this.on(\"buttonEvent\", callback);\n return () => this.off(\"buttonEvent\", callback);\n }\n\n private wireConnection(connection: SatMouseConnection): void {\n connection.on(\"spatialData\", (raw) => {\n this.emit(\"rawSpatialData\", raw);\n\n const id = raw.deviceId ?? \"_default\";\n const processed = this.processPerDevice(raw, id);\n\n this.deviceAccumulators.set(id, {\n tx: processed.translation.x,\n ty: processed.translation.y,\n tz: processed.translation.z,\n rx: processed.rotation.x,\n ry: processed.rotation.y,\n rz: processed.rotation.z,\n w: processed.w ?? 0,\n });\n this.accDirty = true;\n });\n\n connection.on(\"buttonEvent\", (event) => {\n // Check all device configs for matching button routes\n this.dispatchButtonKeys(event);\n this.emit(\"buttonEvent\", event);\n });\n connection.on(\"stateChange\", (state, proto) => {\n this._state = state;\n this._protocol = proto;\n this.emit(\"stateChange\", state, proto);\n });\n connection.on(\"deviceStatus\", (event, device) => {\n if (event === \"connected\") this.knownDevices.set(device.id, device);\n else this.knownDevices.delete(device.id);\n this.emit(\"deviceStatus\", event, device);\n });\n }\n\n private flushAccumulator(): void {\n if (!this.accDirty) return;\n\n const merged = { tx: 0, ty: 0, tz: 0, rx: 0, ry: 0, rz: 0, w: 0 };\n for (const acc of this.deviceAccumulators.values()) {\n merged.tx += acc.tx;\n merged.ty += acc.ty;\n merged.tz += acc.tz;\n merged.rx += acc.rx;\n merged.ry += acc.ry;\n merged.rz += acc.rz;\n merged.w += acc.w;\n }\n\n this.deviceAccumulators.clear();\n this.accDirty = false;\n\n let data: SpatialData = {\n translation: { x: merged.tx, y: merged.ty, z: merged.tz },\n rotation: { x: merged.rx, y: merged.ry, z: merged.rz },\n w: merged.w || undefined,\n timestamp: performance.now() * 1000,\n };\n\n if (this._config.lockPosition) {\n data = { ...data, translation: { x: 0, y: 0, z: 0 } };\n }\n if (this._config.lockRotation) {\n data = { ...data, rotation: { x: 0, y: 0, z: 0 } };\n }\n\n this.emit(\"spatialData\", data);\n }\n\n /** Per-device: deadZone → dominant → routes (flip + scale + remap in one pass) */\n private processPerDevice(raw: SpatialData, deviceId: string): SpatialData {\n const cfg = resolveDeviceConfig(this._config, deviceId);\n let data = raw;\n\n // Dead zone\n if (cfg.deadZone > 0) {\n const dz = (v: number) => (Math.abs(v) < cfg.deadZone ? 0 : v);\n data = {\n ...data,\n translation: { x: dz(data.translation.x), y: dz(data.translation.y), z: dz(data.translation.z) },\n rotation: { x: dz(data.rotation.x), y: dz(data.rotation.y), z: dz(data.rotation.z) },\n };\n }\n\n // Dominant axis\n if (cfg.dominant) {\n const axes = [\n { g: \"t\" as const, k: \"x\" as const, v: Math.abs(data.translation.x) },\n { g: \"t\" as const, k: \"y\" as const, v: Math.abs(data.translation.y) },\n { g: \"t\" as const, k: \"z\" as const, v: Math.abs(data.translation.z) },\n { g: \"r\" as const, k: \"x\" as const, v: Math.abs(data.rotation.x) },\n { g: \"r\" as const, k: \"y\" as const, v: Math.abs(data.rotation.y) },\n { g: \"r\" as const, k: \"z\" as const, v: Math.abs(data.rotation.z) },\n ];\n const max = axes.reduce((a, b) => (b.v > a.v ? b : a));\n const t = { x: 0, y: 0, z: 0 };\n const r = { x: 0, y: 0, z: 0 };\n if (max.g === \"t\") t[max.k] = data.translation[max.k];\n else r[max.k] = data.rotation[max.k];\n data = { ...data, translation: t, rotation: r };\n }\n\n // Routes: flip + scale + remap in one pass\n // Use device-specific routes if configured, otherwise build from device axes metadata\n const device = this.knownDevices.get(deviceId);\n const deviceRoutes = this.resolveRoutes(deviceId, device);\n data = applyRoutes(data, deviceRoutes, cfg.translateScale, cfg.rotateScale, cfg.wScale);\n\n return data;\n }\n\n /** Get the effective routes for a device: device config override > device axes metadata > global default */\n private resolveRoutes(deviceId: string, device?: DeviceInfo): AxisRoute[] {\n // Check for explicit device config (exact match or pattern)\n const devCfg = this._config.devices[deviceId];\n if (devCfg?.routes && Array.isArray(devCfg.routes)) return devCfg.routes;\n\n // Check pattern matches\n for (const [pattern, cfg] of Object.entries(this._config.devices)) {\n if (pattern.endsWith(\"*\") && deviceId.startsWith(pattern.slice(0, -1))) {\n if (cfg.routes && Array.isArray(cfg.routes)) return cfg.routes;\n }\n }\n\n // Build from device axes metadata\n if (device?.axes) return buildRoutes(device.axes);\n\n // Global fallback\n return DEFAULT_ROUTES;\n }\n\n /** Dispatch KeyboardEvents for button routes matching this button event */\n private dispatchButtonKeys(event: ButtonEvent): void {\n if (typeof document === \"undefined\") return;\n\n // Collect all button routes from all device configs + global\n const allRoutes = this.collectButtonRoutes();\n for (const route of allRoutes) {\n if (route.button === event.button) {\n document.dispatchEvent(new KeyboardEvent(\n event.pressed ? \"keydown\" : \"keyup\",\n { key: route.key, code: route.code ?? \"\", bubbles: true },\n ));\n }\n }\n }\n\n /** Gather all button routes from global config + all device configs */\n private collectButtonRoutes(): import(\"./config.js\").ButtonRoute[] {\n const routes = [...this._config.buttonRoutes];\n for (const devCfg of Object.values(this._config.devices)) {\n if (devCfg.buttonRoutes) routes.push(...devCfg.buttonRoutes);\n }\n return routes;\n }\n}\n"]}
|
package/dist/utils/index.d.cts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { S as SpatialData, D as DeviceInfo, e as TypedEmitter, B as ButtonEvent, a as ConnectionState, d as TransportProtocol, b as SatMouseConnection } from '../connection-
|
|
1
|
+
import { S as SpatialData, D as DeviceInfo, e as TypedEmitter, B as ButtonEvent, a as ConnectionState, d as TransportProtocol, b as SatMouseConnection } from '../connection-iUlge6Er.cjs';
|
|
2
2
|
|
|
3
3
|
/** Axis identifier — full or half */
|
|
4
|
-
type InputAxis = "tx" | "ty" | "tz" | "rx" | "ry" | "rz" | "tx+" | "ty+" | "tz+" | "rx+" | "ry+" | "rz+" | "tx-" | "ty-" | "tz-" | "rx-" | "ry-" | "rz-";
|
|
5
|
-
/** The
|
|
4
|
+
type InputAxis = "tx" | "ty" | "tz" | "rx" | "ry" | "rz" | "w" | "tx+" | "ty+" | "tz+" | "rx+" | "ry+" | "rz+" | "w+" | "tx-" | "ty-" | "tz-" | "rx-" | "ry-" | "rz-" | "w-";
|
|
5
|
+
/** The 7 full output axes (6DOF + W) */
|
|
6
6
|
declare const FULL_AXES: InputAxis[];
|
|
7
7
|
/** A single axis route — reads from source, writes to target */
|
|
8
8
|
interface AxisRoute {
|
|
@@ -16,16 +16,30 @@ declare const DEFAULT_ROUTES: AxisRoute[];
|
|
|
16
16
|
/** Build passthrough routes from a device's axis list. Half-axes target their base axis.
|
|
17
17
|
* Negative half-axes (e.g., "ty-") get flip: true. */
|
|
18
18
|
declare function buildRoutes(axes: string[]): AxisRoute[];
|
|
19
|
-
/** Apply routes to SpatialData. Multiple routes targeting the same axis accumulate.
|
|
20
|
-
|
|
21
|
-
declare function applyRoutes(data: SpatialData, routes: AxisRoute[], scale?: number): SpatialData;
|
|
19
|
+
/** Apply routes to SpatialData. Multiple routes targeting the same axis accumulate. */
|
|
20
|
+
declare function applyRoutes(data: SpatialData, routes: AxisRoute[], translateScale?: number, rotateScale?: number, wScale?: number): SpatialData;
|
|
22
21
|
|
|
22
|
+
/** Maps a device button to a keyboard key */
|
|
23
|
+
interface ButtonRoute {
|
|
24
|
+
/** Device button index */
|
|
25
|
+
button: number;
|
|
26
|
+
/** Keyboard key value (KeyboardEvent.key, e.g., "a", "Shift", "ArrowUp") */
|
|
27
|
+
key: string;
|
|
28
|
+
/** Keyboard code (KeyboardEvent.code, e.g., "KeyA", "ShiftLeft"). Optional. */
|
|
29
|
+
code?: string;
|
|
30
|
+
}
|
|
23
31
|
/** Per-device configuration */
|
|
24
32
|
interface DeviceConfig {
|
|
25
33
|
/** Axis routing — each entry maps a device input to an output with optional flip */
|
|
26
34
|
routes?: AxisRoute[];
|
|
27
|
-
/**
|
|
28
|
-
|
|
35
|
+
/** Button-to-key mappings */
|
|
36
|
+
buttonRoutes?: ButtonRoute[];
|
|
37
|
+
/** Scale multiplier for translation axes (tx, ty, tz) */
|
|
38
|
+
translateScale?: number;
|
|
39
|
+
/** Scale multiplier for rotation axes (rx, ry, rz) */
|
|
40
|
+
rotateScale?: number;
|
|
41
|
+
/** Scale multiplier for W axis */
|
|
42
|
+
wScale?: number;
|
|
29
43
|
/** Dead zone threshold (0-1). Values below this are zeroed. */
|
|
30
44
|
deadZone?: number;
|
|
31
45
|
/** Only pass the strongest axis, zero all others */
|
|
@@ -35,8 +49,14 @@ interface DeviceConfig {
|
|
|
35
49
|
interface InputConfig {
|
|
36
50
|
/** Default axis routes (used when device has no override) */
|
|
37
51
|
routes: AxisRoute[];
|
|
38
|
-
/** Default
|
|
39
|
-
|
|
52
|
+
/** Default button-to-key mappings */
|
|
53
|
+
buttonRoutes: ButtonRoute[];
|
|
54
|
+
/** Scale multiplier for translation axes */
|
|
55
|
+
translateScale: number;
|
|
56
|
+
/** Scale multiplier for rotation axes */
|
|
57
|
+
rotateScale: number;
|
|
58
|
+
/** Scale multiplier for W axis */
|
|
59
|
+
wScale: number;
|
|
40
60
|
/** Dead zone threshold */
|
|
41
61
|
deadZone: number;
|
|
42
62
|
/** Dominant axis mode */
|
|
@@ -107,6 +127,10 @@ declare class InputManager extends TypedEmitter<InputManagerEvents> {
|
|
|
107
127
|
private processPerDevice;
|
|
108
128
|
/** Get the effective routes for a device: device config override > device axes metadata > global default */
|
|
109
129
|
private resolveRoutes;
|
|
130
|
+
/** Dispatch KeyboardEvents for button routes matching this button event */
|
|
131
|
+
private dispatchButtonKeys;
|
|
132
|
+
/** Gather all button routes from global config + all device configs */
|
|
133
|
+
private collectButtonRoutes;
|
|
110
134
|
}
|
|
111
135
|
|
|
112
|
-
export { type AxisRoute, DEFAULT_CONFIG, DEFAULT_ROUTES, type DeviceConfig, type DeviceWithConfig, FULL_AXES, type InputAxis, type InputConfig, InputManager, type InputManagerEvents, type StorageAdapter, applyRoutes, buildRoutes, loadSettings, mergeConfig, resolveDeviceConfig, saveSettings };
|
|
136
|
+
export { type AxisRoute, type ButtonRoute, DEFAULT_CONFIG, DEFAULT_ROUTES, type DeviceConfig, type DeviceWithConfig, FULL_AXES, type InputAxis, type InputConfig, InputManager, type InputManagerEvents, type StorageAdapter, applyRoutes, buildRoutes, loadSettings, mergeConfig, resolveDeviceConfig, saveSettings };
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { S as SpatialData, D as DeviceInfo, e as TypedEmitter, B as ButtonEvent, a as ConnectionState, d as TransportProtocol, b as SatMouseConnection } from '../connection-
|
|
1
|
+
import { S as SpatialData, D as DeviceInfo, e as TypedEmitter, B as ButtonEvent, a as ConnectionState, d as TransportProtocol, b as SatMouseConnection } from '../connection-iUlge6Er.js';
|
|
2
2
|
|
|
3
3
|
/** Axis identifier — full or half */
|
|
4
|
-
type InputAxis = "tx" | "ty" | "tz" | "rx" | "ry" | "rz" | "tx+" | "ty+" | "tz+" | "rx+" | "ry+" | "rz+" | "tx-" | "ty-" | "tz-" | "rx-" | "ry-" | "rz-";
|
|
5
|
-
/** The
|
|
4
|
+
type InputAxis = "tx" | "ty" | "tz" | "rx" | "ry" | "rz" | "w" | "tx+" | "ty+" | "tz+" | "rx+" | "ry+" | "rz+" | "w+" | "tx-" | "ty-" | "tz-" | "rx-" | "ry-" | "rz-" | "w-";
|
|
5
|
+
/** The 7 full output axes (6DOF + W) */
|
|
6
6
|
declare const FULL_AXES: InputAxis[];
|
|
7
7
|
/** A single axis route — reads from source, writes to target */
|
|
8
8
|
interface AxisRoute {
|
|
@@ -16,16 +16,30 @@ declare const DEFAULT_ROUTES: AxisRoute[];
|
|
|
16
16
|
/** Build passthrough routes from a device's axis list. Half-axes target their base axis.
|
|
17
17
|
* Negative half-axes (e.g., "ty-") get flip: true. */
|
|
18
18
|
declare function buildRoutes(axes: string[]): AxisRoute[];
|
|
19
|
-
/** Apply routes to SpatialData. Multiple routes targeting the same axis accumulate.
|
|
20
|
-
|
|
21
|
-
declare function applyRoutes(data: SpatialData, routes: AxisRoute[], scale?: number): SpatialData;
|
|
19
|
+
/** Apply routes to SpatialData. Multiple routes targeting the same axis accumulate. */
|
|
20
|
+
declare function applyRoutes(data: SpatialData, routes: AxisRoute[], translateScale?: number, rotateScale?: number, wScale?: number): SpatialData;
|
|
22
21
|
|
|
22
|
+
/** Maps a device button to a keyboard key */
|
|
23
|
+
interface ButtonRoute {
|
|
24
|
+
/** Device button index */
|
|
25
|
+
button: number;
|
|
26
|
+
/** Keyboard key value (KeyboardEvent.key, e.g., "a", "Shift", "ArrowUp") */
|
|
27
|
+
key: string;
|
|
28
|
+
/** Keyboard code (KeyboardEvent.code, e.g., "KeyA", "ShiftLeft"). Optional. */
|
|
29
|
+
code?: string;
|
|
30
|
+
}
|
|
23
31
|
/** Per-device configuration */
|
|
24
32
|
interface DeviceConfig {
|
|
25
33
|
/** Axis routing — each entry maps a device input to an output with optional flip */
|
|
26
34
|
routes?: AxisRoute[];
|
|
27
|
-
/**
|
|
28
|
-
|
|
35
|
+
/** Button-to-key mappings */
|
|
36
|
+
buttonRoutes?: ButtonRoute[];
|
|
37
|
+
/** Scale multiplier for translation axes (tx, ty, tz) */
|
|
38
|
+
translateScale?: number;
|
|
39
|
+
/** Scale multiplier for rotation axes (rx, ry, rz) */
|
|
40
|
+
rotateScale?: number;
|
|
41
|
+
/** Scale multiplier for W axis */
|
|
42
|
+
wScale?: number;
|
|
29
43
|
/** Dead zone threshold (0-1). Values below this are zeroed. */
|
|
30
44
|
deadZone?: number;
|
|
31
45
|
/** Only pass the strongest axis, zero all others */
|
|
@@ -35,8 +49,14 @@ interface DeviceConfig {
|
|
|
35
49
|
interface InputConfig {
|
|
36
50
|
/** Default axis routes (used when device has no override) */
|
|
37
51
|
routes: AxisRoute[];
|
|
38
|
-
/** Default
|
|
39
|
-
|
|
52
|
+
/** Default button-to-key mappings */
|
|
53
|
+
buttonRoutes: ButtonRoute[];
|
|
54
|
+
/** Scale multiplier for translation axes */
|
|
55
|
+
translateScale: number;
|
|
56
|
+
/** Scale multiplier for rotation axes */
|
|
57
|
+
rotateScale: number;
|
|
58
|
+
/** Scale multiplier for W axis */
|
|
59
|
+
wScale: number;
|
|
40
60
|
/** Dead zone threshold */
|
|
41
61
|
deadZone: number;
|
|
42
62
|
/** Dominant axis mode */
|
|
@@ -107,6 +127,10 @@ declare class InputManager extends TypedEmitter<InputManagerEvents> {
|
|
|
107
127
|
private processPerDevice;
|
|
108
128
|
/** Get the effective routes for a device: device config override > device axes metadata > global default */
|
|
109
129
|
private resolveRoutes;
|
|
130
|
+
/** Dispatch KeyboardEvents for button routes matching this button event */
|
|
131
|
+
private dispatchButtonKeys;
|
|
132
|
+
/** Gather all button routes from global config + all device configs */
|
|
133
|
+
private collectButtonRoutes;
|
|
110
134
|
}
|
|
111
135
|
|
|
112
|
-
export { type AxisRoute, DEFAULT_CONFIG, DEFAULT_ROUTES, type DeviceConfig, type DeviceWithConfig, FULL_AXES, type InputAxis, type InputConfig, InputManager, type InputManagerEvents, type StorageAdapter, applyRoutes, buildRoutes, loadSettings, mergeConfig, resolveDeviceConfig, saveSettings };
|
|
136
|
+
export { type AxisRoute, type ButtonRoute, DEFAULT_CONFIG, DEFAULT_ROUTES, type DeviceConfig, type DeviceWithConfig, FULL_AXES, type InputAxis, type InputConfig, InputManager, type InputManagerEvents, type StorageAdapter, applyRoutes, buildRoutes, loadSettings, mergeConfig, resolveDeviceConfig, saveSettings };
|
package/dist/utils/index.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { TypedEmitter } from '../chunk-X6NIARXW.js';
|
|
2
|
-
import { DEFAULT_ROUTES, applyRoutes, buildRoutes } from '../chunk-
|
|
3
|
-
export { DEFAULT_ROUTES, FULL_AXES, applyRoutes, buildRoutes } from '../chunk-
|
|
2
|
+
import { DEFAULT_ROUTES, applyRoutes, buildRoutes } from '../chunk-RE4PNORY.js';
|
|
3
|
+
export { DEFAULT_ROUTES, FULL_AXES, applyRoutes, buildRoutes } from '../chunk-RE4PNORY.js';
|
|
4
4
|
|
|
5
5
|
// src/utils/config.ts
|
|
6
6
|
var DEFAULT_CONFIG = {
|
|
7
7
|
routes: DEFAULT_ROUTES,
|
|
8
|
-
|
|
8
|
+
buttonRoutes: [],
|
|
9
|
+
translateScale: 1e-3,
|
|
10
|
+
rotateScale: 1e-3,
|
|
11
|
+
wScale: 1e-3,
|
|
9
12
|
deadZone: 0,
|
|
10
13
|
dominant: false,
|
|
11
14
|
lockPosition: false,
|
|
@@ -39,6 +42,7 @@ function mergeConfig(base, partial) {
|
|
|
39
42
|
...base,
|
|
40
43
|
...partial,
|
|
41
44
|
routes: partial.routes ?? [...base.routes],
|
|
45
|
+
buttonRoutes: partial.buttonRoutes ?? [...base.buttonRoutes],
|
|
42
46
|
devices: { ...base.devices }
|
|
43
47
|
};
|
|
44
48
|
if (partial.devices) {
|
|
@@ -64,7 +68,10 @@ function resolveDeviceConfig(config, deviceId) {
|
|
|
64
68
|
return {
|
|
65
69
|
...config,
|
|
66
70
|
routes: deviceOverride.routes ?? config.routes,
|
|
67
|
-
|
|
71
|
+
buttonRoutes: deviceOverride.buttonRoutes ?? config.buttonRoutes,
|
|
72
|
+
translateScale: deviceOverride.translateScale ?? config.translateScale,
|
|
73
|
+
rotateScale: deviceOverride.rotateScale ?? config.rotateScale,
|
|
74
|
+
wScale: deviceOverride.wScale ?? config.wScale,
|
|
68
75
|
deadZone: deviceOverride.deadZone ?? config.deadZone,
|
|
69
76
|
dominant: deviceOverride.dominant ?? config.dominant
|
|
70
77
|
};
|
|
@@ -168,7 +175,10 @@ var InputManager = class extends TypedEmitter {
|
|
|
168
175
|
const resolved = resolveDeviceConfig(this._config, deviceId);
|
|
169
176
|
return {
|
|
170
177
|
routes: resolved.routes,
|
|
171
|
-
|
|
178
|
+
buttonRoutes: resolved.buttonRoutes,
|
|
179
|
+
translateScale: resolved.translateScale,
|
|
180
|
+
rotateScale: resolved.rotateScale,
|
|
181
|
+
wScale: resolved.wScale,
|
|
172
182
|
deadZone: resolved.deadZone,
|
|
173
183
|
dominant: resolved.dominant
|
|
174
184
|
};
|
|
@@ -216,11 +226,15 @@ var InputManager = class extends TypedEmitter {
|
|
|
216
226
|
tz: processed.translation.z,
|
|
217
227
|
rx: processed.rotation.x,
|
|
218
228
|
ry: processed.rotation.y,
|
|
219
|
-
rz: processed.rotation.z
|
|
229
|
+
rz: processed.rotation.z,
|
|
230
|
+
w: processed.w ?? 0
|
|
220
231
|
});
|
|
221
232
|
this.accDirty = true;
|
|
222
233
|
});
|
|
223
|
-
connection.on("buttonEvent", (event) =>
|
|
234
|
+
connection.on("buttonEvent", (event) => {
|
|
235
|
+
this.dispatchButtonKeys(event);
|
|
236
|
+
this.emit("buttonEvent", event);
|
|
237
|
+
});
|
|
224
238
|
connection.on("stateChange", (state, proto) => {
|
|
225
239
|
this._state = state;
|
|
226
240
|
this._protocol = proto;
|
|
@@ -234,7 +248,7 @@ var InputManager = class extends TypedEmitter {
|
|
|
234
248
|
}
|
|
235
249
|
flushAccumulator() {
|
|
236
250
|
if (!this.accDirty) return;
|
|
237
|
-
const merged = { tx: 0, ty: 0, tz: 0, rx: 0, ry: 0, rz: 0 };
|
|
251
|
+
const merged = { tx: 0, ty: 0, tz: 0, rx: 0, ry: 0, rz: 0, w: 0 };
|
|
238
252
|
for (const acc of this.deviceAccumulators.values()) {
|
|
239
253
|
merged.tx += acc.tx;
|
|
240
254
|
merged.ty += acc.ty;
|
|
@@ -242,12 +256,14 @@ var InputManager = class extends TypedEmitter {
|
|
|
242
256
|
merged.rx += acc.rx;
|
|
243
257
|
merged.ry += acc.ry;
|
|
244
258
|
merged.rz += acc.rz;
|
|
259
|
+
merged.w += acc.w;
|
|
245
260
|
}
|
|
246
261
|
this.deviceAccumulators.clear();
|
|
247
262
|
this.accDirty = false;
|
|
248
263
|
let data = {
|
|
249
264
|
translation: { x: merged.tx, y: merged.ty, z: merged.tz },
|
|
250
265
|
rotation: { x: merged.rx, y: merged.ry, z: merged.rz },
|
|
266
|
+
w: merged.w || void 0,
|
|
251
267
|
timestamp: performance.now() * 1e3
|
|
252
268
|
};
|
|
253
269
|
if (this._config.lockPosition) {
|
|
@@ -288,7 +304,7 @@ var InputManager = class extends TypedEmitter {
|
|
|
288
304
|
}
|
|
289
305
|
const device = this.knownDevices.get(deviceId);
|
|
290
306
|
const deviceRoutes = this.resolveRoutes(deviceId, device);
|
|
291
|
-
data = applyRoutes(data, deviceRoutes, cfg.
|
|
307
|
+
data = applyRoutes(data, deviceRoutes, cfg.translateScale, cfg.rotateScale, cfg.wScale);
|
|
292
308
|
return data;
|
|
293
309
|
}
|
|
294
310
|
/** Get the effective routes for a device: device config override > device axes metadata > global default */
|
|
@@ -303,6 +319,27 @@ var InputManager = class extends TypedEmitter {
|
|
|
303
319
|
if (device?.axes) return buildRoutes(device.axes);
|
|
304
320
|
return DEFAULT_ROUTES;
|
|
305
321
|
}
|
|
322
|
+
/** Dispatch KeyboardEvents for button routes matching this button event */
|
|
323
|
+
dispatchButtonKeys(event) {
|
|
324
|
+
if (typeof document === "undefined") return;
|
|
325
|
+
const allRoutes = this.collectButtonRoutes();
|
|
326
|
+
for (const route of allRoutes) {
|
|
327
|
+
if (route.button === event.button) {
|
|
328
|
+
document.dispatchEvent(new KeyboardEvent(
|
|
329
|
+
event.pressed ? "keydown" : "keyup",
|
|
330
|
+
{ key: route.key, code: route.code ?? "", bubbles: true }
|
|
331
|
+
));
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
/** Gather all button routes from global config + all device configs */
|
|
336
|
+
collectButtonRoutes() {
|
|
337
|
+
const routes = [...this._config.buttonRoutes];
|
|
338
|
+
for (const devCfg of Object.values(this._config.devices)) {
|
|
339
|
+
if (devCfg.buttonRoutes) routes.push(...devCfg.buttonRoutes);
|
|
340
|
+
}
|
|
341
|
+
return routes;
|
|
342
|
+
}
|
|
306
343
|
};
|
|
307
344
|
|
|
308
345
|
export { DEFAULT_CONFIG, InputManager, loadSettings, mergeConfig, resolveDeviceConfig, saveSettings };
|