diff --git a/package-lock.json b/package-lock.json index 89fd31f..b2d80ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { - "name": "dictation_support", - "version": "1.0.4", + "name": "@mouadennasri/dictation_support", + "version": "1.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "dictation_support", - "version": "1.0.4", + "name": "@mouadennasri/dictation_support", + "version": "1.1.0", "license": "Apache-2.0", "dependencies": { "@types/w3c-web-hid": "^1.0.3" @@ -3354,6 +3354,21 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -9804,6 +9819,13 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "optional": true + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", diff --git a/package.json b/package.json index be30f25..60d59fe 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "dictation_support", - "version": "1.0.5", - "description": "SDK to interact with dictation devices", + "name": "@mouadennasri/dictation_support", + "version": "1.1.0", + "description": "SDK to interact with dictation devices (RADPAIR fork — forwards HIDInputReportEvent.timeStamp to button listeners)", "scripts": { "build": "rimraf dist && npx webpack --config=webpack.config.js", "lint": "eslint --ignore-path .gitignore --ext .ts .", @@ -18,9 +18,12 @@ "/dist/index.js", "/dist/index.d.ts" ], + "publishConfig": { + "access": "public" + }, "repository": { "type": "git", - "url": "https://github.com/GoogleChromeLabs/dictation_support.git" + "url": "https://github.com/mouadennasri/dictation_support.git" }, "devDependencies": { "@types/jasmine": "^4.3.0", diff --git a/src/dictation_device_base.ts b/src/dictation_device_base.ts index 11e75a6..b74352b 100644 --- a/src/dictation_device_base.ts +++ b/src/dictation_device_base.ts @@ -77,7 +77,8 @@ export enum ButtonEvent { } export type ButtonEventListener = - (device: DictationDevice, bitMask: ButtonEvent) => void|Promise; + (device: DictationDevice, bitMask: ButtonEvent, + eventTimeStamp: number) => void|Promise; export abstract class DictationDeviceBase { private static next_id = 0; @@ -117,11 +118,10 @@ export abstract class DictationDeviceBase { } protected async onInputReport(event: HIDInputReportEvent) { - const data = event.data; - await this.handleButtonPress(data); + await this.handleButtonPress(event.data, event.timeStamp); } - protected async handleButtonPress(data: DataView) { + protected async handleButtonPress(data: DataView, eventTimeStamp: number) { const buttonMappings = this.getButtonMappings(); const inputBitMask = this.getInputBitmask(data); let outputBitMask = 0; @@ -135,7 +135,8 @@ export abstract class DictationDeviceBase { outputBitMask = this.filterOutputBitMask(outputBitMask); await Promise.all([...this.buttonEventListeners].map( - listener => listener(this.getThisAsDictationDevice(), outputBitMask))); + listener => listener( + this.getThisAsDictationDevice(), outputBitMask, eventTimeStamp))); } protected filterOutputBitMask(outputBitMask: number): number { diff --git a/src/speechmike_hid_device.ts b/src/speechmike_hid_device.ts index 8e571e0..4089f59 100644 --- a/src/speechmike_hid_device.ts +++ b/src/speechmike_hid_device.ts @@ -261,14 +261,17 @@ export class SpeechMikeHidDevice extends DictationDeviceBase { } this.proxyDevice = proxyDevice; this.proxyDevice.addButtonEventListener( - (_device: DictationDevice, bitMask: ButtonEvent) => - this.onProxyButtonEvent(bitMask)); + (_device: DictationDevice, bitMask: ButtonEvent, + eventTimeStamp: number) => + this.onProxyButtonEvent(bitMask, eventTimeStamp)); } // See comment in DictationDeviceManager - protected async onProxyButtonEvent(bitMask: ButtonEvent) { + protected async onProxyButtonEvent( + bitMask: ButtonEvent, eventTimeStamp: number) { await Promise.all([...this.buttonEventListeners].map( - listener => listener(this.getThisAsDictationDevice(), bitMask))); + listener => listener( + this.getThisAsDictationDevice(), bitMask, eventTimeStamp))); } protected async handleCommandResponse(command: Command, data: DataView) { @@ -360,7 +363,7 @@ export class SpeechMikeHidDevice extends DictationDeviceBase { const command = data.getUint8(0); if (command === Command.BUTTON_PRESS_EVENT) { - await this.handleButtonPress(data); + await this.handleButtonPress(data, event.timeStamp); } else if (command === Command.MOTION_EVENT) { await this.handleMotionEvent(data); } else if (command === Command.WIRELESS_STATUS_EVENT) { diff --git a/src/speechmike_hid_device_test.ts b/src/speechmike_hid_device_test.ts index c2979a8..74342ce 100644 --- a/src/speechmike_hid_device_test.ts +++ b/src/speechmike_hid_device_test.ts @@ -873,11 +873,14 @@ describe('SpeechMikeHidDevice', () => { it('propagates button press events from proxy device', async () => { const button = ButtonEvent.RECORD; + const eventTimeStamp = 1234; expect(state.buttonEventListener).not.toHaveBeenCalled(); await Promise.all([...state.proxyDicationDeviceButtonEventListeners].map( - listener => listener(state.proxyDicationDevice, button))); + listener => + listener(state.proxyDicationDevice, button, eventTimeStamp))); expect(state.buttonEventListener) - .toHaveBeenCalledOnceWith(state.dictationDevice, button); + .toHaveBeenCalledOnceWith( + state.dictationDevice, button, eventTimeStamp); }); }); }); diff --git a/src/test_util/check_button_mapping.ts b/src/test_util/check_button_mapping.ts index 0dea591..8f314a2 100644 --- a/src/test_util/check_button_mapping.ts +++ b/src/test_util/check_button_mapping.ts @@ -33,7 +33,8 @@ export async function checkButtonMapping( expect(buttonEventListener) .withContext(contextMessageButtonPress) .toHaveBeenCalledOnceWith( - expectedDicationDevice, testCase.expectedButtonEvents); + expectedDicationDevice, testCase.expectedButtonEvents, + jasmine.any(Number)); } else { expect(buttonEventListener) @@ -51,7 +52,8 @@ export async function checkButtonMapping( if (testCase.expectedButtonEvents !== undefined) { expect(buttonEventListener) .withContext(contextMessageButtonRelease) - .toHaveBeenCalledOnceWith(expectedDicationDevice, ButtonEvent.NONE); + .toHaveBeenCalledOnceWith( + expectedDicationDevice, ButtonEvent.NONE, jasmine.any(Number)); } else { expect(buttonEventListener) diff --git a/src/test_util/fake_hid_device.ts b/src/test_util/fake_hid_device.ts index 74f25d6..bdde4ee 100644 --- a/src/test_util/fake_hid_device.ts +++ b/src/test_util/fake_hid_device.ts @@ -76,10 +76,10 @@ export class FakeHidDevice implements HIDDevice { if (type === 'inputreport') this.inputReportListeners.delete(listener); } - async handleInputReport(data: number[]) { + async handleInputReport(data: number[], timeStamp = 0) { const dataView = new DataView(new Uint8Array(data).buffer); - const event: HIDInputReportEvent = {data: dataView} as unknown as - HIDInputReportEvent; + const event: HIDInputReportEvent = + {data: dataView, timeStamp} as unknown as HIDInputReportEvent; await Promise.all( [...this.inputReportListeners].map(listener => listener(event))); }