dualsense-ts 6.2.0 → 6.4.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/LINUX_HID.md +85 -0
- package/README.md +83 -12
- package/dist/dualsense.d.ts +28 -8
- package/dist/dualsense.d.ts.map +1 -1
- package/dist/dualsense.js +57 -17
- package/dist/dualsense.js.map +1 -1
- package/dist/hid/bt_checksum.d.ts +7 -0
- package/dist/hid/bt_checksum.d.ts.map +1 -1
- package/dist/hid/bt_checksum.js +33 -1
- package/dist/hid/bt_checksum.js.map +1 -1
- package/dist/hid/dualsense_hid.d.ts +77 -0
- package/dist/hid/dualsense_hid.d.ts.map +1 -1
- package/dist/hid/dualsense_hid.js +193 -0
- package/dist/hid/dualsense_hid.js.map +1 -1
- package/dist/hid/factory_info.d.ts +53 -0
- package/dist/hid/factory_info.d.ts.map +1 -0
- package/dist/hid/factory_info.js +166 -0
- package/dist/hid/factory_info.js.map +1 -0
- package/dist/hid/firmware_info.d.ts +46 -0
- package/dist/hid/firmware_info.d.ts.map +1 -0
- package/dist/hid/firmware_info.js +109 -0
- package/dist/hid/firmware_info.js.map +1 -0
- package/dist/hid/hid_provider.d.ts +12 -0
- package/dist/hid/hid_provider.d.ts.map +1 -1
- package/dist/hid/hid_provider.js +13 -0
- package/dist/hid/hid_provider.js.map +1 -1
- package/dist/hid/index.d.ts +3 -0
- package/dist/hid/index.d.ts.map +1 -1
- package/dist/hid/index.js +3 -0
- package/dist/hid/index.js.map +1 -1
- package/dist/hid/node_hid_provider.d.ts +2 -0
- package/dist/hid/node_hid_provider.d.ts.map +1 -1
- package/dist/hid/node_hid_provider.js +14 -0
- package/dist/hid/node_hid_provider.js.map +1 -1
- package/dist/hid/pairing_info.d.ts +9 -0
- package/dist/hid/pairing_info.d.ts.map +1 -0
- package/dist/hid/pairing_info.js +33 -0
- package/dist/hid/pairing_info.js.map +1 -0
- package/dist/hid/web_hid_provider.d.ts +14 -0
- package/dist/hid/web_hid_provider.d.ts.map +1 -1
- package/dist/hid/web_hid_provider.js +79 -8
- package/dist/hid/web_hid_provider.js.map +1 -1
- package/dist/id.d.ts +4 -0
- package/dist/id.d.ts.map +1 -1
- package/dist/manager.d.ts +57 -4
- package/dist/manager.d.ts.map +1 -1
- package/dist/manager.js +248 -66
- package/dist/manager.js.map +1 -1
- package/nodehid_example/debug.ts +43 -13
- package/nodehid_example/single.ts +29 -0
- package/package.json +1 -1
- package/src/dualsense.ts +73 -23
- package/src/hid/bt_checksum.ts +39 -0
- package/src/hid/dualsense_hid.ts +230 -0
- package/src/hid/factory_info.ts +206 -0
- package/src/hid/firmware_info.ts +157 -0
- package/src/hid/hid_provider.ts +22 -0
- package/src/hid/index.ts +3 -0
- package/src/hid/node_hid_provider.ts +14 -0
- package/src/hid/pairing_info.ts +33 -0
- package/src/hid/web_hid_provider.ts +87 -8
- package/src/id.ts +5 -0
- package/src/manager.ts +285 -71
- package/webhid_example/build/asset-manifest.json +3 -3
- package/webhid_example/build/index.html +1 -1
- package/webhid_example/build/static/js/main.1c1a2c23.js +3 -0
- package/webhid_example/build/static/js/main.1c1a2c23.js.map +1 -0
- package/webhid_example/src/App.tsx +7 -1
- package/webhid_example/src/hud/AudioIndicator.tsx +116 -0
- package/webhid_example/src/hud/BatteryIndicator.tsx +4 -2
- package/webhid_example/src/hud/ColorIndicator.tsx +72 -0
- package/webhid_example/src/hud/ControllerConnection.tsx +29 -2
- package/webhid_example/src/hud/Debugger.tsx +31 -1
- package/webhid_example/src/hud/LightbarFadeButtons.tsx +2 -2
- package/webhid_example/src/hud/MuteLedControls.tsx +3 -2
- package/webhid_example/src/hud/index.tsx +2 -0
- package/webhid_example/build/static/js/main.2ac31d24.js +0 -3
- package/webhid_example/build/static/js/main.2ac31d24.js.map +0 -1
- /package/webhid_example/build/static/js/{main.2ac31d24.js.LICENSE.txt → main.1c1a2c23.js.LICENSE.txt} +0 -0
package/dist/manager.js
CHANGED
|
@@ -72,10 +72,20 @@ class DualsenseManager extends input_1.Input {
|
|
|
72
72
|
this.playerPatterns = [...DEFAULT_PLAYER_PATTERNS];
|
|
73
73
|
/** All controller slots, indexed by slot number */
|
|
74
74
|
this.slots = [];
|
|
75
|
-
/** Map from serial
|
|
75
|
+
/** Map from node-hid serial to slot index — best-effort, used as a fallback */
|
|
76
76
|
this.serialToSlot = new Map();
|
|
77
|
+
/** Map from canonical hardware identity to slot index — preferred when available */
|
|
78
|
+
this.identityToSlot = new Map();
|
|
77
79
|
/** Whether we're running in a browser environment */
|
|
78
80
|
this.isBrowser = typeof window !== "undefined";
|
|
81
|
+
// --- Private ---
|
|
82
|
+
/** Previous state snapshot, for deduplication */
|
|
83
|
+
this.lastActive = 0;
|
|
84
|
+
this.lastPlayerCount = 0;
|
|
85
|
+
/** Fingerprint of the last published player set (slot indices + connected flags) */
|
|
86
|
+
this.lastPlayerKey = "";
|
|
87
|
+
/** HIDDevice objects we've already handed to a provider */
|
|
88
|
+
this.knownWebDevices = new WeakSet();
|
|
79
89
|
this.autoAssignPlayerLeds = params.autoAssignPlayerLeds ?? true;
|
|
80
90
|
if (this.isBrowser) {
|
|
81
91
|
this.startWebDiscovery();
|
|
@@ -87,21 +97,41 @@ class DualsenseManager extends input_1.Input {
|
|
|
87
97
|
get active() {
|
|
88
98
|
return this.state.active > 0;
|
|
89
99
|
}
|
|
90
|
-
/**
|
|
100
|
+
/**
|
|
101
|
+
* All managed controller instances (including disconnected ones awaiting
|
|
102
|
+
* reconnection). Excludes provisional slots whose identity is still being
|
|
103
|
+
* resolved — those become visible only after firmware info loads, to
|
|
104
|
+
* avoid surfacing controllers that may be merged into an existing slot.
|
|
105
|
+
*/
|
|
91
106
|
get controllers() {
|
|
92
|
-
return this.
|
|
107
|
+
return this.publicSlots().map((s) => s.controller);
|
|
93
108
|
}
|
|
94
109
|
/** Number of managed controllers (including disconnected ones awaiting reconnection) */
|
|
95
110
|
get count() {
|
|
96
|
-
return this.
|
|
111
|
+
return this.publicSlots().length;
|
|
97
112
|
}
|
|
98
113
|
/** Get a controller by slot index */
|
|
99
114
|
get(index) {
|
|
100
|
-
|
|
115
|
+
const slot = this.slots[index];
|
|
116
|
+
if (!slot || slot.provisional)
|
|
117
|
+
return undefined;
|
|
118
|
+
return slot.controller;
|
|
101
119
|
}
|
|
102
120
|
/** Iterate over all managed controllers */
|
|
103
121
|
[Symbol.iterator]() {
|
|
104
|
-
return this.
|
|
122
|
+
return this.publicSlots().map((s) => s.controller).values();
|
|
123
|
+
}
|
|
124
|
+
/** Slots that are visible to the consumer (i.e. identity has been resolved) */
|
|
125
|
+
publicSlots() {
|
|
126
|
+
return this.slots.filter((s) => !s.provisional);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* True while at least one controller has been discovered but is still
|
|
130
|
+
* waiting for firmware info to load. Useful for showing a "connecting"
|
|
131
|
+
* state in the UI without surfacing the unresolved slot itself.
|
|
132
|
+
*/
|
|
133
|
+
get pending() {
|
|
134
|
+
return this.slots.some((s) => s.provisional);
|
|
105
135
|
}
|
|
106
136
|
/**
|
|
107
137
|
* Override the player LED pattern for a given slot index.
|
|
@@ -131,16 +161,22 @@ class DualsenseManager extends input_1.Input {
|
|
|
131
161
|
return;
|
|
132
162
|
// Disconnect the HID provider and release the claimed device
|
|
133
163
|
slot.controller.hid.provider.disconnect();
|
|
134
|
-
// Remove serial
|
|
164
|
+
// Remove identity / serial mappings
|
|
165
|
+
if (slot.identity) {
|
|
166
|
+
this.identityToSlot.delete(slot.identity);
|
|
167
|
+
}
|
|
135
168
|
if (slot.serial) {
|
|
136
169
|
this.serialToSlot.delete(slot.serial);
|
|
137
170
|
}
|
|
138
171
|
// Remove the slot (shift remaining slots down)
|
|
139
172
|
this.slots.splice(index, 1);
|
|
140
|
-
// Re-index serial mappings after splice
|
|
173
|
+
// Re-index identity / serial mappings after splice
|
|
141
174
|
for (let i = index; i < this.slots.length; i++) {
|
|
142
175
|
const s = this.slots[i];
|
|
143
176
|
s.index = i;
|
|
177
|
+
if (s.identity) {
|
|
178
|
+
this.identityToSlot.set(s.identity, i);
|
|
179
|
+
}
|
|
144
180
|
if (s.serial) {
|
|
145
181
|
this.serialToSlot.set(s.serial, i);
|
|
146
182
|
}
|
|
@@ -186,51 +222,64 @@ class DualsenseManager extends input_1.Input {
|
|
|
186
222
|
}
|
|
187
223
|
return web_hid_provider_1.WebHIDProvider.getMultiRequest((device) => { this.addWebDevice(device); });
|
|
188
224
|
}
|
|
189
|
-
// --- Private ---
|
|
190
225
|
/** Build a new state snapshot and push it through InputSet */
|
|
191
226
|
updateState() {
|
|
192
227
|
const players = new Map();
|
|
228
|
+
let activeCount = 0;
|
|
229
|
+
let key = "";
|
|
193
230
|
for (const slot of this.slots) {
|
|
231
|
+
if (slot.provisional)
|
|
232
|
+
continue;
|
|
194
233
|
players.set(slot.index, slot.controller);
|
|
234
|
+
const connected = slot.controller.connection.active;
|
|
235
|
+
if (connected)
|
|
236
|
+
activeCount += 1;
|
|
237
|
+
key += `${slot.index}:${connected ? "1" : "0"},`;
|
|
195
238
|
}
|
|
196
|
-
|
|
197
|
-
//
|
|
239
|
+
// Suppress no-op publishes (e.g. provisional slots churning without
|
|
240
|
+
// changing the visible state) to avoid noisy change events.
|
|
241
|
+
if (activeCount === this.lastActive &&
|
|
242
|
+
players.size === this.lastPlayerCount &&
|
|
243
|
+
key === this.lastPlayerKey) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
this.lastActive = activeCount;
|
|
247
|
+
this.lastPlayerCount = players.size;
|
|
248
|
+
this.lastPlayerKey = key;
|
|
198
249
|
this[input_1.InputSet]({ active: activeCount, players });
|
|
199
250
|
}
|
|
200
|
-
/**
|
|
251
|
+
/**
|
|
252
|
+
* Create a Dualsense instance and register it in a (provisional) slot.
|
|
253
|
+
* The caller is responsible for opening the device on the provider — the
|
|
254
|
+
* manager treats this as the *only* path that opens new devices, so
|
|
255
|
+
* identity matching can run before the slot becomes visible.
|
|
256
|
+
*
|
|
257
|
+
* Note: identity is the sole reconnection key. We do NOT key on node-hid's
|
|
258
|
+
* serialNumber because it's frequently missing or wrong (especially over
|
|
259
|
+
* Bluetooth on Linux). Path is tracked only so we can re-target the same
|
|
260
|
+
* device on transplant.
|
|
261
|
+
*/
|
|
201
262
|
createSlot(provider, serial, path) {
|
|
202
|
-
// Check if this serial already has a slot (reconnection)
|
|
203
|
-
if (serial) {
|
|
204
|
-
const existingIndex = this.serialToSlot.get(serial);
|
|
205
|
-
if (existingIndex !== undefined) {
|
|
206
|
-
const existingSlot = this.slots[existingIndex];
|
|
207
|
-
if (existingSlot && !existingSlot.controller.connection.active) {
|
|
208
|
-
// Reconnect to existing slot: update the provider target
|
|
209
|
-
if (provider instanceof node_hid_provider_1.NodeHIDProvider) {
|
|
210
|
-
const existingProvider = existingSlot.controller.hid
|
|
211
|
-
.provider;
|
|
212
|
-
existingProvider.targetPath = path;
|
|
213
|
-
existingProvider.targetSerial = serial;
|
|
214
|
-
}
|
|
215
|
-
existingSlot.path = path;
|
|
216
|
-
// Release the new provider since we're reusing the existing one
|
|
217
|
-
provider.disconnect();
|
|
218
|
-
return existingSlot;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
263
|
const hid = new dualsense_hid_1.DualsenseHID(provider);
|
|
223
264
|
const controller = new dualsense_1.Dualsense({ hid });
|
|
224
265
|
const index = this.slots.length;
|
|
225
|
-
const slot = {
|
|
266
|
+
const slot = {
|
|
267
|
+
controller,
|
|
268
|
+
serial,
|
|
269
|
+
path,
|
|
270
|
+
index,
|
|
271
|
+
// Hide from public state until firmware info has been read and any
|
|
272
|
+
// identity-based merge has had a chance to run.
|
|
273
|
+
provisional: true,
|
|
274
|
+
};
|
|
226
275
|
this.slots.push(slot);
|
|
227
276
|
if (serial) {
|
|
228
277
|
this.serialToSlot.set(serial, index);
|
|
229
278
|
}
|
|
230
|
-
// Assign player LEDs —
|
|
231
|
-
//
|
|
279
|
+
// Assign player LEDs — skip for provisional slots (they may get
|
|
280
|
+
// transplanted to a different index). Re-apply on every connect.
|
|
232
281
|
const applyPlayerLeds = () => {
|
|
233
|
-
if (this.autoAssignPlayerLeds) {
|
|
282
|
+
if (this.autoAssignPlayerLeds && !slot.provisional) {
|
|
234
283
|
controller.playerLeds.set(this.playerPatterns[slot.index] ?? 0);
|
|
235
284
|
}
|
|
236
285
|
};
|
|
@@ -242,9 +291,140 @@ class DualsenseManager extends input_1.Input {
|
|
|
242
291
|
}
|
|
243
292
|
this.updateState();
|
|
244
293
|
});
|
|
294
|
+
// Hook firmware-info readiness so we can perform identity-based slot
|
|
295
|
+
// matching once the controller's hardware identity is known. This is
|
|
296
|
+
// far more reliable than node-hid's serial number, which is
|
|
297
|
+
// frequently missing or wrong (especially over Bluetooth on Linux).
|
|
298
|
+
if (!slot.readyHooked) {
|
|
299
|
+
slot.readyHooked = true;
|
|
300
|
+
hid.onReady(() => this.handleSlotReady(slot));
|
|
301
|
+
}
|
|
245
302
|
this.updateState();
|
|
246
303
|
return slot;
|
|
247
304
|
}
|
|
305
|
+
/**
|
|
306
|
+
* Called when a slot's HID layer has finished reading firmware/factory info.
|
|
307
|
+
* If the resolved identity matches a *different* (disconnected) slot, the
|
|
308
|
+
* underlying device is transplanted into that slot's existing provider so
|
|
309
|
+
* the consumer's Dualsense reference is preserved across reconnect.
|
|
310
|
+
*/
|
|
311
|
+
handleSlotReady(slot) {
|
|
312
|
+
const identity = slot.controller.hid.identity;
|
|
313
|
+
// No identity at all (firmware read failed completely after retries) —
|
|
314
|
+
// promote the slot anyway so the consumer can still use it. We just
|
|
315
|
+
// won't be able to merge it on reconnect.
|
|
316
|
+
if (!identity) {
|
|
317
|
+
this.promoteSlot(slot);
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
const existingIndex = this.identityToSlot.get(identity);
|
|
321
|
+
// First time we've seen this identity — claim it for this slot.
|
|
322
|
+
if (existingIndex === undefined) {
|
|
323
|
+
slot.identity = identity;
|
|
324
|
+
this.identityToSlot.set(identity, slot.index);
|
|
325
|
+
this.promoteSlot(slot);
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
// We already have a slot for this identity — make sure it's not just us.
|
|
329
|
+
if (existingIndex === slot.index) {
|
|
330
|
+
this.promoteSlot(slot);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
const existingSlot = this.slots[existingIndex];
|
|
334
|
+
if (!existingSlot) {
|
|
335
|
+
// Stale mapping — overwrite.
|
|
336
|
+
slot.identity = identity;
|
|
337
|
+
this.identityToSlot.set(identity, slot.index);
|
|
338
|
+
this.promoteSlot(slot);
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
// If the existing slot is currently connected, both slots map to the
|
|
342
|
+
// same hardware (shouldn't normally happen). Prefer the older slot
|
|
343
|
+
// and drop the new one without ever publishing it.
|
|
344
|
+
if (existingSlot.controller.connection.active) {
|
|
345
|
+
this.dropSlot(slot);
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
// Existing slot is disconnected — transplant the new device into it.
|
|
349
|
+
// The new (provisional) slot is dropped before any state is published,
|
|
350
|
+
// so the consumer only ever sees the original slot reconnect in place.
|
|
351
|
+
this.transplant(slot, existingSlot);
|
|
352
|
+
}
|
|
353
|
+
/** Mark a slot as visible to consumers and publish state */
|
|
354
|
+
promoteSlot(slot) {
|
|
355
|
+
if (!slot.provisional)
|
|
356
|
+
return;
|
|
357
|
+
slot.provisional = false;
|
|
358
|
+
if (this.autoAssignPlayerLeds) {
|
|
359
|
+
slot.controller.playerLeds.set(this.playerPatterns[slot.index] ?? 0);
|
|
360
|
+
}
|
|
361
|
+
this.updateState();
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Move the device handle from `from` into `into`'s existing provider so
|
|
365
|
+
* the existing Dualsense instance reconnects in place. Then remove `from`.
|
|
366
|
+
*/
|
|
367
|
+
transplant(from, into) {
|
|
368
|
+
const fromProvider = from.controller.hid.provider;
|
|
369
|
+
const intoProvider = into.controller.hid.provider;
|
|
370
|
+
if (fromProvider instanceof web_hid_provider_1.WebHIDProvider &&
|
|
371
|
+
intoProvider instanceof web_hid_provider_1.WebHIDProvider &&
|
|
372
|
+
fromProvider.device) {
|
|
373
|
+
// Move the open HIDDevice handle from the source provider to the
|
|
374
|
+
// destination. We can't close + reopen here — that would race with
|
|
375
|
+
// the destination's attach() call. Instead we abandon the source
|
|
376
|
+
// provider in place (its slot is about to be dropped) and let the
|
|
377
|
+
// destination take over the same handle. The source's input listener
|
|
378
|
+
// will be GC'd along with the source provider once nothing else
|
|
379
|
+
// references the dropped slot's Dualsense.
|
|
380
|
+
const device = fromProvider.device;
|
|
381
|
+
fromProvider.device = undefined;
|
|
382
|
+
if (fromProvider.deviceId) {
|
|
383
|
+
hid_provider_1.HIDProvider.claimedDevices.delete(fromProvider.deviceId);
|
|
384
|
+
fromProvider.deviceId = undefined;
|
|
385
|
+
}
|
|
386
|
+
intoProvider.replaceDevice(device);
|
|
387
|
+
}
|
|
388
|
+
else if (fromProvider instanceof node_hid_provider_1.NodeHIDProvider &&
|
|
389
|
+
intoProvider instanceof node_hid_provider_1.NodeHIDProvider) {
|
|
390
|
+
// node-hid HID handles can't be moved between providers, so we close
|
|
391
|
+
// the source (releasing its path claim) and re-open the same path on
|
|
392
|
+
// the destination provider — preserving the existing Dualsense
|
|
393
|
+
// instance and its subscribers.
|
|
394
|
+
const newPath = from.path;
|
|
395
|
+
const newSerial = from.serial;
|
|
396
|
+
fromProvider.disconnect();
|
|
397
|
+
intoProvider.targetPath = newPath;
|
|
398
|
+
intoProvider.targetSerial = newSerial;
|
|
399
|
+
into.path = newPath;
|
|
400
|
+
into.serial = newSerial;
|
|
401
|
+
void Promise.resolve(intoProvider.connect()).catch(() => {
|
|
402
|
+
/* errors surface via provider.onError */
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
this.dropSlot(from);
|
|
406
|
+
}
|
|
407
|
+
/** Remove a slot without firing the player-LED reshuffle */
|
|
408
|
+
dropSlot(slot) {
|
|
409
|
+
const idx = this.slots.indexOf(slot);
|
|
410
|
+
if (idx === -1)
|
|
411
|
+
return;
|
|
412
|
+
if (slot.identity)
|
|
413
|
+
this.identityToSlot.delete(slot.identity);
|
|
414
|
+
if (slot.serial)
|
|
415
|
+
this.serialToSlot.delete(slot.serial);
|
|
416
|
+
this.slots.splice(idx, 1);
|
|
417
|
+
// Re-index the trailing slots
|
|
418
|
+
for (let i = idx; i < this.slots.length; i++) {
|
|
419
|
+
const s = this.slots[i];
|
|
420
|
+
s.index = i;
|
|
421
|
+
if (s.identity)
|
|
422
|
+
this.identityToSlot.set(s.identity, i);
|
|
423
|
+
if (s.serial)
|
|
424
|
+
this.serialToSlot.set(s.serial, i);
|
|
425
|
+
}
|
|
426
|
+
this.updateState();
|
|
427
|
+
}
|
|
248
428
|
// --- Node.js discovery ---
|
|
249
429
|
startNodeDiscovery(intervalMs) {
|
|
250
430
|
const poll = async () => {
|
|
@@ -262,32 +442,27 @@ class DualsenseManager extends input_1.Input {
|
|
|
262
442
|
void poll();
|
|
263
443
|
this.discoveryTimer = setInterval(() => void poll(), intervalMs);
|
|
264
444
|
}
|
|
265
|
-
/**
|
|
445
|
+
/**
|
|
446
|
+
* Handle a newly discovered device from enumeration. Opens the device on
|
|
447
|
+
* a fresh provider, which adds it to `claimedDevices` so subsequent polls
|
|
448
|
+
* skip it. Identity matching (and any merge into a disconnected slot)
|
|
449
|
+
* happens later, once firmware info has been read.
|
|
450
|
+
*/
|
|
266
451
|
processDiscoveredDevice(device) {
|
|
267
452
|
if (hid_provider_1.HIDProvider.claimedDevices.has(device.path))
|
|
268
453
|
return;
|
|
269
|
-
// Check if this serial matches a disconnected slot
|
|
270
|
-
if (device.serialNumber !== undefined) {
|
|
271
|
-
const existingSlotIndex = this.serialToSlot.get(device.serialNumber);
|
|
272
|
-
if (existingSlotIndex !== undefined) {
|
|
273
|
-
const slot = this.slots[existingSlotIndex];
|
|
274
|
-
if (!slot.controller.connection.active) {
|
|
275
|
-
// Update the existing provider to reconnect via this path
|
|
276
|
-
const provider = slot.controller.hid.provider;
|
|
277
|
-
provider.targetPath = device.path;
|
|
278
|
-
provider.targetSerial = device.serialNumber;
|
|
279
|
-
slot.path = device.path;
|
|
280
|
-
// The Dualsense's internal 200ms loop will call provider.connect()
|
|
281
|
-
return;
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
// New device: create a provider and slot
|
|
286
454
|
const provider = new node_hid_provider_1.NodeHIDProvider({
|
|
287
455
|
devicePath: device.path,
|
|
288
456
|
serialNumber: device.serialNumber,
|
|
289
457
|
});
|
|
290
458
|
this.createSlot(provider, device.serialNumber, device.path);
|
|
459
|
+
// Drive the connection. The Dualsense instance no longer polls in
|
|
460
|
+
// managed mode, so the manager owns this. claimedDevices is added
|
|
461
|
+
// synchronously inside connect() on success, preventing duplicate
|
|
462
|
+
// discovery on the next poll tick.
|
|
463
|
+
void Promise.resolve(provider.connect()).catch(() => {
|
|
464
|
+
/* errors surface via provider.onError */
|
|
465
|
+
});
|
|
291
466
|
}
|
|
292
467
|
// --- WebHID discovery ---
|
|
293
468
|
startWebDiscovery() {
|
|
@@ -296,21 +471,28 @@ class DualsenseManager extends input_1.Input {
|
|
|
296
471
|
navigator.hid.addEventListener("connect", ({ device }) => {
|
|
297
472
|
this.addWebDevice(device);
|
|
298
473
|
});
|
|
299
|
-
//
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
474
|
+
// Poll for permitted devices. The WebHID connect event only fires
|
|
475
|
+
// for newly-permitted devices, not for already-permitted devices
|
|
476
|
+
// that physically reconnect. Periodic enumeration catches those.
|
|
477
|
+
const poll = () => {
|
|
478
|
+
void web_hid_provider_1.WebHIDProvider.enumerate().then((devices) => {
|
|
479
|
+
for (const device of devices) {
|
|
480
|
+
this.addWebDevice(device);
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
};
|
|
484
|
+
poll();
|
|
485
|
+
this.discoveryTimer = setInterval(poll, 2000);
|
|
305
486
|
}
|
|
306
487
|
}
|
|
307
488
|
addWebDevice(device) {
|
|
308
|
-
//
|
|
309
|
-
for
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
489
|
+
// WeakSet tracks object identity — enumerate() returns the same objects
|
|
490
|
+
// for still-connected devices, so this deduplicates across polls.
|
|
491
|
+
// On reconnect, the browser provides a fresh HIDDevice object, so it
|
|
492
|
+
// passes this check and creates a new provisional slot.
|
|
493
|
+
if (this.knownWebDevices.has(device))
|
|
494
|
+
return;
|
|
495
|
+
this.knownWebDevices.add(device);
|
|
314
496
|
const provider = new web_hid_provider_1.WebHIDProvider({ device });
|
|
315
497
|
this.createSlot(provider, undefined, undefined);
|
|
316
498
|
}
|
package/dist/manager.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../src/manager.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../src/manager.ts"],"names":[],"mappings":"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"}
|
package/nodehid_example/debug.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Dualsense } from "../src/dualsense";
|
|
|
2
2
|
import { DualsenseManager } from "../src/manager";
|
|
3
3
|
import { TriggerEffect } from "../src/elements/trigger_feedback";
|
|
4
4
|
import { ChargeStatus } from "../src/hid/battery_state";
|
|
5
|
+
import { formatFirmwareVersion } from "../src/hid/firmware_info";
|
|
5
6
|
|
|
6
7
|
/** Map a -1..1 stick value to 0..1 */
|
|
7
8
|
function norm(value: number): number {
|
|
@@ -13,21 +14,42 @@ function log(player: number, ...args: unknown[]) {
|
|
|
13
14
|
console.log(`[P${player + 1}]`, ...args);
|
|
14
15
|
}
|
|
15
16
|
|
|
17
|
+
/** Log transport-level connection details (available immediately) */
|
|
18
|
+
function logConnection(controller: Dualsense, player: number) {
|
|
19
|
+
const connected = controller.connection.active;
|
|
20
|
+
log(
|
|
21
|
+
player,
|
|
22
|
+
`Connected: ${connected ? "yes" : "no"} - ${
|
|
23
|
+
connected ? (controller.wireless ? "bluetooth" : "usb") : ""
|
|
24
|
+
}`,
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Log firmware/factory identity (available after onReady) */
|
|
29
|
+
function logIdentity(controller: Dualsense, player: number) {
|
|
30
|
+
if (controller.hid.identity) {
|
|
31
|
+
log(player, `Identity: ${controller.hid.identity}`);
|
|
32
|
+
}
|
|
33
|
+
const fw = controller.firmwareInfo;
|
|
34
|
+
log(player, `Firmware: v${formatFirmwareVersion(fw.mainFirmwareVersion)} | HW: ${fw.hardwareInfo} | DSP: ${fw.dspFirmwareVersion} | Built: ${fw.buildDate} ${fw.buildTime}`);
|
|
35
|
+
const fi = controller.factoryInfo;
|
|
36
|
+
log(player, `Factory: ${fi.colorName} | ${fi.boardRevision} | Serial: ${fi.serialNumber}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
16
39
|
/** Set up all debug bindings for a single controller */
|
|
17
40
|
function bindController(controller: Dualsense, player: number) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
41
|
+
// Log the current connection state immediately.
|
|
42
|
+
logConnection(controller, player);
|
|
43
|
+
|
|
44
|
+
controller.connection.on("change", () => {
|
|
45
|
+
logConnection(controller, player);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Log identity details once firmware/factory info is available. On
|
|
49
|
+
// initial bind onReady fires synchronously (already resolved). On
|
|
50
|
+
// reconnect it fires after the background verification completes.
|
|
51
|
+
controller.hid.onReady(() => {
|
|
52
|
+
logIdentity(controller, player);
|
|
31
53
|
});
|
|
32
54
|
|
|
33
55
|
// Log battery level on connect and when it changes
|
|
@@ -203,6 +225,14 @@ function bindController(controller: Dualsense, player: number) {
|
|
|
203
225
|
log(player, `Mute LED: ${state ? "on" : "off"}`);
|
|
204
226
|
});
|
|
205
227
|
|
|
228
|
+
// Audio peripherals
|
|
229
|
+
controller.microphone.on("change", ({ state }) => {
|
|
230
|
+
log(player, `Microphone: ${state ? "connected" : "disconnected"}`);
|
|
231
|
+
});
|
|
232
|
+
controller.headphone.on("change", ({ state }) => {
|
|
233
|
+
log(player, `Headphone: ${state ? "connected" : "disconnected"}`);
|
|
234
|
+
});
|
|
235
|
+
|
|
206
236
|
// Log stick positions for reference
|
|
207
237
|
controller.left.analog.on("change", (analog) => {
|
|
208
238
|
log(
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Dualsense } from "../src/dualsense";
|
|
2
2
|
import { TriggerEffect } from "../src/elements/trigger_feedback";
|
|
3
3
|
import { ChargeStatus } from "../src/hid/battery_state";
|
|
4
|
+
import { formatFirmwareVersion } from "../src/hid/firmware_info";
|
|
4
5
|
|
|
5
6
|
/** Map a -1..1 stick value to 0..1 */
|
|
6
7
|
function norm(value: number): number {
|
|
@@ -18,6 +19,26 @@ function main() {
|
|
|
18
19
|
state ? (controller.wireless ? "bluetooth" : "usb") : ""
|
|
19
20
|
}`,
|
|
20
21
|
);
|
|
22
|
+
if (state) {
|
|
23
|
+
setTimeout(() => {
|
|
24
|
+
const fw = controller.firmwareInfo;
|
|
25
|
+
if (fw) {
|
|
26
|
+
console.log(
|
|
27
|
+
`Firmware: v${formatFirmwareVersion(fw.mainFirmwareVersion)} | HW: ${fw.hardwareInfo} | DSP: ${fw.dspFirmwareVersion} | Built: ${fw.buildDate} ${fw.buildTime}`,
|
|
28
|
+
);
|
|
29
|
+
} else {
|
|
30
|
+
console.log("Failed to query device firmware info");
|
|
31
|
+
}
|
|
32
|
+
const fi = controller.factoryInfo;
|
|
33
|
+
if (fi) {
|
|
34
|
+
console.log(
|
|
35
|
+
`Factory: ${fi.colorName ?? fi.colorCode} | ${fi.boardRevision ?? "unknown board"} | Serial: ${fi.serialNumber}`,
|
|
36
|
+
);
|
|
37
|
+
} else {
|
|
38
|
+
console.log("Failed to query device factory info");
|
|
39
|
+
}
|
|
40
|
+
}, 2000);
|
|
41
|
+
}
|
|
21
42
|
});
|
|
22
43
|
|
|
23
44
|
// Battery
|
|
@@ -179,6 +200,14 @@ function main() {
|
|
|
179
200
|
console.log(`Mute LED: ${state ? "on" : "off"}`);
|
|
180
201
|
});
|
|
181
202
|
|
|
203
|
+
// Audio peripherals
|
|
204
|
+
controller.microphone.on("change", ({ state }) => {
|
|
205
|
+
console.log(`Microphone: ${state ? "connected" : "disconnected"}`);
|
|
206
|
+
});
|
|
207
|
+
controller.headphone.on("change", ({ state }) => {
|
|
208
|
+
console.log(`Headphone: ${state ? "connected" : "disconnected"}`);
|
|
209
|
+
});
|
|
210
|
+
|
|
182
211
|
// Log stick positions
|
|
183
212
|
controller.left.analog.on("change", (analog) => {
|
|
184
213
|
console.log(
|