Skip to content

Commit

Permalink
fix: handle disconnect events in webhid
Browse files Browse the repository at this point in the history
  • Loading branch information
nytamin committed Nov 14, 2023
1 parent adad215 commit 34e7338
Show file tree
Hide file tree
Showing 7 changed files with 270 additions and 171 deletions.
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,12 @@
"send-coverage": "jest && codecov",
"release:bump-release": "lerna version --exact --conventional-commits --conventional-graduate --no-push",
"release:bump-prerelease": "lerna version --exact --conventional-commits --conventional-prerelease --no-push",
"build-record-test": "cd packages/node-record-test && yarn build-record-test",
"lerna:version": "lerna version --exact",
"lerna:publish": "lerna publish",
"lerna": "lerna"
},
"devDependencies": {
"@sofie-automation/code-standard-preset": "~2.0.2",
"@sofie-automation/code-standard-preset": "~2.5.2",
"@types/jest": "^26.0.20",
"cross-env": "^7.0.3",
"jest": "^26.6.3",
Expand Down
13 changes: 9 additions & 4 deletions packages/core/src/SpaceMouse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export class SpaceMouse extends EventEmitter {
}
private _setupDevice(deviceInfo: DeviceInfo) {
const findProduct = (): { product: Product; productId: number; interface: number } => {
for (const product of Object.values(PRODUCTS)) {
for (const product of Object.values<Product>(PRODUCTS)) {
if (product.vendorId === deviceInfo.vendorId && product.productId === deviceInfo.productId) {
return {
product,
Expand Down Expand Up @@ -111,9 +111,9 @@ export class SpaceMouse extends EventEmitter {
this._device.on('error', (err) => {
if ((err + '').match(/could not read from/)) {
// The device has been disconnected
this._handleDeviceDisconnected().catch((error) => {
this.emit('error', error)
})
this._triggerHandleDeviceDisconnected()
} else if ((err + '').match(/WebHID disconnected/)) {
this._triggerHandleDeviceDisconnected()
} else {
this.emit('error', err)
}
Expand Down Expand Up @@ -157,6 +157,11 @@ export class SpaceMouse extends EventEmitter {
return new Map(this._buttonStates) // Make a copy
}

private _triggerHandleDeviceDisconnected(): void {
this._handleDeviceDisconnected().catch((error) => {
this.emit('error', error)
})
}
/** (Internal function) Called when there has been detected that the device has been disconnected */
public async _handleDeviceDisconnected(): Promise<void> {
if (!this._disconnected) {
Expand Down
4 changes: 2 additions & 2 deletions packages/node/src/methods.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SpaceMouse, PRODUCTS, VENDOR_IDS } from '@spacemouse-lib/core'
import { SpaceMouse, PRODUCTS, VENDOR_IDS, Product } from '@spacemouse-lib/core'
import * as HID from 'node-hid'
import type { usb } from 'usb'
import { NodeHIDDevice } from './node-hid-wrapper'
Expand Down Expand Up @@ -122,7 +122,7 @@ export function isASpaceMouseDevice(device: HID.Device | usb.Device): boolean {

if (!VENDOR_IDS.includes(vendorId)) return false

for (const product of Object.values(PRODUCTS)) {
for (const product of Object.values<Product>(PRODUCTS)) {
if (product.productId === productId && product.vendorId === vendorId) {
return true // break and return
}
Expand Down
2 changes: 1 addition & 1 deletion packages/node/src/watcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ export class SpaceMouseWatcher extends EventEmitter {
let removed = 0
let added = 0
// Removed devices:
for (const [devicePath, o] of Object.entries(this.seenDevicePaths)) {
for (const [devicePath, o] of Object.entries<{ spaceMouse?: SpaceMouse }>(this.seenDevicePaths)) {
if (!pathMap[devicePath]) {
// A device has been removed
this.debugLog('removed')
Expand Down
6 changes: 6 additions & 0 deletions packages/webhid-demo/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ async function openDevice(device: HIDDevice): Promise<void> {

appendLog(`Connected to "${spaceMouse.info.name}"`)

spaceMouse.on('error', (error) => {
appendLog(`Error: ${error}`)
})
spaceMouse.on('disconnected', () => {
appendLog(`disconnected`)
})
spaceMouse.on('down', (keyIndex: number) => {
appendLog(`Button ${keyIndex} down`)
})
Expand Down
28 changes: 20 additions & 8 deletions packages/webhid/src/web-hid-wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,19 @@ export class WebHIDDevice extends EventEmitter implements CoreHIDDevice {
constructor(device: HIDDevice) {
super()

this._handleInputreport = this._handleInputreport.bind(this)
this._handleInputReport = this._handleInputReport.bind(this)
this._handleError = this._handleError.bind(this)
this._handleDisconnect = this._handleDisconnect.bind(this)

this.device = device

this.device.addEventListener('inputreport', this._handleInputreport)
this.device.addEventListener('inputreport', this._handleInputReport)
this.device.addEventListener('error', this._handleError)
navigator.hid.addEventListener('disconnect', this._handleDisconnect)
}
public async close(): Promise<void> {
await this.device.close()
this._cleanup()
}
public write(data: number[]): void {
this.reportQueue
Expand All @@ -33,17 +39,23 @@ export class WebHIDDevice extends EventEmitter implements CoreHIDDevice {
this.emit('error', err)
})
}

public async close(): Promise<void> {
await this.device.close()
this.device.removeEventListener('inputreport', this._handleInputreport.bind(this))
private _cleanup(): void {
this.device.removeEventListener('inputreport', this._handleInputReport)
this.device.removeEventListener('error', this._handleError)
navigator.hid.removeEventListener('disconnect', this._handleDisconnect)
}
private _handleInputreport(event: HIDInputReportEvent) {
const buf = WebBuffer.concat([WebBuffer.from([event.reportId]), WebBuffer.from(event.data.buffer)])

private _handleInputReport(event: HIDInputReportEvent) {
const buf = WebBuffer.concat([WebBuffer.from([event.reportId]), WebBuffer.from(event.data.buffer)])
this.emit('data', buf)
}
private _handleError(error: any) {
this.emit('error', error)
}
private _handleDisconnect(event: HIDConnectionEvent) {
if (event.device === this.device) {
this.emit('error', 'WebHID disconnected')
}
this._cleanup()
}
}
Loading

0 comments on commit 34e7338

Please sign in to comment.