@kelnishi/satmouse-client 0.9.3 → 0.9.5

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.
@@ -427,6 +427,57 @@ function launchSatMouse(options) {
427
427
  });
428
428
  }
429
429
 
430
+ // src/utils/action-map.ts
431
+ var DEFAULT_ACTION_MAP = {
432
+ tx: { source: "tx" },
433
+ ty: { source: "ty" },
434
+ tz: { source: "tz" },
435
+ rx: { source: "rx" },
436
+ ry: { source: "ry" },
437
+ rz: { source: "rz" }
438
+ };
439
+ function readAxis(data, axis) {
440
+ switch (axis) {
441
+ case "tx":
442
+ return data.translation.x;
443
+ case "ty":
444
+ return data.translation.y;
445
+ case "tz":
446
+ return data.translation.z;
447
+ case "rx":
448
+ return data.rotation.x;
449
+ case "ry":
450
+ return data.rotation.y;
451
+ case "rz":
452
+ return data.rotation.z;
453
+ }
454
+ }
455
+ function applyActionMap(data, map) {
456
+ const result = {};
457
+ for (const [action, binding] of Object.entries(map)) {
458
+ let value = readAxis(data, binding.source);
459
+ if (binding.invert) value = -value;
460
+ value *= binding.scale ?? 1;
461
+ result[action] = value;
462
+ }
463
+ return result;
464
+ }
465
+ function actionValuesToSpatialData(values, timestamp) {
466
+ return {
467
+ translation: {
468
+ x: values.tx ?? 0,
469
+ y: values.ty ?? 0,
470
+ z: values.tz ?? 0
471
+ },
472
+ rotation: {
473
+ x: values.rx ?? 0,
474
+ y: values.ry ?? 0,
475
+ z: values.rz ?? 0
476
+ },
477
+ timestamp
478
+ };
479
+ }
480
+
430
481
  // src/utils/config.ts
431
482
  var DEFAULT_CONFIG = {
432
483
  sensitivity: { translation: 1e-3, rotation: 1e-3 },
@@ -435,15 +486,60 @@ var DEFAULT_CONFIG = {
435
486
  dominant: false,
436
487
  axisRemap: { tx: "x", ty: "y", tz: "z", rx: "x", ry: "y", rz: "z" },
437
488
  lockPosition: false,
438
- lockRotation: false
489
+ lockRotation: false,
490
+ actionMap: { ...DEFAULT_ACTION_MAP },
491
+ devices: {}
439
492
  };
440
493
  function mergeConfig(base, partial) {
441
- return {
494
+ const merged = {
442
495
  ...base,
443
496
  ...partial,
444
497
  sensitivity: { ...base.sensitivity, ...partial.sensitivity },
445
498
  flip: { ...base.flip, ...partial.flip },
446
- axisRemap: { ...base.axisRemap, ...partial.axisRemap }
499
+ axisRemap: { ...base.axisRemap, ...partial.axisRemap },
500
+ actionMap: partial.actionMap ? { ...base.actionMap, ...partial.actionMap } : { ...base.actionMap },
501
+ devices: { ...base.devices }
502
+ };
503
+ if (partial.devices) {
504
+ for (const [key, devCfg] of Object.entries(partial.devices)) {
505
+ merged.devices[key] = mergeDeviceConfig(merged.devices[key], devCfg);
506
+ }
507
+ }
508
+ return merged;
509
+ }
510
+ function mergeDeviceConfig(base, partial) {
511
+ if (!base) return partial;
512
+ return {
513
+ ...base,
514
+ ...partial,
515
+ sensitivity: partial.sensitivity ? { ...base.sensitivity, ...partial.sensitivity } : base.sensitivity,
516
+ flip: partial.flip ? { ...base.flip, ...partial.flip } : base.flip,
517
+ axisRemap: partial.axisRemap ? { ...base.axisRemap, ...partial.axisRemap } : base.axisRemap
518
+ };
519
+ }
520
+ function resolveDeviceConfig(config, deviceId) {
521
+ let deviceOverride;
522
+ if (config.devices[deviceId]) {
523
+ deviceOverride = config.devices[deviceId];
524
+ } else {
525
+ for (const [pattern, cfg] of Object.entries(config.devices)) {
526
+ if (pattern.endsWith("*") && deviceId.startsWith(pattern.slice(0, -1))) {
527
+ deviceOverride = cfg;
528
+ break;
529
+ }
530
+ }
531
+ }
532
+ if (!deviceOverride) return config;
533
+ return {
534
+ ...config,
535
+ sensitivity: { ...config.sensitivity, ...deviceOverride.sensitivity },
536
+ flip: { ...config.flip, ...deviceOverride.flip },
537
+ deadZone: deviceOverride.deadZone ?? config.deadZone,
538
+ dominant: deviceOverride.dominant ?? config.dominant,
539
+ axisRemap: { ...config.axisRemap, ...deviceOverride.axisRemap },
540
+ actionMap: deviceOverride.actionMap ? { ...config.actionMap, ...deviceOverride.actionMap } : config.actionMap,
541
+ lockPosition: deviceOverride.lockPosition ?? config.lockPosition,
542
+ lockRotation: deviceOverride.lockRotation ?? config.lockRotation
447
543
  };
448
544
  }
449
545
 
@@ -555,6 +651,7 @@ function applyAxisRemap(data, map) {
555
651
  var InputManager = class extends TypedEmitter {
556
652
  connections = [];
557
653
  storage;
654
+ knownDevices = /* @__PURE__ */ new Map();
558
655
  _config;
559
656
  get config() {
560
657
  return this._config;
@@ -587,14 +684,46 @@ var InputManager = class extends TypedEmitter {
587
684
  /** Fetch device info from all connections */
588
685
  async fetchDeviceInfo() {
589
686
  const results = await Promise.all(this.connections.map((c) => c.fetchDeviceInfo()));
590
- return results.flat();
687
+ const devices = results.flat();
688
+ for (const d of devices) this.knownDevices.set(d.id, d);
689
+ return devices;
591
690
  }
592
- /** Update configuration. Persists by default. */
691
+ /** Get all known connected devices paired with their resolved config */
692
+ getDevicesWithConfig() {
693
+ return Array.from(this.knownDevices.values()).map((device) => ({
694
+ device,
695
+ config: this.getDeviceConfig(device.id)
696
+ }));
697
+ }
698
+ /** Get the resolved per-device config (global defaults + device overrides) */
699
+ getDeviceConfig(deviceId) {
700
+ const resolved = resolveDeviceConfig(this._config, deviceId);
701
+ return {
702
+ sensitivity: resolved.sensitivity,
703
+ flip: resolved.flip,
704
+ deadZone: resolved.deadZone,
705
+ dominant: resolved.dominant,
706
+ axisRemap: resolved.axisRemap,
707
+ actionMap: resolved.actionMap,
708
+ lockPosition: resolved.lockPosition,
709
+ lockRotation: resolved.lockRotation
710
+ };
711
+ }
712
+ /** Update global configuration. Persists by default. */
593
713
  updateConfig(partial, persist = true) {
594
714
  this._config = mergeConfig(this._config, partial);
595
715
  if (persist) saveSettings(this._config, this.storage);
596
716
  this.emit("configChange", this._config);
597
717
  }
718
+ /** Update configuration for a specific device. Persists by default. */
719
+ updateDeviceConfig(deviceId, partial, persist = true) {
720
+ const existing = this._config.devices[deviceId] ?? {};
721
+ this._config = mergeConfig(this._config, {
722
+ devices: { [deviceId]: { ...existing, ...partial } }
723
+ });
724
+ if (persist) saveSettings(this._config, this.storage);
725
+ this.emit("configChange", this._config);
726
+ }
598
727
  /** Register a callback for processed spatial data. Returns unsubscribe function. */
599
728
  onSpatialData(callback) {
600
729
  this.on("spatialData", callback);
@@ -605,15 +734,25 @@ var InputManager = class extends TypedEmitter {
605
734
  this.on("buttonEvent", callback);
606
735
  return () => this.off("buttonEvent", callback);
607
736
  }
737
+ /** Register a callback for action values. Returns unsubscribe function. */
738
+ onActionValues(callback) {
739
+ this.on("actionValues", callback);
740
+ return () => this.off("actionValues", callback);
741
+ }
608
742
  wireConnection(connection) {
609
743
  connection.on("spatialData", (raw) => {
610
744
  this.emit("rawSpatialData", raw);
611
- const processed = this.processSpatialData(raw);
612
- if (processed) this.emit("spatialData", processed);
745
+ const { spatial, actions } = this.processSpatialData(raw);
746
+ if (spatial) this.emit("spatialData", spatial);
747
+ if (actions) this.emit("actionValues", actions);
613
748
  });
614
749
  connection.on("buttonEvent", (event) => this.emit("buttonEvent", event));
615
750
  connection.on("stateChange", (state, proto) => this.emit("stateChange", state, proto));
616
- connection.on("deviceStatus", (event, device) => this.emit("deviceStatus", event, device));
751
+ connection.on("deviceStatus", (event, device) => {
752
+ if (event === "connected") this.knownDevices.set(device.id, device);
753
+ else this.knownDevices.delete(device.id);
754
+ this.emit("deviceStatus", event, device);
755
+ });
617
756
  }
618
757
  processSpatialData(raw) {
619
758
  const cfg = this._config;
@@ -629,7 +768,9 @@ var InputManager = class extends TypedEmitter {
629
768
  if (cfg.lockRotation) {
630
769
  data = { ...data, rotation: { x: 0, y: 0, z: 0 } };
631
770
  }
632
- return data;
771
+ const actions = applyActionMap(data, cfg.actionMap);
772
+ const spatial = actionValuesToSpatialData(actions, data.timestamp);
773
+ return { spatial, actions };
633
774
  }
634
775
  };
635
776
  var SatMouseContext = react.createContext(null);