@kelnishi/satmouse-client 0.9.9 → 0.9.13
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-I47ZOX3M.js +64 -0
- package/dist/chunk-I47ZOX3M.js.map +1 -0
- package/dist/chunk-LDSDVYCV.cjs +69 -0
- package/dist/chunk-LDSDVYCV.cjs.map +1 -0
- package/dist/{connection-CH2YsPn1.d.cts → connection-5KQFvHoJ.d.cts} +8 -1
- package/dist/{connection-CH2YsPn1.d.ts → connection-5KQFvHoJ.d.ts} +8 -1
- package/dist/core/index.cjs +16 -0
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +2 -2
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +16 -0
- package/dist/core/index.js.map +1 -1
- package/dist/elements/index.cjs +301 -0
- package/dist/elements/index.cjs.map +1 -0
- package/dist/elements/index.d.cts +35 -0
- package/dist/elements/index.d.ts +35 -0
- package/dist/elements/index.js +295 -0
- package/dist/elements/index.js.map +1 -0
- package/dist/react/index.cjs +71 -7
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +16 -2
- package/dist/react/index.d.ts +16 -2
- package/dist/react/index.js +71 -7
- package/dist/react/index.js.map +1 -1
- package/dist/utils/index.cjs +75 -75
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.d.cts +9 -2
- package/dist/utils/index.d.ts +9 -2
- package/dist/utils/index.js +58 -69
- package/dist/utils/index.js.map +1 -1
- package/package.json +9 -3
package/dist/utils/index.cjs
CHANGED
|
@@ -1,79 +1,22 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkI5MEZZOT_cjs = require('../chunk-I5MEZZOT.cjs');
|
|
4
|
-
|
|
5
|
-
// src/utils/action-map.ts
|
|
6
|
-
var DEFAULT_ACTION_MAP = {
|
|
7
|
-
tx: { source: "tx" },
|
|
8
|
-
ty: { source: "ty" },
|
|
9
|
-
tz: { source: "tz" },
|
|
10
|
-
rx: { source: "rx" },
|
|
11
|
-
ry: { source: "ry" },
|
|
12
|
-
rz: { source: "rz" }
|
|
13
|
-
};
|
|
14
|
-
function readAxis(data, axis) {
|
|
15
|
-
switch (axis) {
|
|
16
|
-
case "tx":
|
|
17
|
-
return data.translation.x;
|
|
18
|
-
case "ty":
|
|
19
|
-
return data.translation.y;
|
|
20
|
-
case "tz":
|
|
21
|
-
return data.translation.z;
|
|
22
|
-
case "rx":
|
|
23
|
-
return data.rotation.x;
|
|
24
|
-
case "ry":
|
|
25
|
-
return data.rotation.y;
|
|
26
|
-
case "rz":
|
|
27
|
-
return data.rotation.z;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
function applyActionMap(data, map) {
|
|
31
|
-
const result = {};
|
|
32
|
-
for (const [action, binding] of Object.entries(map)) {
|
|
33
|
-
let value = readAxis(data, binding.source);
|
|
34
|
-
if (binding.invert) value = -value;
|
|
35
|
-
value *= binding.scale ?? 1;
|
|
36
|
-
result[action] = value;
|
|
37
|
-
}
|
|
38
|
-
return result;
|
|
39
|
-
}
|
|
40
|
-
function actionValuesToSpatialData(values, timestamp) {
|
|
41
|
-
return {
|
|
42
|
-
translation: {
|
|
43
|
-
x: values.tx ?? 0,
|
|
44
|
-
y: values.ty ?? 0,
|
|
45
|
-
z: values.tz ?? 0
|
|
46
|
-
},
|
|
47
|
-
rotation: {
|
|
48
|
-
x: values.rx ?? 0,
|
|
49
|
-
y: values.ry ?? 0,
|
|
50
|
-
z: values.rz ?? 0
|
|
51
|
-
},
|
|
52
|
-
timestamp
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
function swapActions(map, actionA, actionB) {
|
|
56
|
-
const result = { ...map };
|
|
57
|
-
const a = result[actionA];
|
|
58
|
-
const b = result[actionB];
|
|
59
|
-
if (a && b) {
|
|
60
|
-
result[actionA] = b;
|
|
61
|
-
result[actionB] = a;
|
|
62
|
-
}
|
|
63
|
-
return result;
|
|
64
|
-
}
|
|
4
|
+
var chunkLDSDVYCV_cjs = require('../chunk-LDSDVYCV.cjs');
|
|
65
5
|
|
|
66
6
|
// src/utils/config.ts
|
|
67
7
|
var DEFAULT_CONFIG = {
|
|
68
8
|
sensitivity: { translation: 1e-3, rotation: 1e-3 },
|
|
69
|
-
flip: { tx: false, ty:
|
|
9
|
+
flip: { tx: false, ty: false, tz: false, rx: false, ry: false, rz: false },
|
|
70
10
|
deadZone: 0,
|
|
71
11
|
dominant: false,
|
|
72
12
|
axisRemap: { tx: "x", ty: "y", tz: "z", rx: "x", ry: "y", rz: "z" },
|
|
73
13
|
lockPosition: false,
|
|
74
14
|
lockRotation: false,
|
|
75
|
-
actionMap: { ...DEFAULT_ACTION_MAP },
|
|
76
|
-
devices: {
|
|
15
|
+
actionMap: { ...chunkLDSDVYCV_cjs.DEFAULT_ACTION_MAP },
|
|
16
|
+
devices: {
|
|
17
|
+
// SpaceMouse Z-up → Three.js Y-up axis correction
|
|
18
|
+
"cnx-*": { flip: { ty: true, tz: true, ry: true, rz: true } }
|
|
19
|
+
}
|
|
77
20
|
};
|
|
78
21
|
function mergeConfig(base, partial) {
|
|
79
22
|
const merged = {
|
|
@@ -245,6 +188,10 @@ var InputManager = class extends chunkI5MEZZOT_cjs.TypedEmitter {
|
|
|
245
188
|
connections = [];
|
|
246
189
|
storage;
|
|
247
190
|
knownDevices = /* @__PURE__ */ new Map();
|
|
191
|
+
// Per-device accumulators: latest value from each device per frame tick
|
|
192
|
+
deviceAccumulators = /* @__PURE__ */ new Map();
|
|
193
|
+
accDirty = false;
|
|
194
|
+
flushTimer = null;
|
|
248
195
|
_config;
|
|
249
196
|
get config() {
|
|
250
197
|
return this._config;
|
|
@@ -254,6 +201,7 @@ var InputManager = class extends chunkI5MEZZOT_cjs.TypedEmitter {
|
|
|
254
201
|
this.storage = storage;
|
|
255
202
|
const persisted = loadSettings(storage);
|
|
256
203
|
this._config = mergeConfig(DEFAULT_CONFIG, { ...config, ...persisted });
|
|
204
|
+
this.flushTimer = setInterval(() => this.flushAccumulator(), 16);
|
|
257
205
|
}
|
|
258
206
|
/** Add a connection to the managed set */
|
|
259
207
|
addConnection(connection) {
|
|
@@ -273,6 +221,10 @@ var InputManager = class extends chunkI5MEZZOT_cjs.TypedEmitter {
|
|
|
273
221
|
/** Disconnect all managed connections */
|
|
274
222
|
disconnect() {
|
|
275
223
|
for (const c of this.connections) c.disconnect();
|
|
224
|
+
if (this.flushTimer) {
|
|
225
|
+
clearInterval(this.flushTimer);
|
|
226
|
+
this.flushTimer = null;
|
|
227
|
+
}
|
|
276
228
|
}
|
|
277
229
|
/** Fetch device info from all connections */
|
|
278
230
|
async fetchDeviceInfo() {
|
|
@@ -335,9 +287,17 @@ var InputManager = class extends chunkI5MEZZOT_cjs.TypedEmitter {
|
|
|
335
287
|
wireConnection(connection) {
|
|
336
288
|
connection.on("spatialData", (raw) => {
|
|
337
289
|
this.emit("rawSpatialData", raw);
|
|
338
|
-
const
|
|
339
|
-
|
|
340
|
-
|
|
290
|
+
const id = raw.deviceId ?? "_default";
|
|
291
|
+
const processed = this.processPerDevice(raw, id);
|
|
292
|
+
this.deviceAccumulators.set(id, {
|
|
293
|
+
tx: processed.translation.x,
|
|
294
|
+
ty: processed.translation.y,
|
|
295
|
+
tz: processed.translation.z,
|
|
296
|
+
rx: processed.rotation.x,
|
|
297
|
+
ry: processed.rotation.y,
|
|
298
|
+
rz: processed.rotation.z
|
|
299
|
+
});
|
|
300
|
+
this.accDirty = true;
|
|
341
301
|
});
|
|
342
302
|
connection.on("buttonEvent", (event) => this.emit("buttonEvent", event));
|
|
343
303
|
connection.on("stateChange", (state, proto) => this.emit("stateChange", state, proto));
|
|
@@ -347,32 +307,73 @@ var InputManager = class extends chunkI5MEZZOT_cjs.TypedEmitter {
|
|
|
347
307
|
this.emit("deviceStatus", event, device);
|
|
348
308
|
});
|
|
349
309
|
}
|
|
350
|
-
|
|
351
|
-
|
|
310
|
+
flushAccumulator() {
|
|
311
|
+
if (!this.accDirty) return;
|
|
312
|
+
const merged = { tx: 0, ty: 0, tz: 0, rx: 0, ry: 0, rz: 0 };
|
|
313
|
+
for (const acc of this.deviceAccumulators.values()) {
|
|
314
|
+
merged.tx += acc.tx;
|
|
315
|
+
merged.ty += acc.ty;
|
|
316
|
+
merged.tz += acc.tz;
|
|
317
|
+
merged.rx += acc.rx;
|
|
318
|
+
merged.ry += acc.ry;
|
|
319
|
+
merged.rz += acc.rz;
|
|
320
|
+
}
|
|
321
|
+
this.deviceAccumulators.clear();
|
|
322
|
+
this.accDirty = false;
|
|
323
|
+
const data = {
|
|
324
|
+
translation: { x: merged.tx, y: merged.ty, z: merged.tz },
|
|
325
|
+
rotation: { x: merged.rx, y: merged.ry, z: merged.rz },
|
|
326
|
+
timestamp: performance.now() * 1e3
|
|
327
|
+
};
|
|
328
|
+
const { spatial, actions } = this.applyGlobalTransforms(data);
|
|
329
|
+
if (spatial) this.emit("spatialData", spatial);
|
|
330
|
+
if (actions) this.emit("actionValues", actions);
|
|
331
|
+
}
|
|
332
|
+
/** Per-device transforms: flip, sensitivity, dead zone, dominant, axis remap */
|
|
333
|
+
processPerDevice(raw, deviceId) {
|
|
334
|
+
const cfg = resolveDeviceConfig(this._config, deviceId);
|
|
352
335
|
let data = raw;
|
|
353
336
|
if (cfg.deadZone > 0) data = applyDeadZone(data, cfg.deadZone);
|
|
354
337
|
if (cfg.dominant) data = applyDominant(data);
|
|
355
338
|
data = applyFlip(data, cfg.flip);
|
|
356
339
|
data = applyAxisRemap(data, cfg.axisRemap);
|
|
357
340
|
data = applySensitivity(data, cfg.sensitivity);
|
|
341
|
+
return data;
|
|
342
|
+
}
|
|
343
|
+
/** Global transforms applied after per-device merge: locks + action map */
|
|
344
|
+
applyGlobalTransforms(data) {
|
|
345
|
+
const cfg = this._config;
|
|
358
346
|
if (cfg.lockPosition) {
|
|
359
347
|
data = { ...data, translation: { x: 0, y: 0, z: 0 } };
|
|
360
348
|
}
|
|
361
349
|
if (cfg.lockRotation) {
|
|
362
350
|
data = { ...data, rotation: { x: 0, y: 0, z: 0 } };
|
|
363
351
|
}
|
|
364
|
-
const actions = applyActionMap(data, cfg.actionMap);
|
|
365
|
-
const spatial = actionValuesToSpatialData(actions, data.timestamp);
|
|
352
|
+
const actions = chunkLDSDVYCV_cjs.applyActionMap(data, cfg.actionMap);
|
|
353
|
+
const spatial = chunkLDSDVYCV_cjs.actionValuesToSpatialData(actions, data.timestamp);
|
|
366
354
|
return { spatial, actions };
|
|
367
355
|
}
|
|
368
356
|
};
|
|
369
357
|
|
|
370
|
-
exports
|
|
358
|
+
Object.defineProperty(exports, "DEFAULT_ACTION_MAP", {
|
|
359
|
+
enumerable: true,
|
|
360
|
+
get: function () { return chunkLDSDVYCV_cjs.DEFAULT_ACTION_MAP; }
|
|
361
|
+
});
|
|
362
|
+
Object.defineProperty(exports, "actionValuesToSpatialData", {
|
|
363
|
+
enumerable: true,
|
|
364
|
+
get: function () { return chunkLDSDVYCV_cjs.actionValuesToSpatialData; }
|
|
365
|
+
});
|
|
366
|
+
Object.defineProperty(exports, "applyActionMap", {
|
|
367
|
+
enumerable: true,
|
|
368
|
+
get: function () { return chunkLDSDVYCV_cjs.applyActionMap; }
|
|
369
|
+
});
|
|
370
|
+
Object.defineProperty(exports, "swapActions", {
|
|
371
|
+
enumerable: true,
|
|
372
|
+
get: function () { return chunkLDSDVYCV_cjs.swapActions; }
|
|
373
|
+
});
|
|
371
374
|
exports.DEFAULT_AXIS_MAP = DEFAULT_AXIS_MAP;
|
|
372
375
|
exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
|
|
373
376
|
exports.InputManager = InputManager;
|
|
374
|
-
exports.actionValuesToSpatialData = actionValuesToSpatialData;
|
|
375
|
-
exports.applyActionMap = applyActionMap;
|
|
376
377
|
exports.applyAxisRemap = applyAxisRemap;
|
|
377
378
|
exports.applyDeadZone = applyDeadZone;
|
|
378
379
|
exports.applyDominant = applyDominant;
|
|
@@ -382,6 +383,5 @@ exports.loadSettings = loadSettings;
|
|
|
382
383
|
exports.mergeConfig = mergeConfig;
|
|
383
384
|
exports.resolveDeviceConfig = resolveDeviceConfig;
|
|
384
385
|
exports.saveSettings = saveSettings;
|
|
385
|
-
exports.swapActions = swapActions;
|
|
386
386
|
//# sourceMappingURL=index.cjs.map
|
|
387
387
|
//# sourceMappingURL=index.cjs.map
|
package/dist/utils/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/action-map.ts","../../src/utils/config.ts","../../src/utils/persistence.ts","../../src/utils/transforms.ts","../../src/utils/input-manager.ts"],"names":["TypedEmitter"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { SpatialData } from \"../core/types.js\";\n\n/** Input axis identifier */\nexport type InputAxis = \"tx\" | \"ty\" | \"tz\" | \"rx\" | \"ry\" | \"rz\";\n\n/** A single action binding — maps one input axis to a named output */\nexport interface ActionBinding {\n /** Which input axis drives this action */\n source: InputAxis;\n /** Scale multiplier (default: 1) */\n scale?: number;\n /** Invert the value (default: false) */\n invert?: boolean;\n}\n\n/**\n * ActionMap defines how raw 6DOF axes map to named output actions.\n *\n * Client apps declare the actions they support and how device axes\n * feed into them. Users can reassign axes via the settings UI.\n *\n * Default: 6 actions matching the 6 input axes (passthrough).\n */\nexport type ActionMap = Record<string, ActionBinding>;\n\n/** Default passthrough — each axis maps to itself */\nexport const DEFAULT_ACTION_MAP: ActionMap = {\n tx: { source: \"tx\" },\n ty: { source: \"ty\" },\n tz: { source: \"tz\" },\n rx: { source: \"rx\" },\n ry: { source: \"ry\" },\n rz: { source: \"rz\" },\n};\n\n/** Result of applying an ActionMap to spatial data */\nexport type ActionValues = Record<string, number>;\n\n/** Read a raw axis value from SpatialData */\nfunction readAxis(data: SpatialData, axis: InputAxis): number {\n switch (axis) {\n case \"tx\": return data.translation.x;\n case \"ty\": return data.translation.y;\n case \"tz\": return data.translation.z;\n case \"rx\": return data.rotation.x;\n case \"ry\": return data.rotation.y;\n case \"rz\": return data.rotation.z;\n }\n}\n\n/** Apply an ActionMap to SpatialData, producing named action values */\nexport function applyActionMap(data: SpatialData, map: ActionMap): ActionValues {\n const result: ActionValues = {};\n for (const [action, binding] of Object.entries(map)) {\n let value = readAxis(data, binding.source);\n if (binding.invert) value = -value;\n value *= binding.scale ?? 1;\n result[action] = value;\n }\n return result;\n}\n\n/**\n * Convert ActionValues back to SpatialData.\n * Only populates tx/ty/tz/rx/ry/rz keys if they exist as actions.\n */\nexport function actionValuesToSpatialData(values: ActionValues, timestamp: number): SpatialData {\n return {\n translation: {\n x: values.tx ?? 0,\n y: values.ty ?? 0,\n z: values.tz ?? 0,\n },\n rotation: {\n x: values.rx ?? 0,\n y: values.ry ?? 0,\n z: values.rz ?? 0,\n },\n timestamp,\n };\n}\n\n/** Swap two action bindings */\nexport function swapActions(map: ActionMap, actionA: string, actionB: string): ActionMap {\n const result = { ...map };\n const a = result[actionA];\n const b = result[actionB];\n if (a && b) {\n result[actionA] = b;\n result[actionB] = a;\n }\n return result;\n}\n","import type { FlipConfig, SensitivityConfig, AxisMap } from \"./transforms.js\";\nimport { DEFAULT_ACTION_MAP, type ActionMap } from \"./action-map.js\";\n\n/** Per-device transform overrides. Any field left undefined inherits from global defaults. */\nexport interface DeviceConfig {\n sensitivity?: Partial<SensitivityConfig>;\n flip?: Partial<FlipConfig>;\n deadZone?: number;\n dominant?: boolean;\n axisRemap?: Partial<AxisMap>;\n actionMap?: ActionMap;\n lockPosition?: boolean;\n lockRotation?: boolean;\n}\n\nexport interface InputConfig {\n /** Global defaults applied to all devices */\n sensitivity: SensitivityConfig;\n flip: FlipConfig;\n deadZone: number;\n dominant: boolean;\n axisRemap: AxisMap;\n lockPosition: boolean;\n lockRotation: boolean;\n\n /** Action map — maps input axes to named output actions. Default: passthrough. */\n actionMap: ActionMap;\n\n /**\n * Per-device overrides, keyed by device ID (e.g., \"spacemouse-c635\")\n * or device family pattern (e.g., \"spacemouse-*\", \"hid-054c-*\").\n * Values override global defaults for matching devices.\n */\n devices: Record<string, DeviceConfig>;\n}\n\nexport const DEFAULT_CONFIG: InputConfig = {\n sensitivity: { translation: 0.001, rotation: 0.001 },\n flip: { tx: false, ty: true, tz: true, rx: false, ry: true, rz: true },\n deadZone: 0,\n dominant: false,\n axisRemap: { tx: \"x\", ty: \"y\", tz: \"z\", rx: \"x\", ry: \"y\", rz: \"z\" },\n lockPosition: false,\n lockRotation: false,\n actionMap: { ...DEFAULT_ACTION_MAP },\n devices: {},\n};\n\nexport function mergeConfig(base: InputConfig, partial: Partial<InputConfig>): InputConfig {\n const merged = {\n ...base,\n ...partial,\n sensitivity: { ...base.sensitivity, ...partial.sensitivity },\n flip: { ...base.flip, ...partial.flip },\n axisRemap: { ...base.axisRemap, ...partial.axisRemap },\n actionMap: partial.actionMap ? { ...base.actionMap, ...partial.actionMap } : { ...base.actionMap },\n devices: { ...base.devices },\n };\n\n // Merge per-device configs\n if (partial.devices) {\n for (const [key, devCfg] of Object.entries(partial.devices)) {\n merged.devices[key] = mergeDeviceConfig(merged.devices[key], devCfg);\n }\n }\n\n return merged;\n}\n\nexport function mergeDeviceConfig(base: DeviceConfig | undefined, partial: DeviceConfig): DeviceConfig {\n if (!base) return partial;\n return {\n ...base,\n ...partial,\n sensitivity: partial.sensitivity ? { ...base.sensitivity, ...partial.sensitivity } : base.sensitivity,\n flip: partial.flip ? { ...base.flip, ...partial.flip } : base.flip,\n axisRemap: partial.axisRemap ? { ...base.axisRemap, ...partial.axisRemap } : base.axisRemap,\n };\n}\n\n/** Resolve the effective config for a specific device by merging global + device overrides */\nexport function resolveDeviceConfig(config: InputConfig, deviceId: string): InputConfig {\n // Find matching device config: exact match first, then pattern match\n let deviceOverride: DeviceConfig | undefined;\n\n if (config.devices[deviceId]) {\n deviceOverride = config.devices[deviceId];\n } else {\n // Try pattern match (e.g., \"spacemouse-*\" matches \"spacemouse-c635\")\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 sensitivity: { ...config.sensitivity, ...deviceOverride.sensitivity },\n flip: { ...config.flip, ...deviceOverride.flip },\n deadZone: deviceOverride.deadZone ?? config.deadZone,\n dominant: deviceOverride.dominant ?? config.dominant,\n axisRemap: { ...config.axisRemap, ...deviceOverride.axisRemap },\n actionMap: deviceOverride.actionMap ? { ...config.actionMap, ...deviceOverride.actionMap } : config.actionMap,\n lockPosition: deviceOverride.lockPosition ?? config.lockPosition,\n lockRotation: deviceOverride.lockRotation ?? config.lockRotation,\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 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 type { SpatialData, Vec3 } from \"../core/types.js\";\n\nexport interface FlipConfig {\n tx: boolean;\n ty: boolean;\n tz: boolean;\n rx: boolean;\n ry: boolean;\n rz: boolean;\n}\n\nexport interface SensitivityConfig {\n translation: number;\n rotation: number;\n}\n\n/** Maps each input axis to an output axis. E.g., { tx: \"tz\", tz: \"tx\" } swaps X and Z translation. */\nexport type AxisMap = {\n tx: keyof Vec3;\n ty: keyof Vec3;\n tz: keyof Vec3;\n rx: keyof Vec3;\n ry: keyof Vec3;\n rz: keyof Vec3;\n};\n\nexport const DEFAULT_AXIS_MAP: AxisMap = {\n tx: \"x\", ty: \"y\", tz: \"z\",\n rx: \"x\", ry: \"y\", rz: \"z\",\n};\n\nexport function applyFlip(data: SpatialData, flip: FlipConfig): SpatialData {\n return {\n ...data,\n translation: {\n x: flip.tx ? -data.translation.x : data.translation.x,\n y: flip.ty ? -data.translation.y : data.translation.y,\n z: flip.tz ? -data.translation.z : data.translation.z,\n },\n rotation: {\n x: flip.rx ? -data.rotation.x : data.rotation.x,\n y: flip.ry ? -data.rotation.y : data.rotation.y,\n z: flip.rz ? -data.rotation.z : data.rotation.z,\n },\n };\n}\n\nexport function applySensitivity(data: SpatialData, sens: SensitivityConfig): SpatialData {\n return {\n ...data,\n translation: {\n x: data.translation.x * sens.translation,\n y: data.translation.y * sens.translation,\n z: data.translation.z * sens.translation,\n },\n rotation: {\n x: data.rotation.x * sens.rotation,\n y: data.rotation.y * sens.rotation,\n z: data.rotation.z * sens.rotation,\n },\n };\n}\n\nexport function applyDominant(data: SpatialData): SpatialData {\n const axes = [\n { group: \"t\" as const, key: \"x\" as const, v: Math.abs(data.translation.x) },\n { group: \"t\" as const, key: \"y\" as const, v: Math.abs(data.translation.y) },\n { group: \"t\" as const, key: \"z\" as const, v: Math.abs(data.translation.z) },\n { group: \"r\" as const, key: \"x\" as const, v: Math.abs(data.rotation.x) },\n { group: \"r\" as const, key: \"y\" as const, v: Math.abs(data.rotation.y) },\n { group: \"r\" as const, key: \"z\" as const, v: Math.abs(data.rotation.z) },\n ];\n const max = axes.reduce((a, b) => (b.v > a.v ? b : a));\n\n const t: Vec3 = { x: 0, y: 0, z: 0 };\n const r: Vec3 = { x: 0, y: 0, z: 0 };\n\n if (max.group === \"t\") t[max.key] = data.translation[max.key];\n else r[max.key] = data.rotation[max.key];\n\n return { ...data, translation: t, rotation: r };\n}\n\nexport function applyDeadZone(data: SpatialData, threshold: number): SpatialData {\n const dz = (v: number) => (Math.abs(v) < threshold ? 0 : v);\n return {\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\nexport function applyAxisRemap(data: SpatialData, map: AxisMap): SpatialData {\n return {\n ...data,\n translation: {\n x: 0, y: 0, z: 0,\n [map.tx]: data.translation.x,\n [map.ty]: data.translation.y,\n [map.tz]: data.translation.z,\n } as Vec3,\n rotation: {\n x: 0, y: 0, z: 0,\n [map.rx]: data.rotation.x,\n [map.ry]: data.rotation.y,\n [map.rz]: data.rotation.z,\n } as Vec3,\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, type StorageAdapter } from \"./persistence.js\";\nimport {\n applyFlip,\n applySensitivity,\n applyDominant,\n applyDeadZone,\n applyAxisRemap,\n} from \"./transforms.js\";\nimport { applyActionMap, actionValuesToSpatialData, type ActionValues } from \"./action-map.js\";\n\nexport interface InputManagerEvents {\n /** Processed spatial data (after all transforms + action map) */\n spatialData: (data: SpatialData) => void;\n /** Named action values from the action map */\n actionValues: (values: ActionValues) => void;\n /** Raw spatial data (before transforms) */\n rawSpatialData: (data: SpatialData) => void;\n /** Button event (pass-through from connection) */\n buttonEvent: (data: ButtonEvent) => void;\n /** Connection state changed */\n stateChange: (state: ConnectionState, protocol: TransportProtocol) => void;\n /** Device connected/disconnected */\n deviceStatus: (event: \"connected\" | \"disconnected\", device: DeviceInfo) => void;\n /** Configuration changed */\n configChange: (config: InputConfig) => void;\n}\n\n/** A connected device paired with its resolved configuration */\nexport interface DeviceWithConfig {\n device: DeviceInfo;\n config: DeviceConfig;\n}\n\n/**\n * Unified device service that wraps one or more SatMouseConnections\n * and provides a single processed event stream.\n *\n * Applies a configurable transform pipeline per-device:\n * deadZone → dominant → flip → axisRemap → sensitivity → lock\n *\n * Per-device overrides are resolved from InputConfig.devices using\n * device ID matching (exact or pattern with wildcard \"*\").\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 _config: InputConfig;\n\n get config(): InputConfig {\n return this._config;\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 }\n\n /** Add a connection to the managed set */\n addConnection(connection: SatMouseConnection): void {\n this.connections.push(connection);\n this.wireConnection(connection);\n }\n\n /** Remove a connection */\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 /** Connect all managed connections */\n async connect(): Promise<void> {\n await Promise.all(this.connections.map((c) => c.connect()));\n }\n\n /** Disconnect all managed connections */\n disconnect(): void {\n for (const c of this.connections) c.disconnect();\n }\n\n /** Fetch device info from all connections */\n async fetchDeviceInfo(): Promise<DeviceInfo[]> {\n const results = await Promise.all(this.connections.map((c) => c.fetchDeviceInfo()));\n const devices = results.flat();\n // Track known devices\n for (const d of devices) this.knownDevices.set(d.id, d);\n return devices;\n }\n\n /** Get all known connected devices paired with their resolved config */\n getDevicesWithConfig(): DeviceWithConfig[] {\n return Array.from(this.knownDevices.values()).map((device) => ({\n device,\n config: this.getDeviceConfig(device.id),\n }));\n }\n\n /** Get the resolved per-device config (global defaults + device overrides) */\n getDeviceConfig(deviceId: string): DeviceConfig {\n const resolved = resolveDeviceConfig(this._config, deviceId);\n return {\n sensitivity: resolved.sensitivity,\n flip: resolved.flip,\n deadZone: resolved.deadZone,\n dominant: resolved.dominant,\n axisRemap: resolved.axisRemap,\n actionMap: resolved.actionMap,\n lockPosition: resolved.lockPosition,\n lockRotation: resolved.lockRotation,\n };\n }\n\n /** Update global configuration. Persists by default. */\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 /** Update configuration for a specific device. Persists by default. */\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 /** Register a callback for processed spatial data. Returns unsubscribe function. */\n onSpatialData(callback: (data: SpatialData) => void): () => void {\n this.on(\"spatialData\", callback);\n return () => this.off(\"spatialData\", callback);\n }\n\n /** Register a callback for button events. Returns unsubscribe function. */\n onButtonEvent(callback: (data: ButtonEvent) => void): () => void {\n this.on(\"buttonEvent\", callback);\n return () => this.off(\"buttonEvent\", callback);\n }\n\n /** Register a callback for action values. Returns unsubscribe function. */\n onActionValues(callback: (values: ActionValues) => void): () => void {\n this.on(\"actionValues\", callback);\n return () => this.off(\"actionValues\", callback);\n }\n\n private wireConnection(connection: SatMouseConnection): void {\n connection.on(\"spatialData\", (raw) => {\n this.emit(\"rawSpatialData\", raw);\n const { spatial, actions } = this.processSpatialData(raw);\n if (spatial) this.emit(\"spatialData\", spatial);\n if (actions) this.emit(\"actionValues\", actions);\n });\n\n connection.on(\"buttonEvent\", (event) => this.emit(\"buttonEvent\", event));\n connection.on(\"stateChange\", (state, proto) => this.emit(\"stateChange\", state, proto));\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 processSpatialData(raw: SpatialData): { spatial: SpatialData | null; actions: ActionValues | null } {\n const cfg = this._config;\n let data = raw;\n\n // Transform pipeline\n if (cfg.deadZone > 0) data = applyDeadZone(data, cfg.deadZone);\n if (cfg.dominant) data = applyDominant(data);\n data = applyFlip(data, cfg.flip);\n data = applyAxisRemap(data, cfg.axisRemap);\n data = applySensitivity(data, cfg.sensitivity);\n\n if (cfg.lockPosition) {\n data = { ...data, translation: { x: 0, y: 0, z: 0 } };\n }\n if (cfg.lockRotation) {\n data = { ...data, rotation: { x: 0, y: 0, z: 0 } };\n }\n\n // Apply action map: remap transformed axes to named actions\n const actions = applyActionMap(data, cfg.actionMap);\n\n // Convert action values back to spatial data for consumers that\n // expect the standard tx/ty/tz/rx/ry/rz format\n const spatial = actionValuesToSpatialData(actions, data.timestamp);\n\n return { spatial, actions };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/config.ts","../../src/utils/persistence.ts","../../src/utils/transforms.ts","../../src/utils/input-manager.ts"],"names":["DEFAULT_ACTION_MAP","TypedEmitter","applyActionMap","actionValuesToSpatialData"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { FlipConfig, SensitivityConfig, AxisMap } from \"./transforms.js\";\nimport { DEFAULT_ACTION_MAP, type ActionMap } from \"./action-map.js\";\n\n/** Per-device transform overrides. Any field left undefined inherits from global defaults. */\nexport interface DeviceConfig {\n sensitivity?: Partial<SensitivityConfig>;\n flip?: Partial<FlipConfig>;\n deadZone?: number;\n dominant?: boolean;\n axisRemap?: Partial<AxisMap>;\n actionMap?: ActionMap;\n lockPosition?: boolean;\n lockRotation?: boolean;\n}\n\nexport interface InputConfig {\n /** Global defaults applied to all devices */\n sensitivity: SensitivityConfig;\n flip: FlipConfig;\n deadZone: number;\n dominant: boolean;\n axisRemap: AxisMap;\n lockPosition: boolean;\n lockRotation: boolean;\n\n /** Action map — maps input axes to named output actions. Default: passthrough. */\n actionMap: ActionMap;\n\n /**\n * Per-device overrides, keyed by device ID (e.g., \"spacemouse-c635\")\n * or device family pattern (e.g., \"spacemouse-*\", \"hid-054c-*\").\n * Values override global defaults for matching devices.\n */\n devices: Record<string, DeviceConfig>;\n}\n\nexport const DEFAULT_CONFIG: InputConfig = {\n sensitivity: { translation: 0.001, rotation: 0.001 },\n flip: { tx: false, ty: false, tz: false, rx: false, ry: false, rz: false },\n deadZone: 0,\n dominant: false,\n axisRemap: { tx: \"x\", ty: \"y\", tz: \"z\", rx: \"x\", ry: \"y\", rz: \"z\" },\n lockPosition: false,\n lockRotation: false,\n actionMap: { ...DEFAULT_ACTION_MAP },\n devices: {\n // SpaceMouse Z-up → Three.js Y-up axis correction\n \"cnx-*\": { flip: { ty: true, tz: true, ry: true, rz: true } },\n },\n};\n\nexport function mergeConfig(base: InputConfig, partial: Partial<InputConfig>): InputConfig {\n const merged = {\n ...base,\n ...partial,\n sensitivity: { ...base.sensitivity, ...partial.sensitivity },\n flip: { ...base.flip, ...partial.flip },\n axisRemap: { ...base.axisRemap, ...partial.axisRemap },\n actionMap: partial.actionMap ? { ...base.actionMap, ...partial.actionMap } : { ...base.actionMap },\n devices: { ...base.devices },\n };\n\n // Merge per-device configs\n if (partial.devices) {\n for (const [key, devCfg] of Object.entries(partial.devices)) {\n merged.devices[key] = mergeDeviceConfig(merged.devices[key], devCfg);\n }\n }\n\n return merged;\n}\n\nexport function mergeDeviceConfig(base: DeviceConfig | undefined, partial: DeviceConfig): DeviceConfig {\n if (!base) return partial;\n return {\n ...base,\n ...partial,\n sensitivity: partial.sensitivity ? { ...base.sensitivity, ...partial.sensitivity } : base.sensitivity,\n flip: partial.flip ? { ...base.flip, ...partial.flip } : base.flip,\n axisRemap: partial.axisRemap ? { ...base.axisRemap, ...partial.axisRemap } : base.axisRemap,\n };\n}\n\n/** Resolve the effective config for a specific device by merging global + device overrides */\nexport function resolveDeviceConfig(config: InputConfig, deviceId: string): InputConfig {\n // Find matching device config: exact match first, then pattern match\n let deviceOverride: DeviceConfig | undefined;\n\n if (config.devices[deviceId]) {\n deviceOverride = config.devices[deviceId];\n } else {\n // Try pattern match (e.g., \"spacemouse-*\" matches \"spacemouse-c635\")\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 sensitivity: { ...config.sensitivity, ...deviceOverride.sensitivity },\n flip: { ...config.flip, ...deviceOverride.flip },\n deadZone: deviceOverride.deadZone ?? config.deadZone,\n dominant: deviceOverride.dominant ?? config.dominant,\n axisRemap: { ...config.axisRemap, ...deviceOverride.axisRemap },\n actionMap: deviceOverride.actionMap ? { ...config.actionMap, ...deviceOverride.actionMap } : config.actionMap,\n lockPosition: deviceOverride.lockPosition ?? config.lockPosition,\n lockRotation: deviceOverride.lockRotation ?? config.lockRotation,\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 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 type { SpatialData, Vec3 } from \"../core/types.js\";\n\nexport interface FlipConfig {\n tx: boolean;\n ty: boolean;\n tz: boolean;\n rx: boolean;\n ry: boolean;\n rz: boolean;\n}\n\nexport interface SensitivityConfig {\n translation: number;\n rotation: number;\n}\n\n/** Maps each input axis to an output axis. E.g., { tx: \"tz\", tz: \"tx\" } swaps X and Z translation. */\nexport type AxisMap = {\n tx: keyof Vec3;\n ty: keyof Vec3;\n tz: keyof Vec3;\n rx: keyof Vec3;\n ry: keyof Vec3;\n rz: keyof Vec3;\n};\n\nexport const DEFAULT_AXIS_MAP: AxisMap = {\n tx: \"x\", ty: \"y\", tz: \"z\",\n rx: \"x\", ry: \"y\", rz: \"z\",\n};\n\nexport function applyFlip(data: SpatialData, flip: FlipConfig): SpatialData {\n return {\n ...data,\n translation: {\n x: flip.tx ? -data.translation.x : data.translation.x,\n y: flip.ty ? -data.translation.y : data.translation.y,\n z: flip.tz ? -data.translation.z : data.translation.z,\n },\n rotation: {\n x: flip.rx ? -data.rotation.x : data.rotation.x,\n y: flip.ry ? -data.rotation.y : data.rotation.y,\n z: flip.rz ? -data.rotation.z : data.rotation.z,\n },\n };\n}\n\nexport function applySensitivity(data: SpatialData, sens: SensitivityConfig): SpatialData {\n return {\n ...data,\n translation: {\n x: data.translation.x * sens.translation,\n y: data.translation.y * sens.translation,\n z: data.translation.z * sens.translation,\n },\n rotation: {\n x: data.rotation.x * sens.rotation,\n y: data.rotation.y * sens.rotation,\n z: data.rotation.z * sens.rotation,\n },\n };\n}\n\nexport function applyDominant(data: SpatialData): SpatialData {\n const axes = [\n { group: \"t\" as const, key: \"x\" as const, v: Math.abs(data.translation.x) },\n { group: \"t\" as const, key: \"y\" as const, v: Math.abs(data.translation.y) },\n { group: \"t\" as const, key: \"z\" as const, v: Math.abs(data.translation.z) },\n { group: \"r\" as const, key: \"x\" as const, v: Math.abs(data.rotation.x) },\n { group: \"r\" as const, key: \"y\" as const, v: Math.abs(data.rotation.y) },\n { group: \"r\" as const, key: \"z\" as const, v: Math.abs(data.rotation.z) },\n ];\n const max = axes.reduce((a, b) => (b.v > a.v ? b : a));\n\n const t: Vec3 = { x: 0, y: 0, z: 0 };\n const r: Vec3 = { x: 0, y: 0, z: 0 };\n\n if (max.group === \"t\") t[max.key] = data.translation[max.key];\n else r[max.key] = data.rotation[max.key];\n\n return { ...data, translation: t, rotation: r };\n}\n\nexport function applyDeadZone(data: SpatialData, threshold: number): SpatialData {\n const dz = (v: number) => (Math.abs(v) < threshold ? 0 : v);\n return {\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\nexport function applyAxisRemap(data: SpatialData, map: AxisMap): SpatialData {\n return {\n ...data,\n translation: {\n x: 0, y: 0, z: 0,\n [map.tx]: data.translation.x,\n [map.ty]: data.translation.y,\n [map.tz]: data.translation.z,\n } as Vec3,\n rotation: {\n x: 0, y: 0, z: 0,\n [map.rx]: data.rotation.x,\n [map.ry]: data.rotation.y,\n [map.rz]: data.rotation.z,\n } as Vec3,\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, type StorageAdapter } from \"./persistence.js\";\nimport {\n applyFlip,\n applySensitivity,\n applyDominant,\n applyDeadZone,\n applyAxisRemap,\n} from \"./transforms.js\";\nimport { applyActionMap, actionValuesToSpatialData, type ActionValues } from \"./action-map.js\";\n\nexport interface InputManagerEvents {\n /** Processed spatial data (after all transforms + action map) */\n spatialData: (data: SpatialData) => void;\n /** Named action values from the action map */\n actionValues: (values: ActionValues) => void;\n /** Raw spatial data (before transforms) */\n rawSpatialData: (data: SpatialData) => void;\n /** Button event (pass-through from connection) */\n buttonEvent: (data: ButtonEvent) => void;\n /** Connection state changed */\n stateChange: (state: ConnectionState, protocol: TransportProtocol) => void;\n /** Device connected/disconnected */\n deviceStatus: (event: \"connected\" | \"disconnected\", device: DeviceInfo) => void;\n /** Configuration changed */\n configChange: (config: InputConfig) => void;\n}\n\n/** A connected device paired with its resolved configuration */\nexport interface DeviceWithConfig {\n device: DeviceInfo;\n config: DeviceConfig;\n}\n\n/**\n * Unified device service that wraps one or more SatMouseConnections\n * and provides a single processed event stream.\n *\n * Applies a configurable transform pipeline per-device:\n * deadZone → dominant → flip → axisRemap → sensitivity → lock\n *\n * Per-device overrides are resolved from InputConfig.devices using\n * device ID matching (exact or pattern with wildcard \"*\").\n */\nexport class InputManager extends TypedEmitter<InputManagerEvents> {\n private connections: SatMouseConnection[] = [];\n private storage?: StorageAdapter;\n private knownDevices = new Map<string, DeviceInfo>();\n\n // Per-device accumulators: latest value from each device per frame tick\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\n get config(): InputConfig {\n return this._config;\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\n // Flush accumulated inputs at ~60Hz\n this.flushTimer = setInterval(() => this.flushAccumulator(), 16);\n }\n\n /** Add a connection to the managed set */\n addConnection(connection: SatMouseConnection): void {\n this.connections.push(connection);\n this.wireConnection(connection);\n }\n\n /** Remove a connection */\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 /** Connect all managed connections */\n async connect(): Promise<void> {\n await Promise.all(this.connections.map((c) => c.connect()));\n }\n\n /** Disconnect all managed connections */\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 /** Fetch device info from all connections */\n async fetchDeviceInfo(): Promise<DeviceInfo[]> {\n const results = await Promise.all(this.connections.map((c) => c.fetchDeviceInfo()));\n const devices = results.flat();\n // Track known devices\n for (const d of devices) this.knownDevices.set(d.id, d);\n return devices;\n }\n\n /** Get all known connected devices paired with their resolved config */\n getDevicesWithConfig(): DeviceWithConfig[] {\n return Array.from(this.knownDevices.values()).map((device) => ({\n device,\n config: this.getDeviceConfig(device.id),\n }));\n }\n\n /** Get the resolved per-device config (global defaults + device overrides) */\n getDeviceConfig(deviceId: string): DeviceConfig {\n const resolved = resolveDeviceConfig(this._config, deviceId);\n return {\n sensitivity: resolved.sensitivity,\n flip: resolved.flip,\n deadZone: resolved.deadZone,\n dominant: resolved.dominant,\n axisRemap: resolved.axisRemap,\n actionMap: resolved.actionMap,\n lockPosition: resolved.lockPosition,\n lockRotation: resolved.lockRotation,\n };\n }\n\n /** Update global configuration. Persists by default. */\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 /** Update configuration for a specific device. Persists by default. */\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 /** Register a callback for processed spatial data. Returns unsubscribe function. */\n onSpatialData(callback: (data: SpatialData) => void): () => void {\n this.on(\"spatialData\", callback);\n return () => this.off(\"spatialData\", callback);\n }\n\n /** Register a callback for button events. Returns unsubscribe function. */\n onButtonEvent(callback: (data: ButtonEvent) => void): () => void {\n this.on(\"buttonEvent\", callback);\n return () => this.off(\"buttonEvent\", callback);\n }\n\n /** Register a callback for action values. Returns unsubscribe function. */\n onActionValues(callback: (values: ActionValues) => void): () => void {\n this.on(\"actionValues\", callback);\n return () => this.off(\"actionValues\", 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\n // Apply per-device transforms BEFORE accumulating\n const processed = this.processPerDevice(raw, id);\n\n // Store latest per-device processed values\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) => this.emit(\"stateChange\", state, proto));\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 // Merge all device accumulators: sum contributions from each device\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 // Reset all device accumulators\n this.deviceAccumulators.clear();\n this.accDirty = false;\n\n const 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 // Apply global transforms (action map, locks)\n const { spatial, actions } = this.applyGlobalTransforms(data);\n if (spatial) this.emit(\"spatialData\", spatial);\n if (actions) this.emit(\"actionValues\", actions);\n }\n\n /** Per-device transforms: flip, sensitivity, dead zone, dominant, axis remap */\n private processPerDevice(raw: SpatialData, deviceId: string): SpatialData {\n const cfg = resolveDeviceConfig(this._config, deviceId);\n let data = raw;\n\n if (cfg.deadZone > 0) data = applyDeadZone(data, cfg.deadZone);\n if (cfg.dominant) data = applyDominant(data);\n data = applyFlip(data, cfg.flip);\n data = applyAxisRemap(data, cfg.axisRemap);\n data = applySensitivity(data, cfg.sensitivity);\n\n return data;\n }\n\n /** Global transforms applied after per-device merge: locks + action map */\n private applyGlobalTransforms(data: SpatialData): { spatial: SpatialData | null; actions: ActionValues | null } {\n const cfg = this._config;\n\n if (cfg.lockPosition) {\n data = { ...data, translation: { x: 0, y: 0, z: 0 } };\n }\n if (cfg.lockRotation) {\n data = { ...data, rotation: { x: 0, y: 0, z: 0 } };\n }\n\n const actions = applyActionMap(data, cfg.actionMap);\n const spatial = actionValuesToSpatialData(actions, data.timestamp);\n\n return { spatial, actions };\n }\n}\n"]}
|
package/dist/utils/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { V as Vec3, 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 { V as Vec3, S as SpatialData, D as DeviceInfo, e as TypedEmitter, B as ButtonEvent, a as ConnectionState, d as TransportProtocol, b as SatMouseConnection } from '../connection-5KQFvHoJ.cjs';
|
|
2
2
|
|
|
3
3
|
interface FlipConfig {
|
|
4
4
|
tx: boolean;
|
|
@@ -138,6 +138,9 @@ declare class InputManager extends TypedEmitter<InputManagerEvents> {
|
|
|
138
138
|
private connections;
|
|
139
139
|
private storage?;
|
|
140
140
|
private knownDevices;
|
|
141
|
+
private deviceAccumulators;
|
|
142
|
+
private accDirty;
|
|
143
|
+
private flushTimer;
|
|
141
144
|
private _config;
|
|
142
145
|
get config(): InputConfig;
|
|
143
146
|
constructor(config?: Partial<InputConfig>, storage?: StorageAdapter);
|
|
@@ -166,7 +169,11 @@ declare class InputManager extends TypedEmitter<InputManagerEvents> {
|
|
|
166
169
|
/** Register a callback for action values. Returns unsubscribe function. */
|
|
167
170
|
onActionValues(callback: (values: ActionValues) => void): () => void;
|
|
168
171
|
private wireConnection;
|
|
169
|
-
private
|
|
172
|
+
private flushAccumulator;
|
|
173
|
+
/** Per-device transforms: flip, sensitivity, dead zone, dominant, axis remap */
|
|
174
|
+
private processPerDevice;
|
|
175
|
+
/** Global transforms applied after per-device merge: locks + action map */
|
|
176
|
+
private applyGlobalTransforms;
|
|
170
177
|
}
|
|
171
178
|
|
|
172
179
|
export { type ActionBinding, type ActionMap, type ActionValues, type AxisMap, DEFAULT_ACTION_MAP, DEFAULT_AXIS_MAP, DEFAULT_CONFIG, type DeviceConfig, type DeviceWithConfig, type FlipConfig, type InputAxis, type InputConfig, InputManager, type InputManagerEvents, type SensitivityConfig, type StorageAdapter, actionValuesToSpatialData, applyActionMap, applyAxisRemap, applyDeadZone, applyDominant, applyFlip, applySensitivity, loadSettings, mergeConfig, resolveDeviceConfig, saveSettings, swapActions };
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { V as Vec3, 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 { V as Vec3, S as SpatialData, D as DeviceInfo, e as TypedEmitter, B as ButtonEvent, a as ConnectionState, d as TransportProtocol, b as SatMouseConnection } from '../connection-5KQFvHoJ.js';
|
|
2
2
|
|
|
3
3
|
interface FlipConfig {
|
|
4
4
|
tx: boolean;
|
|
@@ -138,6 +138,9 @@ declare class InputManager extends TypedEmitter<InputManagerEvents> {
|
|
|
138
138
|
private connections;
|
|
139
139
|
private storage?;
|
|
140
140
|
private knownDevices;
|
|
141
|
+
private deviceAccumulators;
|
|
142
|
+
private accDirty;
|
|
143
|
+
private flushTimer;
|
|
141
144
|
private _config;
|
|
142
145
|
get config(): InputConfig;
|
|
143
146
|
constructor(config?: Partial<InputConfig>, storage?: StorageAdapter);
|
|
@@ -166,7 +169,11 @@ declare class InputManager extends TypedEmitter<InputManagerEvents> {
|
|
|
166
169
|
/** Register a callback for action values. Returns unsubscribe function. */
|
|
167
170
|
onActionValues(callback: (values: ActionValues) => void): () => void;
|
|
168
171
|
private wireConnection;
|
|
169
|
-
private
|
|
172
|
+
private flushAccumulator;
|
|
173
|
+
/** Per-device transforms: flip, sensitivity, dead zone, dominant, axis remap */
|
|
174
|
+
private processPerDevice;
|
|
175
|
+
/** Global transforms applied after per-device merge: locks + action map */
|
|
176
|
+
private applyGlobalTransforms;
|
|
170
177
|
}
|
|
171
178
|
|
|
172
179
|
export { type ActionBinding, type ActionMap, type ActionValues, type AxisMap, DEFAULT_ACTION_MAP, DEFAULT_AXIS_MAP, DEFAULT_CONFIG, type DeviceConfig, type DeviceWithConfig, type FlipConfig, type InputAxis, type InputConfig, InputManager, type InputManagerEvents, type SensitivityConfig, type StorageAdapter, actionValuesToSpatialData, applyActionMap, applyAxisRemap, applyDeadZone, applyDominant, applyFlip, applySensitivity, loadSettings, mergeConfig, resolveDeviceConfig, saveSettings, swapActions };
|
package/dist/utils/index.js
CHANGED
|
@@ -1,77 +1,21 @@
|
|
|
1
1
|
import { TypedEmitter } from '../chunk-X6NIARXW.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var DEFAULT_ACTION_MAP = {
|
|
5
|
-
tx: { source: "tx" },
|
|
6
|
-
ty: { source: "ty" },
|
|
7
|
-
tz: { source: "tz" },
|
|
8
|
-
rx: { source: "rx" },
|
|
9
|
-
ry: { source: "ry" },
|
|
10
|
-
rz: { source: "rz" }
|
|
11
|
-
};
|
|
12
|
-
function readAxis(data, axis) {
|
|
13
|
-
switch (axis) {
|
|
14
|
-
case "tx":
|
|
15
|
-
return data.translation.x;
|
|
16
|
-
case "ty":
|
|
17
|
-
return data.translation.y;
|
|
18
|
-
case "tz":
|
|
19
|
-
return data.translation.z;
|
|
20
|
-
case "rx":
|
|
21
|
-
return data.rotation.x;
|
|
22
|
-
case "ry":
|
|
23
|
-
return data.rotation.y;
|
|
24
|
-
case "rz":
|
|
25
|
-
return data.rotation.z;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
function applyActionMap(data, map) {
|
|
29
|
-
const result = {};
|
|
30
|
-
for (const [action, binding] of Object.entries(map)) {
|
|
31
|
-
let value = readAxis(data, binding.source);
|
|
32
|
-
if (binding.invert) value = -value;
|
|
33
|
-
value *= binding.scale ?? 1;
|
|
34
|
-
result[action] = value;
|
|
35
|
-
}
|
|
36
|
-
return result;
|
|
37
|
-
}
|
|
38
|
-
function actionValuesToSpatialData(values, timestamp) {
|
|
39
|
-
return {
|
|
40
|
-
translation: {
|
|
41
|
-
x: values.tx ?? 0,
|
|
42
|
-
y: values.ty ?? 0,
|
|
43
|
-
z: values.tz ?? 0
|
|
44
|
-
},
|
|
45
|
-
rotation: {
|
|
46
|
-
x: values.rx ?? 0,
|
|
47
|
-
y: values.ry ?? 0,
|
|
48
|
-
z: values.rz ?? 0
|
|
49
|
-
},
|
|
50
|
-
timestamp
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
function swapActions(map, actionA, actionB) {
|
|
54
|
-
const result = { ...map };
|
|
55
|
-
const a = result[actionA];
|
|
56
|
-
const b = result[actionB];
|
|
57
|
-
if (a && b) {
|
|
58
|
-
result[actionA] = b;
|
|
59
|
-
result[actionB] = a;
|
|
60
|
-
}
|
|
61
|
-
return result;
|
|
62
|
-
}
|
|
2
|
+
import { DEFAULT_ACTION_MAP, applyActionMap, actionValuesToSpatialData } from '../chunk-I47ZOX3M.js';
|
|
3
|
+
export { DEFAULT_ACTION_MAP, actionValuesToSpatialData, applyActionMap, swapActions } from '../chunk-I47ZOX3M.js';
|
|
63
4
|
|
|
64
5
|
// src/utils/config.ts
|
|
65
6
|
var DEFAULT_CONFIG = {
|
|
66
7
|
sensitivity: { translation: 1e-3, rotation: 1e-3 },
|
|
67
|
-
flip: { tx: false, ty:
|
|
8
|
+
flip: { tx: false, ty: false, tz: false, rx: false, ry: false, rz: false },
|
|
68
9
|
deadZone: 0,
|
|
69
10
|
dominant: false,
|
|
70
11
|
axisRemap: { tx: "x", ty: "y", tz: "z", rx: "x", ry: "y", rz: "z" },
|
|
71
12
|
lockPosition: false,
|
|
72
13
|
lockRotation: false,
|
|
73
14
|
actionMap: { ...DEFAULT_ACTION_MAP },
|
|
74
|
-
devices: {
|
|
15
|
+
devices: {
|
|
16
|
+
// SpaceMouse Z-up → Three.js Y-up axis correction
|
|
17
|
+
"cnx-*": { flip: { ty: true, tz: true, ry: true, rz: true } }
|
|
18
|
+
}
|
|
75
19
|
};
|
|
76
20
|
function mergeConfig(base, partial) {
|
|
77
21
|
const merged = {
|
|
@@ -243,6 +187,10 @@ var InputManager = class extends TypedEmitter {
|
|
|
243
187
|
connections = [];
|
|
244
188
|
storage;
|
|
245
189
|
knownDevices = /* @__PURE__ */ new Map();
|
|
190
|
+
// Per-device accumulators: latest value from each device per frame tick
|
|
191
|
+
deviceAccumulators = /* @__PURE__ */ new Map();
|
|
192
|
+
accDirty = false;
|
|
193
|
+
flushTimer = null;
|
|
246
194
|
_config;
|
|
247
195
|
get config() {
|
|
248
196
|
return this._config;
|
|
@@ -252,6 +200,7 @@ var InputManager = class extends TypedEmitter {
|
|
|
252
200
|
this.storage = storage;
|
|
253
201
|
const persisted = loadSettings(storage);
|
|
254
202
|
this._config = mergeConfig(DEFAULT_CONFIG, { ...config, ...persisted });
|
|
203
|
+
this.flushTimer = setInterval(() => this.flushAccumulator(), 16);
|
|
255
204
|
}
|
|
256
205
|
/** Add a connection to the managed set */
|
|
257
206
|
addConnection(connection) {
|
|
@@ -271,6 +220,10 @@ var InputManager = class extends TypedEmitter {
|
|
|
271
220
|
/** Disconnect all managed connections */
|
|
272
221
|
disconnect() {
|
|
273
222
|
for (const c of this.connections) c.disconnect();
|
|
223
|
+
if (this.flushTimer) {
|
|
224
|
+
clearInterval(this.flushTimer);
|
|
225
|
+
this.flushTimer = null;
|
|
226
|
+
}
|
|
274
227
|
}
|
|
275
228
|
/** Fetch device info from all connections */
|
|
276
229
|
async fetchDeviceInfo() {
|
|
@@ -333,9 +286,17 @@ var InputManager = class extends TypedEmitter {
|
|
|
333
286
|
wireConnection(connection) {
|
|
334
287
|
connection.on("spatialData", (raw) => {
|
|
335
288
|
this.emit("rawSpatialData", raw);
|
|
336
|
-
const
|
|
337
|
-
|
|
338
|
-
|
|
289
|
+
const id = raw.deviceId ?? "_default";
|
|
290
|
+
const processed = this.processPerDevice(raw, id);
|
|
291
|
+
this.deviceAccumulators.set(id, {
|
|
292
|
+
tx: processed.translation.x,
|
|
293
|
+
ty: processed.translation.y,
|
|
294
|
+
tz: processed.translation.z,
|
|
295
|
+
rx: processed.rotation.x,
|
|
296
|
+
ry: processed.rotation.y,
|
|
297
|
+
rz: processed.rotation.z
|
|
298
|
+
});
|
|
299
|
+
this.accDirty = true;
|
|
339
300
|
});
|
|
340
301
|
connection.on("buttonEvent", (event) => this.emit("buttonEvent", event));
|
|
341
302
|
connection.on("stateChange", (state, proto) => this.emit("stateChange", state, proto));
|
|
@@ -345,14 +306,42 @@ var InputManager = class extends TypedEmitter {
|
|
|
345
306
|
this.emit("deviceStatus", event, device);
|
|
346
307
|
});
|
|
347
308
|
}
|
|
348
|
-
|
|
349
|
-
|
|
309
|
+
flushAccumulator() {
|
|
310
|
+
if (!this.accDirty) return;
|
|
311
|
+
const merged = { tx: 0, ty: 0, tz: 0, rx: 0, ry: 0, rz: 0 };
|
|
312
|
+
for (const acc of this.deviceAccumulators.values()) {
|
|
313
|
+
merged.tx += acc.tx;
|
|
314
|
+
merged.ty += acc.ty;
|
|
315
|
+
merged.tz += acc.tz;
|
|
316
|
+
merged.rx += acc.rx;
|
|
317
|
+
merged.ry += acc.ry;
|
|
318
|
+
merged.rz += acc.rz;
|
|
319
|
+
}
|
|
320
|
+
this.deviceAccumulators.clear();
|
|
321
|
+
this.accDirty = false;
|
|
322
|
+
const data = {
|
|
323
|
+
translation: { x: merged.tx, y: merged.ty, z: merged.tz },
|
|
324
|
+
rotation: { x: merged.rx, y: merged.ry, z: merged.rz },
|
|
325
|
+
timestamp: performance.now() * 1e3
|
|
326
|
+
};
|
|
327
|
+
const { spatial, actions } = this.applyGlobalTransforms(data);
|
|
328
|
+
if (spatial) this.emit("spatialData", spatial);
|
|
329
|
+
if (actions) this.emit("actionValues", actions);
|
|
330
|
+
}
|
|
331
|
+
/** Per-device transforms: flip, sensitivity, dead zone, dominant, axis remap */
|
|
332
|
+
processPerDevice(raw, deviceId) {
|
|
333
|
+
const cfg = resolveDeviceConfig(this._config, deviceId);
|
|
350
334
|
let data = raw;
|
|
351
335
|
if (cfg.deadZone > 0) data = applyDeadZone(data, cfg.deadZone);
|
|
352
336
|
if (cfg.dominant) data = applyDominant(data);
|
|
353
337
|
data = applyFlip(data, cfg.flip);
|
|
354
338
|
data = applyAxisRemap(data, cfg.axisRemap);
|
|
355
339
|
data = applySensitivity(data, cfg.sensitivity);
|
|
340
|
+
return data;
|
|
341
|
+
}
|
|
342
|
+
/** Global transforms applied after per-device merge: locks + action map */
|
|
343
|
+
applyGlobalTransforms(data) {
|
|
344
|
+
const cfg = this._config;
|
|
356
345
|
if (cfg.lockPosition) {
|
|
357
346
|
data = { ...data, translation: { x: 0, y: 0, z: 0 } };
|
|
358
347
|
}
|
|
@@ -365,6 +354,6 @@ var InputManager = class extends TypedEmitter {
|
|
|
365
354
|
}
|
|
366
355
|
};
|
|
367
356
|
|
|
368
|
-
export {
|
|
357
|
+
export { DEFAULT_AXIS_MAP, DEFAULT_CONFIG, InputManager, applyAxisRemap, applyDeadZone, applyDominant, applyFlip, applySensitivity, loadSettings, mergeConfig, resolveDeviceConfig, saveSettings };
|
|
369
358
|
//# sourceMappingURL=index.js.map
|
|
370
359
|
//# sourceMappingURL=index.js.map
|