@kelnishi/satmouse-client 0.10.8 → 0.12.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-RNM322RZ.js → chunk-RE4PNORY.js} +18 -11
- package/dist/chunk-RE4PNORY.js.map +1 -0
- package/dist/{chunk-JTG5GEIB.cjs → chunk-Y75556IA.cjs} +18 -11
- package/dist/chunk-Y75556IA.cjs.map +1 -0
- package/dist/{connection-DQxI5qib.d.cts → connection-C7xJRLzQ.d.cts} +5 -1
- package/dist/{connection-DQxI5qib.d.ts → connection-C7xJRLzQ.d.ts} +5 -1
- package/dist/core/index.d.cts +2 -2
- package/dist/core/index.d.ts +2 -2
- package/dist/elements/index.cjs +138 -14
- package/dist/elements/index.cjs.map +1 -1
- package/dist/elements/index.d.cts +2 -1
- package/dist/elements/index.d.ts +2 -1
- package/dist/elements/index.js +136 -12
- package/dist/elements/index.js.map +1 -1
- package/dist/react/index.cjs +59 -15
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +35 -6
- package/dist/react/index.d.ts +35 -6
- package/dist/react/index.js +59 -15
- package/dist/react/index.js.map +1 -1
- package/dist/utils/index.cjs +52 -15
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.d.cts +35 -11
- package/dist/utils/index.d.ts +35 -11
- package/dist/utils/index.js +46 -9
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-JTG5GEIB.cjs.map +0 -1
- package/dist/chunk-RNM322RZ.js.map +0 -1
package/dist/react/index.d.ts
CHANGED
|
@@ -16,10 +16,12 @@ interface Vec3 {
|
|
|
16
16
|
y: number;
|
|
17
17
|
z: number;
|
|
18
18
|
}
|
|
19
|
-
/** 6DOF spatial input frame
|
|
19
|
+
/** 6DOF+W spatial input frame */
|
|
20
20
|
interface SpatialData {
|
|
21
21
|
translation: Vec3;
|
|
22
22
|
rotation: Vec3;
|
|
23
|
+
/** Virtual W axis — application-defined (e.g., zoom, scroll, tool size) */
|
|
24
|
+
w?: number;
|
|
23
25
|
timestamp: number;
|
|
24
26
|
/** Source device ID (e.g., "cnx-c635", "hid-054c-5c4") */
|
|
25
27
|
deviceId?: string;
|
|
@@ -46,6 +48,8 @@ interface DeviceInfo$1 {
|
|
|
46
48
|
axisLabels?: string[];
|
|
47
49
|
/** Number of buttons this device provides */
|
|
48
50
|
buttonCount?: number;
|
|
51
|
+
/** Human-readable labels for buttons (indexed by targetButton) */
|
|
52
|
+
buttonLabels?: string[];
|
|
49
53
|
}
|
|
50
54
|
type ConnectionState = "disconnected" | "connecting" | "connected" | "failed";
|
|
51
55
|
type TransportProtocol = "webtransport" | "websocket" | "none";
|
|
@@ -111,7 +115,7 @@ declare class SatMouseConnection extends TypedEmitter<SatMouseEvents> {
|
|
|
111
115
|
}
|
|
112
116
|
|
|
113
117
|
/** Axis identifier — full or half */
|
|
114
|
-
type InputAxis = "tx" | "ty" | "tz" | "rx" | "ry" | "rz" | "tx+" | "ty+" | "tz+" | "rx+" | "ry+" | "rz+" | "tx-" | "ty-" | "tz-" | "rx-" | "ry-" | "rz-";
|
|
118
|
+
type InputAxis = "tx" | "ty" | "tz" | "rx" | "ry" | "rz" | "w" | "tx+" | "ty+" | "tz+" | "rx+" | "ry+" | "rz+" | "w+" | "tx-" | "ty-" | "tz-" | "rx-" | "ry-" | "rz-" | "w-";
|
|
115
119
|
/** A single axis route — reads from source, writes to target */
|
|
116
120
|
interface AxisRoute {
|
|
117
121
|
source: InputAxis;
|
|
@@ -120,12 +124,27 @@ interface AxisRoute {
|
|
|
120
124
|
flip?: boolean;
|
|
121
125
|
}
|
|
122
126
|
|
|
127
|
+
/** Maps a device button to a keyboard key */
|
|
128
|
+
interface ButtonRoute {
|
|
129
|
+
/** Device button index */
|
|
130
|
+
button: number;
|
|
131
|
+
/** Keyboard key value (KeyboardEvent.key, e.g., "a", "Shift", "ArrowUp") */
|
|
132
|
+
key: string;
|
|
133
|
+
/** Keyboard code (KeyboardEvent.code, e.g., "KeyA", "ShiftLeft"). Optional. */
|
|
134
|
+
code?: string;
|
|
135
|
+
}
|
|
123
136
|
/** Per-device configuration */
|
|
124
137
|
interface DeviceConfig {
|
|
125
138
|
/** Axis routing — each entry maps a device input to an output with optional flip */
|
|
126
139
|
routes?: AxisRoute[];
|
|
127
|
-
/**
|
|
128
|
-
|
|
140
|
+
/** Button-to-key mappings */
|
|
141
|
+
buttonRoutes?: ButtonRoute[];
|
|
142
|
+
/** Scale multiplier for translation axes (tx, ty, tz) */
|
|
143
|
+
translateScale?: number;
|
|
144
|
+
/** Scale multiplier for rotation axes (rx, ry, rz) */
|
|
145
|
+
rotateScale?: number;
|
|
146
|
+
/** Scale multiplier for W axis */
|
|
147
|
+
wScale?: number;
|
|
129
148
|
/** Dead zone threshold (0-1). Values below this are zeroed. */
|
|
130
149
|
deadZone?: number;
|
|
131
150
|
/** Only pass the strongest axis, zero all others */
|
|
@@ -135,8 +154,14 @@ interface DeviceConfig {
|
|
|
135
154
|
interface InputConfig {
|
|
136
155
|
/** Default axis routes (used when device has no override) */
|
|
137
156
|
routes: AxisRoute[];
|
|
138
|
-
/** Default
|
|
139
|
-
|
|
157
|
+
/** Default button-to-key mappings */
|
|
158
|
+
buttonRoutes: ButtonRoute[];
|
|
159
|
+
/** Scale multiplier for translation axes */
|
|
160
|
+
translateScale: number;
|
|
161
|
+
/** Scale multiplier for rotation axes */
|
|
162
|
+
rotateScale: number;
|
|
163
|
+
/** Scale multiplier for W axis */
|
|
164
|
+
wScale: number;
|
|
140
165
|
/** Dead zone threshold */
|
|
141
166
|
deadZone: number;
|
|
142
167
|
/** Dominant axis mode */
|
|
@@ -201,6 +226,10 @@ declare class InputManager extends TypedEmitter<InputManagerEvents> {
|
|
|
201
226
|
private processPerDevice;
|
|
202
227
|
/** Get the effective routes for a device: device config override > device axes metadata > global default */
|
|
203
228
|
private resolveRoutes;
|
|
229
|
+
/** Dispatch KeyboardEvents for button routes matching this button event */
|
|
230
|
+
private dispatchButtonKeys;
|
|
231
|
+
/** Gather all button routes from global config + all device configs */
|
|
232
|
+
private collectButtonRoutes;
|
|
204
233
|
}
|
|
205
234
|
|
|
206
235
|
interface SatMouseContextValue {
|
package/dist/react/index.js
CHANGED
|
@@ -472,35 +472,45 @@ function readAxis(data, axis) {
|
|
|
472
472
|
return data.rotation.y;
|
|
473
473
|
case "rz":
|
|
474
474
|
return data.rotation.z;
|
|
475
|
+
case "w":
|
|
476
|
+
return data.w ?? 0;
|
|
475
477
|
default:
|
|
476
478
|
return 0;
|
|
477
479
|
}
|
|
478
480
|
}
|
|
479
|
-
function writeAxis(
|
|
481
|
+
function writeAxis(acc, axis, value) {
|
|
480
482
|
const isNeg = axis.endsWith("-");
|
|
481
483
|
const base = axis.replace(/[+-]$/, "");
|
|
482
484
|
const sign = isNeg ? -1 : 1;
|
|
485
|
+
if (base === "w") {
|
|
486
|
+
acc.w += value * sign;
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
483
489
|
const group = base[0];
|
|
484
490
|
const key = base[1];
|
|
485
|
-
if (group === "t") t[key] += value * sign;
|
|
486
|
-
else r[key] += value * sign;
|
|
491
|
+
if (group === "t") acc.t[key] += value * sign;
|
|
492
|
+
else acc.r[key] += value * sign;
|
|
487
493
|
}
|
|
488
|
-
function applyRoutes(data, routes,
|
|
489
|
-
const
|
|
490
|
-
const r = { x: 0, y: 0, z: 0 };
|
|
494
|
+
function applyRoutes(data, routes, translateScale = 1, rotateScale = 1, wScale = 1) {
|
|
495
|
+
const acc = { t: { x: 0, y: 0, z: 0 }, r: { x: 0, y: 0, z: 0 }, w: 0 };
|
|
491
496
|
for (const route of routes) {
|
|
492
497
|
let value = readAxis(data, route.source);
|
|
493
498
|
if (route.flip) value = -value;
|
|
499
|
+
const targetBase = route.target.replace(/[+-]$/, "");
|
|
500
|
+
const scale = targetBase === "w" ? wScale : targetBase[0] === "t" ? translateScale : rotateScale;
|
|
494
501
|
value *= scale;
|
|
495
|
-
writeAxis(
|
|
502
|
+
writeAxis(acc, route.target, value);
|
|
496
503
|
}
|
|
497
|
-
return { translation: t, rotation: r, timestamp: data.timestamp, deviceId: data.deviceId };
|
|
504
|
+
return { translation: acc.t, rotation: acc.r, w: acc.w || void 0, timestamp: data.timestamp, deviceId: data.deviceId };
|
|
498
505
|
}
|
|
499
506
|
|
|
500
507
|
// src/utils/config.ts
|
|
501
508
|
var DEFAULT_CONFIG = {
|
|
502
509
|
routes: DEFAULT_ROUTES,
|
|
503
|
-
|
|
510
|
+
buttonRoutes: [],
|
|
511
|
+
translateScale: 1e-3,
|
|
512
|
+
rotateScale: 1e-3,
|
|
513
|
+
wScale: 1e-3,
|
|
504
514
|
deadZone: 0,
|
|
505
515
|
dominant: false,
|
|
506
516
|
lockPosition: false,
|
|
@@ -534,6 +544,7 @@ function mergeConfig(base, partial) {
|
|
|
534
544
|
...base,
|
|
535
545
|
...partial,
|
|
536
546
|
routes: partial.routes ?? [...base.routes],
|
|
547
|
+
buttonRoutes: partial.buttonRoutes ?? [...base.buttonRoutes],
|
|
537
548
|
devices: { ...base.devices }
|
|
538
549
|
};
|
|
539
550
|
if (partial.devices) {
|
|
@@ -559,7 +570,10 @@ function resolveDeviceConfig(config, deviceId) {
|
|
|
559
570
|
return {
|
|
560
571
|
...config,
|
|
561
572
|
routes: deviceOverride.routes ?? config.routes,
|
|
562
|
-
|
|
573
|
+
buttonRoutes: deviceOverride.buttonRoutes ?? config.buttonRoutes,
|
|
574
|
+
translateScale: deviceOverride.translateScale ?? config.translateScale,
|
|
575
|
+
rotateScale: deviceOverride.rotateScale ?? config.rotateScale,
|
|
576
|
+
wScale: deviceOverride.wScale ?? config.wScale,
|
|
563
577
|
deadZone: deviceOverride.deadZone ?? config.deadZone,
|
|
564
578
|
dominant: deviceOverride.dominant ?? config.dominant
|
|
565
579
|
};
|
|
@@ -663,7 +677,10 @@ var InputManager = class extends TypedEmitter {
|
|
|
663
677
|
const resolved = resolveDeviceConfig(this._config, deviceId);
|
|
664
678
|
return {
|
|
665
679
|
routes: resolved.routes,
|
|
666
|
-
|
|
680
|
+
buttonRoutes: resolved.buttonRoutes,
|
|
681
|
+
translateScale: resolved.translateScale,
|
|
682
|
+
rotateScale: resolved.rotateScale,
|
|
683
|
+
wScale: resolved.wScale,
|
|
667
684
|
deadZone: resolved.deadZone,
|
|
668
685
|
dominant: resolved.dominant
|
|
669
686
|
};
|
|
@@ -711,11 +728,15 @@ var InputManager = class extends TypedEmitter {
|
|
|
711
728
|
tz: processed.translation.z,
|
|
712
729
|
rx: processed.rotation.x,
|
|
713
730
|
ry: processed.rotation.y,
|
|
714
|
-
rz: processed.rotation.z
|
|
731
|
+
rz: processed.rotation.z,
|
|
732
|
+
w: processed.w ?? 0
|
|
715
733
|
});
|
|
716
734
|
this.accDirty = true;
|
|
717
735
|
});
|
|
718
|
-
connection.on("buttonEvent", (event) =>
|
|
736
|
+
connection.on("buttonEvent", (event) => {
|
|
737
|
+
this.dispatchButtonKeys(event);
|
|
738
|
+
this.emit("buttonEvent", event);
|
|
739
|
+
});
|
|
719
740
|
connection.on("stateChange", (state, proto) => {
|
|
720
741
|
this._state = state;
|
|
721
742
|
this._protocol = proto;
|
|
@@ -729,7 +750,7 @@ var InputManager = class extends TypedEmitter {
|
|
|
729
750
|
}
|
|
730
751
|
flushAccumulator() {
|
|
731
752
|
if (!this.accDirty) return;
|
|
732
|
-
const merged = { tx: 0, ty: 0, tz: 0, rx: 0, ry: 0, rz: 0 };
|
|
753
|
+
const merged = { tx: 0, ty: 0, tz: 0, rx: 0, ry: 0, rz: 0, w: 0 };
|
|
733
754
|
for (const acc of this.deviceAccumulators.values()) {
|
|
734
755
|
merged.tx += acc.tx;
|
|
735
756
|
merged.ty += acc.ty;
|
|
@@ -737,12 +758,14 @@ var InputManager = class extends TypedEmitter {
|
|
|
737
758
|
merged.rx += acc.rx;
|
|
738
759
|
merged.ry += acc.ry;
|
|
739
760
|
merged.rz += acc.rz;
|
|
761
|
+
merged.w += acc.w;
|
|
740
762
|
}
|
|
741
763
|
this.deviceAccumulators.clear();
|
|
742
764
|
this.accDirty = false;
|
|
743
765
|
let data = {
|
|
744
766
|
translation: { x: merged.tx, y: merged.ty, z: merged.tz },
|
|
745
767
|
rotation: { x: merged.rx, y: merged.ry, z: merged.rz },
|
|
768
|
+
w: merged.w || void 0,
|
|
746
769
|
timestamp: performance.now() * 1e3
|
|
747
770
|
};
|
|
748
771
|
if (this._config.lockPosition) {
|
|
@@ -783,7 +806,7 @@ var InputManager = class extends TypedEmitter {
|
|
|
783
806
|
}
|
|
784
807
|
const device = this.knownDevices.get(deviceId);
|
|
785
808
|
const deviceRoutes = this.resolveRoutes(deviceId, device);
|
|
786
|
-
data = applyRoutes(data, deviceRoutes, cfg.
|
|
809
|
+
data = applyRoutes(data, deviceRoutes, cfg.translateScale, cfg.rotateScale, cfg.wScale);
|
|
787
810
|
return data;
|
|
788
811
|
}
|
|
789
812
|
/** Get the effective routes for a device: device config override > device axes metadata > global default */
|
|
@@ -798,6 +821,27 @@ var InputManager = class extends TypedEmitter {
|
|
|
798
821
|
if (device?.axes) return buildRoutes(device.axes);
|
|
799
822
|
return DEFAULT_ROUTES;
|
|
800
823
|
}
|
|
824
|
+
/** Dispatch KeyboardEvents for button routes matching this button event */
|
|
825
|
+
dispatchButtonKeys(event) {
|
|
826
|
+
if (typeof document === "undefined") return;
|
|
827
|
+
const allRoutes = this.collectButtonRoutes();
|
|
828
|
+
for (const route of allRoutes) {
|
|
829
|
+
if (route.button === event.button) {
|
|
830
|
+
document.dispatchEvent(new KeyboardEvent(
|
|
831
|
+
event.pressed ? "keydown" : "keyup",
|
|
832
|
+
{ key: route.key, code: route.code ?? "", bubbles: true }
|
|
833
|
+
));
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
/** Gather all button routes from global config + all device configs */
|
|
838
|
+
collectButtonRoutes() {
|
|
839
|
+
const routes = [...this._config.buttonRoutes];
|
|
840
|
+
for (const devCfg of Object.values(this._config.devices)) {
|
|
841
|
+
if (devCfg.buttonRoutes) routes.push(...devCfg.buttonRoutes);
|
|
842
|
+
}
|
|
843
|
+
return routes;
|
|
844
|
+
}
|
|
801
845
|
};
|
|
802
846
|
var SatMouseContext = createContext(null);
|
|
803
847
|
function SatMouseProvider({
|