@kelnishi/satmouse-client 0.16.1 → 0.17.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/README.md CHANGED
@@ -73,33 +73,66 @@ function Scene() {
73
73
  <satmouse-debug></satmouse-debug>
74
74
  ```
75
75
 
76
- ## Per-Device Configuration
76
+ ## Configuration
77
77
 
78
- Axis routing with per-device flip, scale, and remapping:
78
+ ### Device class defaults
79
+
80
+ Set routes, scales, and behavior by device class — applies to all devices of that type:
79
81
 
80
82
  ```typescript
81
83
  const manager = new InputManager({
82
84
  translateScale: 0.001,
83
85
  rotateScale: 0.001,
84
- wScale: 0.001,
85
- devices: {
86
- "cnx-*": {
86
+ deviceClasses: {
87
+ spacemouse: {
88
+ // Built-in default: flips Y/Z axes (3Dconnexion convention)
89
+ rotateScale: 0.0005,
90
+ },
91
+ gamepad: {
87
92
  routes: [
88
93
  { source: "tx", target: "tx" },
89
- { source: "ty", target: "ty", flip: true },
90
- { source: "tz", target: "tz", flip: true },
94
+ { source: "tz", target: "tz" },
91
95
  { source: "rx", target: "rx" },
92
- { source: "ry", target: "ry", flip: true },
93
- { source: "rz", target: "rz", flip: true },
96
+ { source: "rz", target: "rz" },
97
+ { source: "ty", target: "ty" }, // L2 trigger
98
+ { source: "ry", target: "ty", flip: true }, // R2 trigger (push-pull)
94
99
  ],
100
+ deadZone: 0.05,
95
101
  },
96
102
  },
97
103
  });
104
+ ```
105
+
106
+ Device classes: `"spacemouse"`, `"gamepad"`, `"dial"`, `"joystick"`, `"6dof"`, `"other"`
107
+
108
+ ### Per-device overrides
109
+
110
+ Override config for a specific device by ID or vendor pattern:
111
+
112
+ ```typescript
113
+ const manager = new InputManager({
114
+ devices: {
115
+ // All PlayStation controllers (vendor 054c)
116
+ "hid-54c-*": { translateScale: 0.002 },
117
+ // A specific device by ID
118
+ "hid-54c-9cc-1": { dominant: true },
119
+ },
120
+ });
98
121
 
99
- // Update per-device at runtime
122
+ // Update at runtime
100
123
  manager.updateDeviceConfig("cnx-c635", { translateScale: 0.0005 });
101
124
  ```
102
125
 
126
+ ### Resolution order
127
+
128
+ Config is resolved per-device in this priority:
129
+
130
+ 1. **Exact device ID** — `devices["hid-54c-9cc-1"]`
131
+ 2. **ID pattern** — `devices["hid-54c-*"]`
132
+ 3. **Device class** — `deviceClasses["gamepad"]`
133
+ 4. **Device axes metadata** — auto-generated passthrough from bridge
134
+ 5. **Global defaults** — `routes`, `translateScale`, etc.
135
+
103
136
  ## Button-to-Key Mapping
104
137
 
105
138
  Map device buttons to keyboard events:
@@ -162,4 +162,4 @@ declare class SatMouseConnection extends TypedEmitter<SatMouseEvents> {
162
162
  private clearReconnect;
163
163
  }
164
164
 
165
- export { type ButtonEvent as B, type ConnectOptions as C, type DeviceInfo as D, type SpatialData as S, type ThingDescription as T, type Vec3 as V, type ConnectionState as a, SatMouseConnection as b, type SatMouseEvents as c, type TransportProtocol as d, TypedEmitter as e, buildSatMouseUri as f, parseSatMouseUri as p };
165
+ export { type ButtonEvent as B, type ConnectOptions as C, type DeviceInfo as D, type SpatialData as S, type ThingDescription as T, type Vec3 as V, type ConnectionState as a, SatMouseConnection as b, type SatMouseEvents as c, type TransportProtocol as d, TypedEmitter as e, buildSatMouseUri as f, type DeviceClass as g, parseSatMouseUri as p };
@@ -162,4 +162,4 @@ declare class SatMouseConnection extends TypedEmitter<SatMouseEvents> {
162
162
  private clearReconnect;
163
163
  }
164
164
 
165
- export { type ButtonEvent as B, type ConnectOptions as C, type DeviceInfo as D, type SpatialData as S, type ThingDescription as T, type Vec3 as V, type ConnectionState as a, SatMouseConnection as b, type SatMouseEvents as c, type TransportProtocol as d, TypedEmitter as e, buildSatMouseUri as f, parseSatMouseUri as p };
165
+ export { type ButtonEvent as B, type ConnectOptions as C, type DeviceInfo as D, type SpatialData as S, type ThingDescription as T, type Vec3 as V, type ConnectionState as a, SatMouseConnection as b, type SatMouseEvents as c, type TransportProtocol as d, TypedEmitter as e, buildSatMouseUri as f, type DeviceClass as g, parseSatMouseUri as p };
@@ -1,5 +1,5 @@
1
- import { T as ThingDescription, S as SpatialData, B as ButtonEvent } from '../connection-DXjjuaLv.cjs';
2
- export { C as ConnectOptions, a as ConnectionState, D as DeviceInfo, b as SatMouseConnection, c as SatMouseEvents, d as TransportProtocol, e as TypedEmitter, V as Vec3, f as buildSatMouseUri, p as parseSatMouseUri } from '../connection-DXjjuaLv.cjs';
1
+ import { T as ThingDescription, S as SpatialData, B as ButtonEvent } from '../connection-DcA50IC2.cjs';
2
+ export { C as ConnectOptions, a as ConnectionState, D as DeviceInfo, b as SatMouseConnection, c as SatMouseEvents, d as TransportProtocol, e as TypedEmitter, V as Vec3, f as buildSatMouseUri, p as parseSatMouseUri } from '../connection-DcA50IC2.cjs';
3
3
 
4
4
  interface ResolvedEndpoints {
5
5
  webtransport?: {
@@ -1,5 +1,5 @@
1
- import { T as ThingDescription, S as SpatialData, B as ButtonEvent } from '../connection-DXjjuaLv.js';
2
- export { C as ConnectOptions, a as ConnectionState, D as DeviceInfo, b as SatMouseConnection, c as SatMouseEvents, d as TransportProtocol, e as TypedEmitter, V as Vec3, f as buildSatMouseUri, p as parseSatMouseUri } from '../connection-DXjjuaLv.js';
1
+ import { T as ThingDescription, S as SpatialData, B as ButtonEvent } from '../connection-DcA50IC2.js';
2
+ export { C as ConnectOptions, a as ConnectionState, D as DeviceInfo, b as SatMouseConnection, c as SatMouseEvents, d as TransportProtocol, e as TypedEmitter, V as Vec3, f as buildSatMouseUri, p as parseSatMouseUri } from '../connection-DcA50IC2.js';
3
3
 
4
4
  interface ResolvedEndpoints {
5
5
  webtransport?: {
@@ -1,5 +1,5 @@
1
1
  import { InputManager } from '../utils/index.cjs';
2
- import '../connection-DXjjuaLv.cjs';
2
+ import '../connection-DcA50IC2.cjs';
3
3
 
4
4
  declare class SatMouseStatus extends HTMLElement {
5
5
  private dot;
@@ -1,5 +1,5 @@
1
1
  import { InputManager } from '../utils/index.js';
2
- import '../connection-DXjjuaLv.js';
2
+ import '../connection-DcA50IC2.js';
3
3
 
4
4
  declare class SatMouseStatus extends HTMLElement {
5
5
  private dot;
@@ -598,8 +598,9 @@ var DEFAULT_CONFIG = {
598
598
  dominant: false,
599
599
  lockPosition: false,
600
600
  lockRotation: false,
601
- devices: {
602
- "cnx-*": {
601
+ devices: {},
602
+ deviceClasses: {
603
+ spacemouse: {
603
604
  routes: [
604
605
  { source: "tx", target: "tx" },
605
606
  { source: "ty", target: "ty", flip: true },
@@ -608,17 +609,6 @@ var DEFAULT_CONFIG = {
608
609
  { source: "ry", target: "ry", flip: true },
609
610
  { source: "rz", target: "rz", flip: true }
610
611
  ]
611
- },
612
- // PlayStation: L2 (ty) → TY, R2 (ry) → TY flipped (push-pull)
613
- "hid-54c-*": {
614
- routes: [
615
- { source: "tx", target: "tx" },
616
- { source: "tz", target: "tz" },
617
- { source: "rz", target: "rz" },
618
- { source: "rx", target: "rx" },
619
- { source: "ty", target: "ty" },
620
- { source: "ry", target: "ty", flip: true }
621
- ]
622
612
  }
623
613
  }
624
614
  };
@@ -628,16 +618,22 @@ function mergeConfig(base, partial) {
628
618
  ...partial,
629
619
  routes: partial.routes ?? [...base.routes],
630
620
  buttonRoutes: partial.buttonRoutes ?? [...base.buttonRoutes],
631
- devices: { ...base.devices }
621
+ devices: { ...base.devices },
622
+ deviceClasses: { ...base.deviceClasses }
632
623
  };
633
624
  if (partial.devices) {
634
625
  for (const [key, devCfg] of Object.entries(partial.devices)) {
635
626
  merged.devices[key] = { ...merged.devices[key], ...devCfg };
636
627
  }
637
628
  }
629
+ if (partial.deviceClasses) {
630
+ for (const [key, classCfg] of Object.entries(partial.deviceClasses)) {
631
+ if (classCfg) merged.deviceClasses[key] = { ...merged.deviceClasses[key], ...classCfg };
632
+ }
633
+ }
638
634
  return merged;
639
635
  }
640
- function resolveDeviceConfig(config, deviceId) {
636
+ function resolveDeviceConfig(config, deviceId, deviceClass) {
641
637
  let deviceOverride;
642
638
  if (config.devices[deviceId]) {
643
639
  deviceOverride = config.devices[deviceId];
@@ -649,6 +645,9 @@ function resolveDeviceConfig(config, deviceId) {
649
645
  }
650
646
  }
651
647
  }
648
+ if (!deviceOverride && deviceClass && config.deviceClasses[deviceClass]) {
649
+ deviceOverride = config.deviceClasses[deviceClass];
650
+ }
652
651
  if (!deviceOverride) return config;
653
652
  return {
654
653
  ...config,
@@ -764,7 +763,8 @@ var InputManager = class extends TypedEmitter {
764
763
  }));
765
764
  }
766
765
  getDeviceConfig(deviceId) {
767
- const resolved = resolveDeviceConfig(this._config, deviceId);
766
+ const device = this.knownDevices.get(deviceId);
767
+ const resolved = resolveDeviceConfig(this._config, deviceId, device?.deviceClass);
768
768
  return {
769
769
  routes: resolved.routes,
770
770
  buttonRoutes: resolved.buttonRoutes,
@@ -868,7 +868,8 @@ var InputManager = class extends TypedEmitter {
868
868
  }
869
869
  /** Per-device: deadZone → dominant → routes (flip + scale + remap in one pass) */
870
870
  processPerDevice(raw, deviceId) {
871
- const cfg = resolveDeviceConfig(this._config, deviceId);
871
+ const device = this.knownDevices.get(deviceId);
872
+ const cfg = resolveDeviceConfig(this._config, deviceId, device?.deviceClass);
872
873
  let data = raw;
873
874
  if (cfg.deadZone > 0) {
874
875
  const dz = (v) => Math.abs(v) < cfg.deadZone ? 0 : v;
@@ -894,12 +895,12 @@ var InputManager = class extends TypedEmitter {
894
895
  else r[max.k] = data.rotation[max.k];
895
896
  data = { ...data, translation: t, rotation: r };
896
897
  }
897
- const device = this.knownDevices.get(deviceId);
898
898
  const deviceRoutes = this.resolveRoutes(deviceId, device);
899
899
  data = applyRoutes(data, deviceRoutes, cfg.translateScale, cfg.rotateScale, cfg.wScale);
900
900
  return data;
901
901
  }
902
- /** Get the effective routes for a device: device config override > device axes metadata > global default */
902
+ /** Get the effective routes for a device:
903
+ * device ID override > pattern match > deviceClass > device axes metadata > global default */
903
904
  resolveRoutes(deviceId, device) {
904
905
  const devCfg = this._config.devices[deviceId];
905
906
  if (devCfg?.routes && Array.isArray(devCfg.routes)) return devCfg.routes;
@@ -908,6 +909,10 @@ var InputManager = class extends TypedEmitter {
908
909
  if (cfg.routes && Array.isArray(cfg.routes)) return cfg.routes;
909
910
  }
910
911
  }
912
+ if (device?.deviceClass) {
913
+ const classCfg = this._config.deviceClasses[device.deviceClass];
914
+ if (classCfg?.routes && Array.isArray(classCfg.routes)) return classCfg.routes;
915
+ }
911
916
  if (device?.axes) return buildRoutes(device.axes);
912
917
  return DEFAULT_ROUTES;
913
918
  }