@kelnishi/satmouse-client 0.9.14 → 0.10.0
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-JTG5GEIB.cjs +65 -0
- package/dist/chunk-JTG5GEIB.cjs.map +1 -0
- package/dist/chunk-RNM322RZ.js +60 -0
- package/dist/chunk-RNM322RZ.js.map +1 -0
- package/dist/{connection-5KQFvHoJ.d.cts → connection-DQxI5qib.d.cts} +6 -0
- package/dist/{connection-5KQFvHoJ.d.ts → connection-DQxI5qib.d.ts} +6 -0
- package/dist/core/index.d.cts +2 -2
- package/dist/core/index.d.ts +2 -2
- package/dist/elements/index.cjs +84 -67
- package/dist/elements/index.cjs.map +1 -1
- package/dist/elements/index.d.cts +4 -1
- package/dist/elements/index.d.ts +4 -1
- package/dist/elements/index.js +84 -67
- package/dist/elements/index.js.map +1 -1
- package/dist/react/index.cjs +130 -236
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +35 -95
- package/dist/react/index.d.ts +35 -95
- package/dist/react/index.js +130 -236
- package/dist/react/index.js.map +1 -1
- package/dist/utils/index.cjs +102 -173
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.d.cts +42 -115
- package/dist/utils/index.d.ts +42 -115
- package/dist/utils/index.js +96 -161
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-I47ZOX3M.js +0 -64
- package/dist/chunk-I47ZOX3M.js.map +0 -1
- package/dist/chunk-LDSDVYCV.cjs +0 -69
- package/dist/chunk-LDSDVYCV.cjs.map +0 -1
package/dist/utils/index.cjs
CHANGED
|
@@ -1,50 +1,54 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkI5MEZZOT_cjs = require('../chunk-I5MEZZOT.cjs');
|
|
4
|
-
var
|
|
4
|
+
var chunkJTG5GEIB_cjs = require('../chunk-JTG5GEIB.cjs');
|
|
5
5
|
|
|
6
6
|
// src/utils/config.ts
|
|
7
7
|
var DEFAULT_CONFIG = {
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
routes: chunkJTG5GEIB_cjs.DEFAULT_ROUTES,
|
|
9
|
+
scale: 1e-3,
|
|
10
10
|
deadZone: 0,
|
|
11
11
|
dominant: false,
|
|
12
|
-
axisRemap: { tx: "x", ty: "y", tz: "z", rx: "x", ry: "y", rz: "z" },
|
|
13
12
|
lockPosition: false,
|
|
14
13
|
lockRotation: false,
|
|
15
|
-
actionMap: { ...chunkLDSDVYCV_cjs.DEFAULT_ACTION_MAP },
|
|
16
14
|
devices: {
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
"cnx-*": {
|
|
16
|
+
routes: [
|
|
17
|
+
{ source: "tx", target: "tx" },
|
|
18
|
+
{ source: "ty", target: "ty", flip: true },
|
|
19
|
+
{ source: "tz", target: "tz", flip: true },
|
|
20
|
+
{ source: "rx", target: "rx" },
|
|
21
|
+
{ source: "ry", target: "ry", flip: true },
|
|
22
|
+
{ source: "rz", target: "rz", flip: true }
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
// PlayStation: L2 (ty) → TY, R2 (ry) → TY flipped (push-pull)
|
|
26
|
+
"hid-54c-*": {
|
|
27
|
+
routes: [
|
|
28
|
+
{ source: "tx", target: "tx" },
|
|
29
|
+
{ source: "tz", target: "tz" },
|
|
30
|
+
{ source: "rz", target: "rz" },
|
|
31
|
+
{ source: "rx", target: "rx" },
|
|
32
|
+
{ source: "ty", target: "ty" },
|
|
33
|
+
{ source: "ry", target: "ty", flip: true }
|
|
34
|
+
]
|
|
35
|
+
}
|
|
19
36
|
}
|
|
20
37
|
};
|
|
21
38
|
function mergeConfig(base, partial) {
|
|
22
39
|
const merged = {
|
|
23
40
|
...base,
|
|
24
41
|
...partial,
|
|
25
|
-
|
|
26
|
-
flip: { ...base.flip, ...partial.flip },
|
|
27
|
-
axisRemap: { ...base.axisRemap, ...partial.axisRemap },
|
|
28
|
-
actionMap: partial.actionMap ? { ...base.actionMap, ...partial.actionMap } : { ...base.actionMap },
|
|
42
|
+
routes: partial.routes ?? [...base.routes],
|
|
29
43
|
devices: { ...base.devices }
|
|
30
44
|
};
|
|
31
45
|
if (partial.devices) {
|
|
32
46
|
for (const [key, devCfg] of Object.entries(partial.devices)) {
|
|
33
|
-
merged.devices[key] =
|
|
47
|
+
merged.devices[key] = { ...merged.devices[key], ...devCfg };
|
|
34
48
|
}
|
|
35
49
|
}
|
|
36
50
|
return merged;
|
|
37
51
|
}
|
|
38
|
-
function mergeDeviceConfig(base, partial) {
|
|
39
|
-
if (!base) return partial;
|
|
40
|
-
return {
|
|
41
|
-
...base,
|
|
42
|
-
...partial,
|
|
43
|
-
sensitivity: partial.sensitivity ? { ...base.sensitivity, ...partial.sensitivity } : base.sensitivity,
|
|
44
|
-
flip: partial.flip ? { ...base.flip, ...partial.flip } : base.flip,
|
|
45
|
-
axisRemap: partial.axisRemap ? { ...base.axisRemap, ...partial.axisRemap } : base.axisRemap
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
52
|
function resolveDeviceConfig(config, deviceId) {
|
|
49
53
|
let deviceOverride;
|
|
50
54
|
if (config.devices[deviceId]) {
|
|
@@ -60,14 +64,10 @@ function resolveDeviceConfig(config, deviceId) {
|
|
|
60
64
|
if (!deviceOverride) return config;
|
|
61
65
|
return {
|
|
62
66
|
...config,
|
|
63
|
-
|
|
64
|
-
|
|
67
|
+
routes: deviceOverride.routes ?? config.routes,
|
|
68
|
+
scale: deviceOverride.scale ?? config.scale,
|
|
65
69
|
deadZone: deviceOverride.deadZone ?? config.deadZone,
|
|
66
|
-
dominant: deviceOverride.dominant ?? config.dominant
|
|
67
|
-
axisRemap: { ...config.axisRemap, ...deviceOverride.axisRemap },
|
|
68
|
-
actionMap: deviceOverride.actionMap ? { ...config.actionMap, ...deviceOverride.actionMap } : config.actionMap,
|
|
69
|
-
lockPosition: deviceOverride.lockPosition ?? config.lockPosition,
|
|
70
|
-
lockRotation: deviceOverride.lockRotation ?? config.lockRotation
|
|
70
|
+
dominant: deviceOverride.dominant ?? config.dominant
|
|
71
71
|
};
|
|
72
72
|
}
|
|
73
73
|
|
|
@@ -86,6 +86,11 @@ function saveSettings(config, storage) {
|
|
|
86
86
|
if (!s) return;
|
|
87
87
|
s.setItem(STORAGE_KEY, JSON.stringify(config));
|
|
88
88
|
}
|
|
89
|
+
function clearSettings(storage) {
|
|
90
|
+
const s = getStorage(storage);
|
|
91
|
+
if (!s) return;
|
|
92
|
+
s.setItem(STORAGE_KEY, "{}");
|
|
93
|
+
}
|
|
89
94
|
function loadSettings(storage) {
|
|
90
95
|
const s = getStorage(storage);
|
|
91
96
|
if (!s) return null;
|
|
@@ -98,97 +103,11 @@ function loadSettings(storage) {
|
|
|
98
103
|
}
|
|
99
104
|
}
|
|
100
105
|
|
|
101
|
-
// src/utils/transforms.ts
|
|
102
|
-
var DEFAULT_AXIS_MAP = {
|
|
103
|
-
tx: "x",
|
|
104
|
-
ty: "y",
|
|
105
|
-
tz: "z",
|
|
106
|
-
rx: "x",
|
|
107
|
-
ry: "y",
|
|
108
|
-
rz: "z"
|
|
109
|
-
};
|
|
110
|
-
function applyFlip(data, flip) {
|
|
111
|
-
return {
|
|
112
|
-
...data,
|
|
113
|
-
translation: {
|
|
114
|
-
x: flip.tx ? -data.translation.x : data.translation.x,
|
|
115
|
-
y: flip.ty ? -data.translation.y : data.translation.y,
|
|
116
|
-
z: flip.tz ? -data.translation.z : data.translation.z
|
|
117
|
-
},
|
|
118
|
-
rotation: {
|
|
119
|
-
x: flip.rx ? -data.rotation.x : data.rotation.x,
|
|
120
|
-
y: flip.ry ? -data.rotation.y : data.rotation.y,
|
|
121
|
-
z: flip.rz ? -data.rotation.z : data.rotation.z
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
function applySensitivity(data, sens) {
|
|
126
|
-
return {
|
|
127
|
-
...data,
|
|
128
|
-
translation: {
|
|
129
|
-
x: data.translation.x * sens.translation,
|
|
130
|
-
y: data.translation.y * sens.translation,
|
|
131
|
-
z: data.translation.z * sens.translation
|
|
132
|
-
},
|
|
133
|
-
rotation: {
|
|
134
|
-
x: data.rotation.x * sens.rotation,
|
|
135
|
-
y: data.rotation.y * sens.rotation,
|
|
136
|
-
z: data.rotation.z * sens.rotation
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
function applyDominant(data) {
|
|
141
|
-
const axes = [
|
|
142
|
-
{ group: "t", key: "x", v: Math.abs(data.translation.x) },
|
|
143
|
-
{ group: "t", key: "y", v: Math.abs(data.translation.y) },
|
|
144
|
-
{ group: "t", key: "z", v: Math.abs(data.translation.z) },
|
|
145
|
-
{ group: "r", key: "x", v: Math.abs(data.rotation.x) },
|
|
146
|
-
{ group: "r", key: "y", v: Math.abs(data.rotation.y) },
|
|
147
|
-
{ group: "r", key: "z", v: Math.abs(data.rotation.z) }
|
|
148
|
-
];
|
|
149
|
-
const max = axes.reduce((a, b) => b.v > a.v ? b : a);
|
|
150
|
-
const t = { x: 0, y: 0, z: 0 };
|
|
151
|
-
const r = { x: 0, y: 0, z: 0 };
|
|
152
|
-
if (max.group === "t") t[max.key] = data.translation[max.key];
|
|
153
|
-
else r[max.key] = data.rotation[max.key];
|
|
154
|
-
return { ...data, translation: t, rotation: r };
|
|
155
|
-
}
|
|
156
|
-
function applyDeadZone(data, threshold) {
|
|
157
|
-
const dz = (v) => Math.abs(v) < threshold ? 0 : v;
|
|
158
|
-
return {
|
|
159
|
-
...data,
|
|
160
|
-
translation: { x: dz(data.translation.x), y: dz(data.translation.y), z: dz(data.translation.z) },
|
|
161
|
-
rotation: { x: dz(data.rotation.x), y: dz(data.rotation.y), z: dz(data.rotation.z) }
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
function applyAxisRemap(data, map) {
|
|
165
|
-
return {
|
|
166
|
-
...data,
|
|
167
|
-
translation: {
|
|
168
|
-
x: 0,
|
|
169
|
-
y: 0,
|
|
170
|
-
z: 0,
|
|
171
|
-
[map.tx]: data.translation.x,
|
|
172
|
-
[map.ty]: data.translation.y,
|
|
173
|
-
[map.tz]: data.translation.z
|
|
174
|
-
},
|
|
175
|
-
rotation: {
|
|
176
|
-
x: 0,
|
|
177
|
-
y: 0,
|
|
178
|
-
z: 0,
|
|
179
|
-
[map.rx]: data.rotation.x,
|
|
180
|
-
[map.ry]: data.rotation.y,
|
|
181
|
-
[map.rz]: data.rotation.z
|
|
182
|
-
}
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
|
|
186
106
|
// src/utils/input-manager.ts
|
|
187
107
|
var InputManager = class extends chunkI5MEZZOT_cjs.TypedEmitter {
|
|
188
108
|
connections = [];
|
|
189
109
|
storage;
|
|
190
110
|
knownDevices = /* @__PURE__ */ new Map();
|
|
191
|
-
// Per-device accumulators: latest value from each device per frame tick
|
|
192
111
|
deviceAccumulators = /* @__PURE__ */ new Map();
|
|
193
112
|
accDirty = false;
|
|
194
113
|
flushTimer = null;
|
|
@@ -203,22 +122,18 @@ var InputManager = class extends chunkI5MEZZOT_cjs.TypedEmitter {
|
|
|
203
122
|
this._config = mergeConfig(DEFAULT_CONFIG, { ...config, ...persisted });
|
|
204
123
|
this.flushTimer = setInterval(() => this.flushAccumulator(), 16);
|
|
205
124
|
}
|
|
206
|
-
/** Add a connection to the managed set */
|
|
207
125
|
addConnection(connection) {
|
|
208
126
|
this.connections.push(connection);
|
|
209
127
|
this.wireConnection(connection);
|
|
210
128
|
}
|
|
211
|
-
/** Remove a connection */
|
|
212
129
|
removeConnection(connection) {
|
|
213
130
|
const idx = this.connections.indexOf(connection);
|
|
214
131
|
if (idx !== -1) this.connections.splice(idx, 1);
|
|
215
132
|
connection.removeAllListeners();
|
|
216
133
|
}
|
|
217
|
-
/** Connect all managed connections */
|
|
218
134
|
async connect() {
|
|
219
135
|
await Promise.all(this.connections.map((c) => c.connect()));
|
|
220
136
|
}
|
|
221
|
-
/** Disconnect all managed connections */
|
|
222
137
|
disconnect() {
|
|
223
138
|
for (const c of this.connections) c.disconnect();
|
|
224
139
|
if (this.flushTimer) {
|
|
@@ -226,41 +141,32 @@ var InputManager = class extends chunkI5MEZZOT_cjs.TypedEmitter {
|
|
|
226
141
|
this.flushTimer = null;
|
|
227
142
|
}
|
|
228
143
|
}
|
|
229
|
-
/** Fetch device info from all connections */
|
|
230
144
|
async fetchDeviceInfo() {
|
|
231
145
|
const results = await Promise.all(this.connections.map((c) => c.fetchDeviceInfo()));
|
|
232
146
|
const devices = results.flat();
|
|
233
147
|
for (const d of devices) this.knownDevices.set(d.id, d);
|
|
234
148
|
return devices;
|
|
235
149
|
}
|
|
236
|
-
/** Get all known connected devices paired with their resolved config */
|
|
237
150
|
getDevicesWithConfig() {
|
|
238
151
|
return Array.from(this.knownDevices.values()).map((device) => ({
|
|
239
152
|
device,
|
|
240
153
|
config: this.getDeviceConfig(device.id)
|
|
241
154
|
}));
|
|
242
155
|
}
|
|
243
|
-
/** Get the resolved per-device config (global defaults + device overrides) */
|
|
244
156
|
getDeviceConfig(deviceId) {
|
|
245
157
|
const resolved = resolveDeviceConfig(this._config, deviceId);
|
|
246
158
|
return {
|
|
247
|
-
|
|
248
|
-
|
|
159
|
+
routes: resolved.routes,
|
|
160
|
+
scale: resolved.scale,
|
|
249
161
|
deadZone: resolved.deadZone,
|
|
250
|
-
dominant: resolved.dominant
|
|
251
|
-
axisRemap: resolved.axisRemap,
|
|
252
|
-
actionMap: resolved.actionMap,
|
|
253
|
-
lockPosition: resolved.lockPosition,
|
|
254
|
-
lockRotation: resolved.lockRotation
|
|
162
|
+
dominant: resolved.dominant
|
|
255
163
|
};
|
|
256
164
|
}
|
|
257
|
-
/** Update global configuration. Persists by default. */
|
|
258
165
|
updateConfig(partial, persist = true) {
|
|
259
166
|
this._config = mergeConfig(this._config, partial);
|
|
260
167
|
if (persist) saveSettings(this._config, this.storage);
|
|
261
168
|
this.emit("configChange", this._config);
|
|
262
169
|
}
|
|
263
|
-
/** Update configuration for a specific device. Persists by default. */
|
|
264
170
|
updateDeviceConfig(deviceId, partial, persist = true) {
|
|
265
171
|
const existing = this._config.devices[deviceId] ?? {};
|
|
266
172
|
this._config = mergeConfig(this._config, {
|
|
@@ -269,21 +175,25 @@ var InputManager = class extends chunkI5MEZZOT_cjs.TypedEmitter {
|
|
|
269
175
|
if (persist) saveSettings(this._config, this.storage);
|
|
270
176
|
this.emit("configChange", this._config);
|
|
271
177
|
}
|
|
272
|
-
|
|
178
|
+
resetDeviceConfig(deviceId, persist = true) {
|
|
179
|
+
const { [deviceId]: _, ...rest } = this._config.devices;
|
|
180
|
+
this._config = { ...this._config, devices: rest };
|
|
181
|
+
if (persist) saveSettings(this._config, this.storage);
|
|
182
|
+
this.emit("configChange", this._config);
|
|
183
|
+
}
|
|
184
|
+
resetAllConfig() {
|
|
185
|
+
clearSettings(this.storage);
|
|
186
|
+
this._config = { ...DEFAULT_CONFIG };
|
|
187
|
+
this.emit("configChange", this._config);
|
|
188
|
+
}
|
|
273
189
|
onSpatialData(callback) {
|
|
274
190
|
this.on("spatialData", callback);
|
|
275
191
|
return () => this.off("spatialData", callback);
|
|
276
192
|
}
|
|
277
|
-
/** Register a callback for button events. Returns unsubscribe function. */
|
|
278
193
|
onButtonEvent(callback) {
|
|
279
194
|
this.on("buttonEvent", callback);
|
|
280
195
|
return () => this.off("buttonEvent", callback);
|
|
281
196
|
}
|
|
282
|
-
/** Register a callback for action values. Returns unsubscribe function. */
|
|
283
|
-
onActionValues(callback) {
|
|
284
|
-
this.on("actionValues", callback);
|
|
285
|
-
return () => this.off("actionValues", callback);
|
|
286
|
-
}
|
|
287
197
|
wireConnection(connection) {
|
|
288
198
|
connection.on("spatialData", (raw) => {
|
|
289
199
|
this.emit("rawSpatialData", raw);
|
|
@@ -320,65 +230,84 @@ var InputManager = class extends chunkI5MEZZOT_cjs.TypedEmitter {
|
|
|
320
230
|
}
|
|
321
231
|
this.deviceAccumulators.clear();
|
|
322
232
|
this.accDirty = false;
|
|
323
|
-
|
|
233
|
+
let data = {
|
|
324
234
|
translation: { x: merged.tx, y: merged.ty, z: merged.tz },
|
|
325
235
|
rotation: { x: merged.rx, y: merged.ry, z: merged.rz },
|
|
326
236
|
timestamp: performance.now() * 1e3
|
|
327
237
|
};
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
238
|
+
if (this._config.lockPosition) {
|
|
239
|
+
data = { ...data, translation: { x: 0, y: 0, z: 0 } };
|
|
240
|
+
}
|
|
241
|
+
if (this._config.lockRotation) {
|
|
242
|
+
data = { ...data, rotation: { x: 0, y: 0, z: 0 } };
|
|
243
|
+
}
|
|
244
|
+
this.emit("spatialData", data);
|
|
331
245
|
}
|
|
332
|
-
/** Per-device
|
|
246
|
+
/** Per-device: deadZone → dominant → routes (flip + scale + remap in one pass) */
|
|
333
247
|
processPerDevice(raw, deviceId) {
|
|
334
248
|
const cfg = resolveDeviceConfig(this._config, deviceId);
|
|
335
249
|
let data = raw;
|
|
336
|
-
if (cfg.deadZone > 0)
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
250
|
+
if (cfg.deadZone > 0) {
|
|
251
|
+
const dz = (v) => Math.abs(v) < cfg.deadZone ? 0 : v;
|
|
252
|
+
data = {
|
|
253
|
+
...data,
|
|
254
|
+
translation: { x: dz(data.translation.x), y: dz(data.translation.y), z: dz(data.translation.z) },
|
|
255
|
+
rotation: { x: dz(data.rotation.x), y: dz(data.rotation.y), z: dz(data.rotation.z) }
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
if (cfg.dominant) {
|
|
259
|
+
const axes = [
|
|
260
|
+
{ g: "t", k: "x", v: Math.abs(data.translation.x) },
|
|
261
|
+
{ g: "t", k: "y", v: Math.abs(data.translation.y) },
|
|
262
|
+
{ g: "t", k: "z", v: Math.abs(data.translation.z) },
|
|
263
|
+
{ g: "r", k: "x", v: Math.abs(data.rotation.x) },
|
|
264
|
+
{ g: "r", k: "y", v: Math.abs(data.rotation.y) },
|
|
265
|
+
{ g: "r", k: "z", v: Math.abs(data.rotation.z) }
|
|
266
|
+
];
|
|
267
|
+
const max = axes.reduce((a, b) => b.v > a.v ? b : a);
|
|
268
|
+
const t = { x: 0, y: 0, z: 0 };
|
|
269
|
+
const r = { x: 0, y: 0, z: 0 };
|
|
270
|
+
if (max.g === "t") t[max.k] = data.translation[max.k];
|
|
271
|
+
else r[max.k] = data.rotation[max.k];
|
|
272
|
+
data = { ...data, translation: t, rotation: r };
|
|
273
|
+
}
|
|
274
|
+
const device = this.knownDevices.get(deviceId);
|
|
275
|
+
const deviceRoutes = this.resolveRoutes(deviceId, device);
|
|
276
|
+
data = chunkJTG5GEIB_cjs.applyRoutes(data, deviceRoutes, cfg.scale);
|
|
341
277
|
return data;
|
|
342
278
|
}
|
|
343
|
-
/**
|
|
344
|
-
|
|
345
|
-
const
|
|
346
|
-
if (
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
279
|
+
/** Get the effective routes for a device: device config override > device axes metadata > global default */
|
|
280
|
+
resolveRoutes(deviceId, device) {
|
|
281
|
+
const devCfg = this._config.devices[deviceId];
|
|
282
|
+
if (devCfg?.routes && Array.isArray(devCfg.routes)) return devCfg.routes;
|
|
283
|
+
for (const [pattern, cfg] of Object.entries(this._config.devices)) {
|
|
284
|
+
if (pattern.endsWith("*") && deviceId.startsWith(pattern.slice(0, -1))) {
|
|
285
|
+
if (cfg.routes && Array.isArray(cfg.routes)) return cfg.routes;
|
|
286
|
+
}
|
|
351
287
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
return { spatial, actions };
|
|
288
|
+
if (device?.axes) return chunkJTG5GEIB_cjs.buildRoutes(device.axes);
|
|
289
|
+
return chunkJTG5GEIB_cjs.DEFAULT_ROUTES;
|
|
355
290
|
}
|
|
356
291
|
};
|
|
357
292
|
|
|
358
|
-
Object.defineProperty(exports, "
|
|
293
|
+
Object.defineProperty(exports, "DEFAULT_ROUTES", {
|
|
359
294
|
enumerable: true,
|
|
360
|
-
get: function () { return
|
|
295
|
+
get: function () { return chunkJTG5GEIB_cjs.DEFAULT_ROUTES; }
|
|
361
296
|
});
|
|
362
|
-
Object.defineProperty(exports, "
|
|
297
|
+
Object.defineProperty(exports, "FULL_AXES", {
|
|
363
298
|
enumerable: true,
|
|
364
|
-
get: function () { return
|
|
299
|
+
get: function () { return chunkJTG5GEIB_cjs.FULL_AXES; }
|
|
365
300
|
});
|
|
366
|
-
Object.defineProperty(exports, "
|
|
301
|
+
Object.defineProperty(exports, "applyRoutes", {
|
|
367
302
|
enumerable: true,
|
|
368
|
-
get: function () { return
|
|
303
|
+
get: function () { return chunkJTG5GEIB_cjs.applyRoutes; }
|
|
369
304
|
});
|
|
370
|
-
Object.defineProperty(exports, "
|
|
305
|
+
Object.defineProperty(exports, "buildRoutes", {
|
|
371
306
|
enumerable: true,
|
|
372
|
-
get: function () { return
|
|
307
|
+
get: function () { return chunkJTG5GEIB_cjs.buildRoutes; }
|
|
373
308
|
});
|
|
374
|
-
exports.DEFAULT_AXIS_MAP = DEFAULT_AXIS_MAP;
|
|
375
309
|
exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
|
|
376
310
|
exports.InputManager = InputManager;
|
|
377
|
-
exports.applyAxisRemap = applyAxisRemap;
|
|
378
|
-
exports.applyDeadZone = applyDeadZone;
|
|
379
|
-
exports.applyDominant = applyDominant;
|
|
380
|
-
exports.applyFlip = applyFlip;
|
|
381
|
-
exports.applySensitivity = applySensitivity;
|
|
382
311
|
exports.loadSettings = loadSettings;
|
|
383
312
|
exports.mergeConfig = mergeConfig;
|
|
384
313
|
exports.resolveDeviceConfig = resolveDeviceConfig;
|
package/dist/utils/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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"]}
|
|
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\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 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 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) => 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 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"]}
|