diff --git a/packages/uhk-agent/src/electron-main.ts b/packages/uhk-agent/src/electron-main.ts index 3b7496bd..06ca1927 100644 --- a/packages/uhk-agent/src/electron-main.ts +++ b/packages/uhk-agent/src/electron-main.ts @@ -39,6 +39,8 @@ let appService: AppService; let sudoService: SudoService; function createWindow() { + logger.info('[Electron Main] Create new window.'); + // Create the browser window. win = new BrowserWindow({ title: 'UHK Agent', @@ -73,10 +75,13 @@ function createWindow() { // Dereference the window object, usually you would store windows // in an array if your app supports multi windows, this is the time // when you should delete the corresponding element. + logger.info('[Electron Main] win closed'); win = null; + deviceService.close(); deviceService = null; appUpdateService = null; appService = null; + uhkHidDeviceService.close(); uhkHidDeviceService = null; sudoService = null; }); @@ -96,11 +101,7 @@ app.on('ready', createWindow); // Quit when all windows are closed. app.on('window-all-closed', () => { - // On macOS it is common for applications and their menu bar - // to stay active until the user quits explicitly with Cmd + Q - if (process.platform !== 'darwin') { - app.quit(); - } + app.quit(); }); app.on('will-quit', () => { diff --git a/packages/uhk-agent/src/services/device.service.ts b/packages/uhk-agent/src/services/device.service.ts index dcc2fe45..5121bfb7 100644 --- a/packages/uhk-agent/src/services/device.service.ts +++ b/packages/uhk-agent/src/services/device.service.ts @@ -83,10 +83,11 @@ export class DeviceService { try { this.logService.debug(`[DeviceService] USB[T]: Read ${configName} size from keyboard`); - const configSize = await this.getConfigSizeFromKeyboard(property); + let configSize = await this.getConfigSizeFromKeyboard(property); const chunkSize = 63; let offset = 0; let configBuffer = new Buffer(0); + let firstRead = true; this.logService.debug(`[DeviceService] USB[T]: Read ${configName} from keyboard`); while (offset < configSize) { @@ -95,6 +96,11 @@ export class DeviceService { const readBuffer = await this.device.write(writeBuffer); configBuffer = Buffer.concat([configBuffer, new Buffer(readBuffer.slice(1, chunkSizeToRead + 1))]); offset += chunkSizeToRead; + + if (firstRead && config === UsbCommand.ReadUserConfig) { + firstRead = false; + configSize = readBuffer[3] + (readBuffer[4] << 8); + } } response = UhkHidDevice.convertBufferToIntArray(configBuffer); return Promise.resolve(JSON.stringify(response)); @@ -105,6 +111,13 @@ export class DeviceService { } } + public close(): void { + this.connected = false; + this.pollTimer$.unsubscribe(); + this.logService.info('[DeviceService] Device connection checker stopped.'); + + } + /** * HID API not support device attached and detached event. * This method check the keyboard is attached to the computer or not. diff --git a/packages/uhk-common/src/config-serializer/config-items/user-configuration.ts b/packages/uhk-common/src/config-serializer/config-items/user-configuration.ts index a7305e40..37aa0a0b 100644 --- a/packages/uhk-common/src/config-serializer/config-items/user-configuration.ts +++ b/packages/uhk-common/src/config-serializer/config-items/user-configuration.ts @@ -10,6 +10,9 @@ export class UserConfiguration { @assertUInt16 dataModelVersion: number; + @assertUInt16 + userConfigurationLength: number; + deviceName: string; moduleConfigurations: ModuleConfiguration[] = []; @@ -24,6 +27,7 @@ export class UserConfiguration { fromJsonObject(jsonObject: any): UserConfiguration { this.dataModelVersion = jsonObject.dataModelVersion; + this.userConfigurationLength = jsonObject.userConfigurationLength; this.deviceName = jsonObject.deviceName; this.setDefaultDeviceName(); this.moduleConfigurations = jsonObject.moduleConfigurations.map((moduleConfiguration: any) => { @@ -35,11 +39,13 @@ export class UserConfiguration { return macro; }); this.keymaps = jsonObject.keymaps.map((keymap: any) => new Keymap().fromJsonObject(keymap, this.macros)); + this.recalculateConfigurationLength(); return this; } fromBinary(buffer: UhkBuffer): UserConfiguration { this.dataModelVersion = buffer.readUInt16(); + this.userConfigurationLength = buffer.readUInt16(); this.deviceName = buffer.readString(); this.setDefaultDeviceName(); this.moduleConfigurations = buffer.readArray(uhkBuffer => { @@ -52,12 +58,18 @@ export class UserConfiguration { }); this.keymaps = buffer.readArray(uhkBuffer => new Keymap().fromBinary(uhkBuffer, this.macros)); ConfigSerializer.resolveSwitchKeymapActions(this.keymaps); + + if (this.userConfigurationLength === 0) { + this.recalculateConfigurationLength(); + } + return this; } toJsonObject(): any { return { dataModelVersion: this.dataModelVersion, + userConfigurationLength: this.userConfigurationLength, deviceName: this.deviceName, moduleConfigurations: this.moduleConfigurations.map(moduleConfiguration => moduleConfiguration.toJsonObject()), keymaps: this.keymaps.map(keymap => keymap.toJsonObject(this.macros)), @@ -67,6 +79,7 @@ export class UserConfiguration { toBinary(buffer: UhkBuffer): void { buffer.writeUInt16(this.dataModelVersion); + buffer.writeUInt16(this.userConfigurationLength); buffer.writeString(this.deviceName); buffer.writeArray(this.moduleConfigurations); buffer.writeArray(this.macros); @@ -87,6 +100,12 @@ export class UserConfiguration { return this.macros.find(macro => macroId === macro.id); } + recalculateConfigurationLength(){ + const buffer = new UhkBuffer(); + this.toBinary(buffer); + this.userConfigurationLength = buffer.offset; + } + private setDefaultDeviceName(): void { if (!this.deviceName || this.deviceName.trim().length === 0) { this.deviceName = 'My UHK'; diff --git a/packages/uhk-usb/src/uhk-hid-device.ts b/packages/uhk-usb/src/uhk-hid-device.ts index 3613a9db..e9166581 100644 --- a/packages/uhk-usb/src/uhk-hid-device.ts +++ b/packages/uhk-usb/src/uhk-hid-device.ts @@ -157,12 +157,13 @@ export class UhkHidDevice { * Close the communication chanel with UHK Device */ public close(): void { + this.logService.info('[UhkHidDevice] Device communication closing.'); if (!this._device) { return; } - this._device.close(); this._device = null; + this.logService.info('[UhkHidDevice] Device communication closed.'); } public async waitUntilKeyboardBusy(): Promise { @@ -196,7 +197,7 @@ export class UhkHidDevice { private connectToDevice(): HID { try { const devs = devices(); - this.logService.debug('[DeviceService] Available devices:', devs); + this.logService.debug('[UhkHidDevice] Available devices:', devs); const dev = devs.find((x: Device) => x.vendorId === Constants.VENDOR_ID && @@ -204,15 +205,15 @@ export class UhkHidDevice { ((x.usagePage === 128 && x.usage === 129) || x.interface === 0)); if (!dev) { - this.logService.info('[DeviceService] UHK Device not found:'); + this.logService.info('[UhkHidDevice] UHK Device not found:'); return null; } const device = new HID(dev.path); - this.logService.info('[DeviceService] Used device:', dev); + this.logService.info('[UhkHidDevice] Used device:', dev); return device; } catch (err) { - this.logService.error('[DeviceService] Can not create device:', err); + this.logService.error('[UhkHidDevice] Can not create device:', err); } return null; diff --git a/packages/uhk-web/src/app/store/effects/user-config.ts b/packages/uhk-web/src/app/store/effects/user-config.ts index fe57eba4..f01e8b44 100644 --- a/packages/uhk-web/src/app/store/effects/user-config.ts +++ b/packages/uhk-web/src/app/store/effects/user-config.ts @@ -78,6 +78,7 @@ export class UserConfigEffects { Observable) .withLatestFrom(this.store.select(getUserConfiguration), this.store.select(getPrevUserConfiguration)) .mergeMap(([action, config, prevUserConfiguration]) => { + config.recalculateConfigurationLength(); this.dataStorageRepository.saveConfig(config); if (action.type === KeymapActions.REMOVE || action.type === MacroActions.REMOVE) {