feat(device): Read only filled user configuration and fix app close on mac (#486)
* feat(device): Save user configuration length * feat(device): Read only filled user configuration from EEPROM * fix(agent): Close device connections and quit from app on Mac
This commit is contained in:
committed by
László Monda
parent
fe6cd68c55
commit
0c30eccaca
@@ -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', () => {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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<ModuleConfiguration>(uhkBuffer => {
|
||||
@@ -52,12 +58,18 @@ export class UserConfiguration {
|
||||
});
|
||||
this.keymaps = buffer.readArray<Keymap>(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';
|
||||
|
||||
@@ -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<void> {
|
||||
@@ -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;
|
||||
|
||||
@@ -78,6 +78,7 @@ export class UserConfigEffects {
|
||||
Observable<KeymapAction | MacroAction | RenameUserConfigurationAction>)
|
||||
.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) {
|
||||
|
||||
Reference in New Issue
Block a user