feat(config): Read / write hardware configuration area (#423)

* add write-hca.js

* refactor: Move config serializer into the uhk-common package

* refactor: Move getTransferBuffers into the uhk-usb package

* refactor: delete obsoleted classes

* build: add uhk-usb build command

* refactor: move eeprom transfer to uhk-usb package

* fix: Fix write-hca.js

* feat: load hardware config from the device and

* style: fix ts lint errors

* build: fix rxjs dependency resolve

* test: Add jasmine unit test framework to the tet serializer

* fix(user-config): A "type": "basic", properties to the "keystroke" action types

* feat(usb): set chmod+x on write-hca.js

* feat(usb): Create USB logger

* style: Fix type

* build: Add chalk to dependencies.

Chalk will colorize the output
This commit is contained in:
Róbert Kiss
2017-09-26 16:57:27 +00:00
committed by László Monda
parent 1122784bdb
commit 9294bede50
130 changed files with 9108 additions and 1991 deletions
+3 -4
View File
@@ -1,4 +1,3 @@
uhk-config.bin
uhk-config-serialized.json
uhk-config-serialized.bin
test-serializer.js
user-config.bin
user-config-serialized.json
user-config-serialized.bin
+8
View File
@@ -0,0 +1,8 @@
{
"spec_dir": "spec",
"spec_files": [
"**/*[sS]pec.ts"
],
"stopSpecOnExpectationFailure": true,
"random": false
}
File diff suppressed because it is too large Load Diff
+9 -3
View File
@@ -16,10 +16,16 @@
"dependencies": {
},
"devDependencies": {
"uhk-web": "^1.0.0"
"@types/jasmine": "^2.6.0",
"@types/node": "8.0.30",
"jasmine": "^2.8.0",
"jasmine-core": "^2.8.0",
"jasmine-node": "2.0.0",
"jasmine-ts": "^0.2.1",
"ts-node": "3.3.0",
"uhk-common": "1.0.0"
},
"scripts": {
"build": "webpack",
"test": "node ./test-serializer.js"
"test": "jasmine-ts --config=jasmine.json"
}
}
@@ -0,0 +1,33 @@
import { UhkBuffer, UserConfiguration } from '../../uhk-common/index';
const fs = require('fs');
const userConfig = JSON.parse(fs.readFileSync('../uhk-web/src/app/services/user-config.json'));
describe('Test Serializer', () => {
it('full config match', () => {
const config1Js = userConfig;
const config1Ts: UserConfiguration = new UserConfiguration().fromJsonObject(config1Js);
const config1Buffer = new UhkBuffer();
config1Ts.toBinary(config1Buffer);
const config1BufferContent = config1Buffer.getBufferContent();
fs.writeFileSync('user-config.bin', config1BufferContent);
config1Buffer.offset = 0;
console.log();
const config2Ts = new UserConfiguration().fromBinary(config1Buffer);
console.log('\n');
const config2Js = config2Ts.toJsonObject();
const config2Buffer = new UhkBuffer();
config2Ts.toBinary(config2Buffer);
fs.writeFileSync('user-config-serialized.json', JSON.stringify(config2Js, undefined, 4));
const config2BufferContent = config1Buffer.getBufferContent();
fs.writeFileSync('user-config-serialized.bin', config2BufferContent);
expect(config1Js).toEqual(config2Js);
const buffersContentsAreEqual: boolean = Buffer.compare(config1BufferContent, config2BufferContent) === 0;
expect(buffersContentsAreEqual).toBe(true);
});
});
@@ -1,45 +0,0 @@
import { UserConfiguration } from '../uhk-web/src/app/config-serializer/config-items/user-configuration';
import { UhkBuffer } from '../uhk-web/src/app/config-serializer/uhk-buffer';
const assert = require('assert');
const fs = require('fs');
const userConfig = JSON.parse(fs.readFileSync('../uhk-web/src/app/config-serializer/user-config.json'));
const config1Js = userConfig;
const config1Ts: UserConfiguration = new UserConfiguration().fromJsonObject(config1Js);
const config1Buffer = new UhkBuffer();
config1Ts.toBinary(config1Buffer);
const config1BufferContent = config1Buffer.getBufferContent();
fs.writeFileSync('user-config.bin', config1BufferContent);
config1Buffer.offset = 0;
console.log();
const config2Ts = new UserConfiguration().fromBinary(config1Buffer);
console.log('\n');
const config2Js = config2Ts.toJsonObject();
const config2Buffer = new UhkBuffer();
config2Ts.toBinary(config2Buffer);
fs.writeFileSync('user-config-serialized.json', JSON.stringify(config2Js, undefined, 4));
const config2BufferContent = config1Buffer.getBufferContent();
fs.writeFileSync('user-config-serialized.bin', config2BufferContent);
console.log('\n');
let returnValue = 0;
try {
assert.deepEqual(config1Js, config2Js);
console.log('JSON configurations are identical.');
} catch (error) {
console.log('JSON configurations differ.');
returnValue = 1;
}
const buffersContentsAreEqual: boolean = Buffer.compare(config1BufferContent, config2BufferContent) === 0;
if (buffersContentsAreEqual) {
console.log('Binary configurations are identical.');
} else {
console.log('Binary configurations differ.');
returnValue += 2;
}
process.exit(returnValue);
+1 -4
View File
@@ -5,10 +5,7 @@
"moduleResolution": "node",
"experimentalDecorators": true,
"typeRoots": [
"../node_modules/@types"
],
"types": [
"node"
"./node_modules/@types"
]
}
}
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
+6 -6
View File
@@ -392,9 +392,9 @@
}
},
"electron": {
"version": "1.7.6",
"resolved": "https://registry.npmjs.org/electron/-/electron-1.7.6.tgz",
"integrity": "sha1-+2nqMb0D3w7/JH8m8LU4vSm27nI=",
"version": "1.7.5",
"resolved": "https://registry.npmjs.org/electron/-/electron-1.7.5.tgz",
"integrity": "sha1-BloxAr+LhxAt9QxQmF/v5sVpBFs=",
"requires": {
"@types/node": "7.0.43",
"electron-download": "3.3.0",
@@ -432,9 +432,9 @@
"integrity": "sha1-ihBD4ys6HaHD9VPc4oznZCRhZ+M="
},
"electron-log": {
"version": "2.2.9",
"resolved": "https://registry.npmjs.org/electron-log/-/electron-log-2.2.9.tgz",
"integrity": "sha512-WNMSipQYurNxY14RO6IKgcxcZg1e4aNVpUUJK9q7Bqe0TZEKn1e5h4HiQKhTgVLqKrUn++ugOZrty450P9vpjA=="
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/electron-log/-/electron-log-2.2.6.tgz",
"integrity": "sha1-zPo+CbOfMhRoyQpkJwE4CjQHnxo="
},
"electron-rebuild": {
"version": "1.6.0",
+2 -1
View File
@@ -22,7 +22,8 @@
"electron-settings": "3.0.14",
"electron-updater": "2.2.0",
"node-hid": "0.5.4",
"sudo-prompt": "^7.0.0"
"sudo-prompt": "^7.0.0",
"uhk-usb": "1.0.0"
},
"devDependencies": {
"uhk-common": "^1.0.0"
+3 -3
View File
@@ -8,6 +8,7 @@ import { autoUpdater } from 'electron-updater';
import * as path from 'path';
import * as url from 'url';
import * as commandLineArgs from 'command-line-args';
import { UhkHidDevice } from 'uhk-usb';
// import { ElectronDataStorageRepositoryService } from './services/electron-datastorage-repository.service';
import { CommandLineArgs } from 'uhk-common';
@@ -16,7 +17,6 @@ import { logger } from './services/logger.service';
import { AppUpdateService } from './services/app-update.service';
import { AppService } from './services/app.service';
import { SudoService } from './services/sudo.service';
import { UhkHidDeviceService } from './services/uhk-hid-device.service';
const optionDefinitions = [
{ name: 'addons', type: Boolean, defaultOption: false }
@@ -33,7 +33,7 @@ let win: Electron.BrowserWindow;
autoUpdater.logger = logger;
let deviceService: DeviceService;
let uhkHidDeviceService: UhkHidDeviceService;
let uhkHidDeviceService: UhkHidDevice;
let appUpdateService: AppUpdateService;
let appService: AppService;
let sudoService: SudoService;
@@ -51,7 +51,7 @@ function createWindow() {
});
win.setMenuBarVisibility(false);
win.maximize();
uhkHidDeviceService = new UhkHidDeviceService(logger);
uhkHidDeviceService = new UhkHidDevice(logger);
deviceService = new DeviceService(logger, win, uhkHidDeviceService);
appUpdateService = new AppUpdateService(logger, win, app);
appService = new AppService(logger, win, deviceService, options, uhkHidDeviceService);
@@ -1,16 +1,16 @@
import { ipcMain, BrowserWindow } from 'electron';
import { UhkHidDevice } from 'uhk-usb';
import { CommandLineArgs, IpcEvents, AppStartInfo, LogService } from 'uhk-common';
import { MainServiceBase } from './main-service-base';
import { DeviceService } from './device.service';
import { UhkHidDeviceService } from './uhk-hid-device.service';
export class AppService extends MainServiceBase {
constructor(protected logService: LogService,
protected win: Electron.BrowserWindow,
private deviceService: DeviceService,
private options: CommandLineArgs,
private uhkHidDeviceService: UhkHidDeviceService) {
private uhkHidDeviceService: UhkHidDevice) {
super(logService, win);
ipcMain.on(IpcEvents.app.getAppStartInfo, this.handleAppStartInfo.bind(this));
@@ -1,10 +1,10 @@
import { ipcMain } from 'electron';
import { Constants, IpcEvents, LogService, IpcResponse } from 'uhk-common';
import { IpcEvents, LogService, IpcResponse, ConfigurationReply } from 'uhk-common';
import { Constants, EepromTransfer, SystemPropertyIds, UsbCommand } from 'uhk-usb';
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
import { Device, devices } from 'node-hid';
import { UhkHidDevice } from 'uhk-usb';
import 'rxjs/add/observable/interval';
import 'rxjs/add/operator/startWith';
@@ -12,38 +12,6 @@ import 'rxjs/add/operator/map';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/distinctUntilChanged';
import { UhkHidDeviceService } from './uhk-hid-device.service';
/**
* UHK USB Communications command. All communication package should have start with a command code.
*/
enum Command {
GetProperty = 0,
UploadConfig = 8,
ApplyConfig = 9,
LaunchEepromTransfer = 12,
ReadUserConfig = 15,
GetKeyboardState = 16
}
enum EepromTransfer {
ReadHardwareConfig = 0,
WriteHardwareConfig = 1,
ReadUserConfig = 2,
WriteUserConfig = 3
}
enum SystemPropertyIds {
UsbProtocolVersion = 0,
BridgeProtocolVersion = 1,
DataModelVersion = 2,
FirmwareVersion = 3,
HardwareConfigSize = 4,
UserConfigSize = 5
}
const snooze = ms => new Promise(resolve => setTimeout(resolve, ms));
/**
* IpcMain pair of the UHK Communication
* Functionality:
@@ -57,10 +25,10 @@ export class DeviceService {
constructor(private logService: LogService,
private win: Electron.BrowserWindow,
private device: UhkHidDeviceService) {
private device: UhkHidDevice) {
this.pollUhkDevice();
ipcMain.on(IpcEvents.device.saveUserConfiguration, this.saveUserConfiguration.bind(this));
ipcMain.on(IpcEvents.device.loadUserConfiguration, this.loadUserConfiguration.bind(this));
ipcMain.on(IpcEvents.device.loadConfigurations, this.loadConfigurations.bind(this));
logService.debug('[DeviceService] init success');
}
@@ -76,32 +44,64 @@ export class DeviceService {
* Return with the actual UserConfiguration from UHK Device
* @returns {Promise<Buffer>}
*/
public async loadUserConfiguration(event: Electron.Event): Promise<void> {
public async loadConfigurations(event: Electron.Event): Promise<void> {
try {
const userConfiguration = await this.loadConfiguration(
SystemPropertyIds.UserConfigSize,
UsbCommand.ReadUserConfig,
'user configuration');
const hardwareConfiguration = await this.loadConfiguration(
SystemPropertyIds.HardwareConfigSize,
UsbCommand.ReadHardwareConfig,
'hardware configuration');
const response: ConfigurationReply = {
success: true,
userConfiguration,
hardwareConfiguration
};
event.sender.send(IpcEvents.device.loadConfigurationReply, JSON.stringify(response));
} catch (error) {
const response: ConfigurationReply = {
success: false,
error: error.message
};
event.sender.send(IpcEvents.device.loadConfigurationReply, JSON.stringify(response));
} finally {
this.device.close();
}
}
/**
* Return with the actual user / hardware fonfiguration from UHK Device
* @returns {Promise<Buffer>}
*/
public async loadConfiguration(property: SystemPropertyIds, config: UsbCommand, configName: string): Promise<string> {
let response = [];
try {
this.logService.debug('[DeviceService] USB[T]: Read user configuration size from keyboard');
const configSize = await this.getUserConfigSizeFromKeyboard();
this.logService.debug(`[DeviceService] USB[T]: Read ${configName} size from keyboard`);
const configSize = await this.getConfigSizeFromKeyboard(property);
const chunkSize = 63;
let offset = 0;
let configBuffer = new Buffer(0);
this.logService.debug('[DeviceService] USB[T]: Read user configuration from keyboard');
this.logService.debug(`[DeviceService] USB[T]: Read ${configName} from keyboard`);
while (offset < configSize) {
const chunkSizeToRead = Math.min(chunkSize, configSize - offset);
const writeBuffer = Buffer.from([Command.ReadUserConfig, chunkSizeToRead, offset & 0xff, offset >> 8]);
const writeBuffer = Buffer.from([config, chunkSizeToRead, offset & 0xff, offset >> 8]);
const readBuffer = await this.device.write(writeBuffer);
configBuffer = Buffer.concat([configBuffer, new Buffer(readBuffer.slice(1, chunkSizeToRead + 1))]);
offset += chunkSizeToRead;
}
response = UhkHidDeviceService.convertBufferToIntArray(configBuffer);
response = UhkHidDevice.convertBufferToIntArray(configBuffer);
return Promise.resolve(JSON.stringify(response));
} catch (error) {
this.logService.error('[DeviceService] getUserConfigFromEeprom error', error);
} finally {
this.device.close();
const errMsg = `[DeviceService] ${configName} from eeprom error`;
this.logService.error(errMsg, error);
throw new Error(errMsg);
}
event.sender.send(IpcEvents.device.loadUserConfigurationReply, JSON.stringify(response));
}
/**
@@ -127,11 +127,11 @@ export class DeviceService {
}
/**
* Return the UserConfiguration size from the UHK Device
* Return the user / hardware configuration size from the UHK Device
* @returns {Promise<number>}
*/
private async getUserConfigSizeFromKeyboard(): Promise<number> {
const buffer = await this.device.write(new Buffer([Command.GetProperty, SystemPropertyIds.UserConfigSize]));
private async getConfigSizeFromKeyboard(property: SystemPropertyIds): Promise<number> {
const buffer = await this.device.write(new Buffer([UsbCommand.GetProperty, property]));
const configSize = buffer[1] + (buffer[2] << 8);
this.logService.debug('[DeviceService] User config size:', configSize);
return configSize;
@@ -144,7 +144,7 @@ export class DeviceService {
this.logService.debug('[DeviceService] USB[T]: Write user configuration to keyboard');
await this.sendUserConfigToKeyboard(json);
this.logService.debug('[DeviceService] USB[T]: Write user configuration to EEPROM');
await this.writeUserConfigToEeprom();
await this.device.writeConfigToEeprom(EepromTransfer.WriteUserConfig);
response.success = true;
}
@@ -168,48 +168,12 @@ export class DeviceService {
*/
private async sendUserConfigToKeyboard(json: string): Promise<void> {
const buffer: Buffer = new Buffer(JSON.parse(json).data);
const fragments = this.getTransferBuffers(buffer);
const fragments = UhkHidDevice.getTransferBuffers(UsbCommand.UploadUserConfig, buffer);
for (const fragment of fragments) {
await this.device.write(fragment);
}
this.logService.debug('[DeviceService] USB[T]: Apply user configuration to keyboard');
const applyBuffer = new Buffer([Command.ApplyConfig]);
const applyBuffer = new Buffer([UsbCommand.ApplyConfig]);
await this.device.write(applyBuffer);
}
private async writeUserConfigToEeprom(): Promise<void> {
await this.device.write(new Buffer([Command.LaunchEepromTransfer, EepromTransfer.WriteUserConfig]));
await this.waitUntilKeyboardBusy();
}
private async waitUntilKeyboardBusy(): Promise<void> {
while (true) {
const buffer = await this.device.write(new Buffer([Command.GetKeyboardState]));
if (buffer[1] === 0) {
break;
}
this.logService.debug('Keyboard is busy, wait...');
await snooze(200);
}
}
/**
* Split the whole UserConfiguration package into 64 byte fragments
* @param {Buffer} configBuffer
* @returns {Buffer[]}
* @private
*/
private getTransferBuffers(configBuffer: Buffer): Buffer[] {
const fragments: Buffer[] = [];
const MAX_SENDING_PAYLOAD_SIZE = Constants.MAX_PAYLOAD_SIZE - 4;
for (let offset = 0; offset < configBuffer.length; offset += MAX_SENDING_PAYLOAD_SIZE) {
const length = offset + MAX_SENDING_PAYLOAD_SIZE < configBuffer.length
? MAX_SENDING_PAYLOAD_SIZE
: configBuffer.length - offset;
const header = new Buffer([Command.UploadConfig, length, offset & 0xFF, offset >> 8]);
fragments.push(Buffer.concat([header, configBuffer.slice(offset, offset + length)]));
}
return fragments;
}
}
+1
View File
@@ -1,3 +1,4 @@
export * from './src/util';
export * from './src/models';
export * from './src/services';
export * from './src/config-serializer';
+5
View File
@@ -20,6 +20,11 @@
"resolved": "https://registry.npmjs.org/@ngrx/store/-/store-2.2.3.tgz",
"integrity": "sha1-570RSfHEQgjxzEdENT8PmKDx9Xs="
},
"@types/node": {
"version": "8.0.28",
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.0.28.tgz",
"integrity": "sha512-HupkFXEv3O3KSzcr3Ylfajg0kaerBg1DyaZzRBBQfrU3NN1mTBRE7sCveqHwXLS5Yrjvww8qFzkzYQQakG9FuQ=="
},
"tslib": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.7.1.tgz",
+5 -3
View File
@@ -3,15 +3,17 @@
"private": true,
"version": "1.0.0",
"description": "Common Library contains the common code for uhk-agent (electron-main) and web (electron-renderer) modules",
"main": "src/index.js",
"main": "dist/index.js",
"scripts": {
"build": "tsc",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@angular/core": "^4.3.3",
"@angular/core": "4.3.3",
"@ngrx/core": "1.2.0",
"@ngrx/store": "^2.2.3"
"@ngrx/store": "2.2.3",
"@types/node": "8.0.28"
}
}
@@ -6,13 +6,13 @@ The configuration of the UHK is unusually complex for a keyboard, and is compose
## Setup
Given that the development dependencies are installed on your system you should be able to build the configuration serializer tester by executing `npm run build:test` in this directory, then start the test by running `node test-serializer.js`.
Given that the development dependencies are installed on your system you should be able to run the configuration serializer tester test by running `npm run test` in this directorx.
## Configuration representations
There are 3 different representations of the configuration, each filling a specific purpose.
The **JavaScript representation** is optimally suited to be serialized as JSON, and saved to the file system, or transmitted over the network. As a plaintext format, it's human-readable and easily editable. See [user-config.json](user-config.json) for an example configuration.
The **JavaScript representation** is optimally suited to be serialized as JSON, and saved to the file system, or transmitted over the network. As a plaintext format, it's human-readable and easily editable. See [user-config.json](../../../uhk-web/src/app/services/user-config.json) for an example configuration.
The **TypeScript representation** is structurally similar to the JavaScript representation, but it features strongly typed TypeScript objects instead of typeless JavaScript objects. This representation is meant to be used by Agent. Extensive, per-property [assertion](assert.ts) takes place upon initializing the TypeScript objects to ensure the integrity of the configuration.
@@ -75,7 +75,7 @@ KeyActions.toJsObject: <KeyActions length="9">
## Testing the serializer
[test-serializer.ts](test-serializer.ts) is designed to test the serializer by taking [user-config.json](user-config.json), and transforming it to TypeScript representation, then to binary representation, then finally back to JavaScript representation. This should exercise every major code path.
[test-serializer.ts](test-serializer.ts) is designed to test the serializer by taking [user-config.json](../../../uhk-web/src/app/services/user-config.json), and transforming it to TypeScript representation, then to binary representation, then finally back to JavaScript representation. This should exercise every major code path.
If the testing is successful the following should be displayed:
@@ -0,0 +1,11 @@
export * from './key-action';
export * from './macro-action';
export * from './hardware-configuration';
export * from './key-modifiers';
export * from './keymap';
export * from './layer';
export * from './long-press-action';
export * from './macro';
export * from './module';
export * from './module-configuration';
export * from './user-configuration';
@@ -1,8 +1,9 @@
export * from './key-action';
export * from './keystroke-action';
export * from './keystroke-type';
export * from './mouse-action';
export * from './none-action';
export * from './play-macro-action';
export * from './switch-keymap-action';
export * from './switch-layer-action';
export * from './helper';
export { Helper as KeyActionHelper } from './helper';
@@ -3,7 +3,6 @@ import { Layer } from './layer';
import { Macro } from './macro';
import { SwitchLayerAction } from './key-action/switch-layer-action';
import { KeyAction } from './key-action/key-action';
import { ConfigSerializer } from '../config-serializer';
import { UserConfiguration } from './user-configuration';
export class Keymap {
@@ -2,7 +2,6 @@ import { UhkBuffer } from '../uhk-buffer';
import { Macro } from './macro';
import { Module } from './module';
import { UserConfiguration } from './user-configuration';
import { ConfigSerializer } from '../config-serializer';
export class Layer {
@@ -5,4 +5,4 @@ export * from './move-mouse-macro-action';
export * from './mouse-button-macro-action';
export * from './scroll-mouse-macro-action';
export * from './text-macro-action';
export * from './helper';
export { Helper as MacroActionHelper } from './helper';
@@ -1,6 +1,7 @@
import { assertUInt8 } from '../assert';
import { UhkBuffer } from '../uhk-buffer';
import { Helper as MacroActionHelper, MacroAction } from './macro-action';
import { MacroAction } from './macro-action';
import { Helper as MacroActionHelper } from './macro-action/helper';
export class Macro {
@@ -1,6 +1,6 @@
import { assertEnum, assertUInt8 } from '../assert';
import { UhkBuffer } from '../uhk-buffer';
import { Helper as KeyActionHelper, KeyAction, NoneAction, PlayMacroAction, SwitchKeymapAction } from './key-action';
import { KeyActionHelper, KeyAction, NoneAction, PlayMacroAction, SwitchKeymapAction } from './key-action';
import { Macro } from './macro';
import { UserConfiguration } from './user-configuration';
@@ -0,0 +1,4 @@
export * from './config-items';
export * from './assert';
export * from './config-serializer';
export * from './uhk-buffer';
@@ -4,6 +4,24 @@ export class UhkBuffer {
(<any>element).toBinary(buffer); // TODO: Remove any
}
static fromArray(data: Array<number>): UhkBuffer {
if (data.length < 1) {
return null;
}
const uhkBuffer = new UhkBuffer();
let hasNonZeroValue = false;
for (const num of data) {
if (num > 0) {
hasNonZeroValue = true;
}
uhkBuffer.writeUInt8(num);
}
uhkBuffer.offset = 0;
return uhkBuffer;
}
private static eepromSize = 32 * 1024;
private static maxCompactLength = 0xFFFF;
private static longCompactLengthPrefix = 0xFF;
@@ -0,0 +1,6 @@
export interface ConfigurationReply {
success: boolean;
userConfiguration?: string;
hardwareConfiguration?: string;
error?: string;
}
+1
View File
@@ -2,3 +2,4 @@ export * from './command-line-args';
export * from './notification';
export * from './ipc-response';
export * from './app-start-info';
export * from './configuration-reply';
@@ -1,17 +1,14 @@
import { Injectable } from '@angular/core';
@Injectable()
export class LogService {
error(...args: any[]): void {
console.error(args);
}
debug(...args: any[]): void {
console.debug(args);
console.log(args);
}
silly(...args: any[]): void {
console.debug(args);
console.log(args);
}
info(...args: any[]): void {
+1 -1
View File
@@ -1,5 +1,5 @@
export { Constants } from './constants';
export { IpcEvents } from './ipcEvents';
export * from './log';
// Source: http://stackoverflow.com/questions/13720256/javascript-regex-camelcase-to-sentence
export function camelCaseToSentence(camelCasedText: string): string {
+2 -2
View File
@@ -22,8 +22,8 @@ class Device {
public static readonly deviceConnectionStateChanged = 'device-connection-state-changed';
public static readonly saveUserConfiguration = 'device-save-user-configuration';
public static readonly saveUserConfigurationReply = 'device-save-user-configuration-reply';
public static readonly loadUserConfiguration = 'device-load-user-configuration';
public static readonly loadUserConfigurationReply = 'device-load-user-configuration-reply';
public static readonly loadConfigurations = 'device-load-configuration';
public static readonly loadConfigurationReply = 'device-load-configuration-reply';
}
export class IpcEvents {
+6
View File
@@ -0,0 +1,6 @@
export namespace LogRegExps {
export const transferRegExp = /USB\[T]:/;
export const writeRegExp = /USB\[W]:/;
export const readRegExp = /USB\[R]: 00/;
export const errorRegExp = /(?:(USB\[R]: ([^0]|0[^0])))/;
}
+1
View File
@@ -2,6 +2,7 @@
"compileOnSave": false,
"compilerOptions": {
"sourceMap": true,
"outDir": "./dist",
"declaration": false,
"module": "commonjs",
"moduleResolution": "node",
+1
View File
@@ -0,0 +1 @@
export * from './src';
+781
View File
File diff suppressed because it is too large Load Diff
+17
View File
@@ -0,0 +1,17 @@
{
"name": "uhk-usb",
"version": "1.0.0",
"description": "Agent preliminary USB code",
"main": "dist/index.js",
"license": "GPL-3.0",
"scripts": {
"build": "tsc"
},
"devDependencies": {
"@types/node": "8.0.28"
},
"dependencies": {
"node-hid": "0.5.4",
"uhk-common": "1.0.0"
}
}
+35
View File
@@ -0,0 +1,35 @@
export namespace Constants {
export const VENDOR_ID = 0x1D50;
export const PRODUCT_ID = 0x6122;
export const MAX_PAYLOAD_SIZE = 64;
}
/**
* UHK USB Communications command. All communication package should have start with a command code.
*/
export enum UsbCommand {
GetProperty = 0,
UploadUserConfig = 8,
ApplyConfig = 9,
LaunchEepromTransfer = 12,
ReadHardwareConfig = 13,
WriteHardwareConfig = 14,
ReadUserConfig = 15,
GetKeyboardState = 16
}
export enum EepromTransfer {
ReadHardwareConfig = 0,
WriteHardwareConfig = 1,
ReadUserConfig = 2,
WriteUserConfig = 3
}
export enum SystemPropertyIds {
UsbProtocolVersion = 0,
BridgeProtocolVersion = 1,
DataModelVersion = 2,
FirmwareVersion = 3,
HardwareConfigSize = 4,
UserConfigSize = 5
}
+2
View File
@@ -0,0 +1,2 @@
export * from './constants';
export * from './uhk-hid-device';
@@ -1,11 +1,14 @@
import { Device, devices, HID } from 'node-hid';
import { LogService } from 'uhk-common';
import { Constants, LogService } from 'uhk-common';
import { Constants, EepromTransfer, UsbCommand } from './constants';
const snooze = ms => new Promise(resolve => setTimeout(resolve, ms));
/**
* HID API wrapper to support unified logging and async write
*/
export class UhkHidDeviceService {
export class UhkHidDevice {
/**
* Convert the Buffer to number[]
* @param {Buffer} buffer
@@ -17,6 +20,27 @@ export class UhkHidDeviceService {
return Array.prototype.slice.call(buffer, 0);
}
/**
* Split the communication package into 64 byte fragments
* @param {UsbCommand} usbCommand
* @param {Buffer} configBuffer
* @returns {Buffer[]}
* @private
*/
public static getTransferBuffers(usbCommand: UsbCommand, configBuffer: Buffer): Buffer[] {
const fragments: Buffer[] = [];
const MAX_SENDING_PAYLOAD_SIZE = Constants.MAX_PAYLOAD_SIZE - 4;
for (let offset = 0; offset < configBuffer.length; offset += MAX_SENDING_PAYLOAD_SIZE) {
const length = offset + MAX_SENDING_PAYLOAD_SIZE < configBuffer.length
? MAX_SENDING_PAYLOAD_SIZE
: configBuffer.length - offset;
const header = new Buffer([usbCommand, length, offset & 0xFF, offset >> 8]);
fragments.push(Buffer.concat([header, configBuffer.slice(offset, offset + length)]));
}
return fragments;
}
/**
* Create the communication package that will send over USB and
* - add usb report code as 1st byte
@@ -27,7 +51,7 @@ export class UhkHidDeviceService {
* @static
*/
private static getTransferData(buffer: Buffer): number[] {
const data = UhkHidDeviceService.convertBufferToIntArray(buffer);
const data = UhkHidDevice.convertBufferToIntArray(buffer);
// if data start with 0 need to add additional leading zero because HID API remove it.
// https://github.com/node-hid/node-hid/issues/187
if (data.length > 0 && data[0] === 0 && process.platform === 'win32') {
@@ -108,7 +132,7 @@ export class UhkHidDeviceService {
this.logService.error('[UhkHidDevice] Transfer error: ', err);
return reject(err);
}
const logString = UhkHidDeviceService.bufferToString(receivedData);
const logString = UhkHidDevice.bufferToString(receivedData);
this.logService.debug('[UhkHidDevice] USB[R]:', logString);
if (receivedData[0] !== 0) {
@@ -118,12 +142,17 @@ export class UhkHidDeviceService {
return resolve(Buffer.from(receivedData));
});
const sendData = UhkHidDeviceService.getTransferData(buffer);
this.logService.debug('[UhkHidDevice] USB[W]:', UhkHidDeviceService.bufferToString(sendData));
const sendData = UhkHidDevice.getTransferData(buffer);
this.logService.debug('[UhkHidDevice] USB[W]:', UhkHidDevice.bufferToString(sendData));
device.write(sendData);
});
}
public async writeConfigToEeprom(transferType: EepromTransfer): Promise<void> {
await this.write(new Buffer([UsbCommand.LaunchEepromTransfer, transferType]));
await this.waitUntilKeyboardBusy();
}
/**
* Close the communication chanel with UHK Device
*/
@@ -136,6 +165,17 @@ export class UhkHidDeviceService {
this._device = null;
}
private async waitUntilKeyboardBusy(): Promise<void> {
while (true) {
const buffer = await this.write(new Buffer([UsbCommand.GetKeyboardState]));
if (buffer[1] === 0) {
break;
}
this.logService.debug('Keyboard is busy, wait...');
await snooze(200);
}
}
/**
* Return the stored version of HID device. If not exist try to initialize.
* @returns {HID}
+21
View File
@@ -0,0 +1,21 @@
{
"compileOnSave": false,
"compilerOptions": {
"sourceMap": true,
"outDir": "./dist",
"declaration": false,
"module": "commonjs",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es2016",
"typeRoots": [
"node_modules/@types"
],
"lib": [
"es2015.iterable",
"dom",
"es2016"
]
}
}
+1 -1
View File
@@ -2,6 +2,7 @@ import { Component, HostListener, ViewEncapsulation } from '@angular/core';
import { animate, style, transition, trigger } from '@angular/animations';
import { Observable } from 'rxjs/Observable';
import { Action, Store } from '@ngrx/store';
import { UhkBuffer } from 'uhk-common';
import 'rxjs/add/operator/last';
@@ -14,7 +15,6 @@ import {
saveToKeyboardState
} from './store';
import { getUserConfiguration } from './store/reducers/user-configuration';
import { UhkBuffer } from './config-serializer/uhk-buffer';
import { ProgressButtonState } from './store/reducers/progress-button-state';
@Component({
@@ -1,13 +1,14 @@
<svg-keyboard *ngFor="let layer of layers; let index = index; trackBy: trackKeyboard"
[@layerState]="layerAnimationState[index]"
[moduleConfig]="layer.modules"
[keybindAnimationEnabled]="keybindAnimationEnabled"
[halvesSplit]="halvesSplit"
[capturingEnabled]="capturingEnabled"
[selectedKey]="selectedKey"
[selected]="selectedKey?.layerId === index"
(keyClick)="keyClick.emit($event)"
(keyHover)="keyHover.emit($event)"
(capture)="capture.emit($event)"
[@layerState]="layerAnimationState[index]"
[moduleConfig]="layer.modules"
[keybindAnimationEnabled]="keybindAnimationEnabled"
[halvesSplit]="halvesSplit"
[capturingEnabled]="capturingEnabled"
[selectedKey]="selectedKey"
[selected]="selectedKey?.layerId === index"
[keyboardLayout]="keyboardLayout"
(keyClick)="keyClick.emit($event)"
(keyHover)="keyHover.emit($event)"
(capture)="capture.emit($event)"
>
</svg-keyboard>

Before

Width:  |  Height:  |  Size: 511 B

After

Width:  |  Height:  |  Size: 659 B

@@ -1,7 +1,8 @@
import { Component, ChangeDetectionStrategy, Input, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core';
import { animate, keyframes, state, style, transition, trigger } from '@angular/animations';
import { Layer } from 'uhk-common';
import { Layer } from '../../../config-serializer/config-items/layer';
import { KeyboardLayout } from '../../../keyboard/keyboard-layout.enum';
type AnimationKeyboard =
'leftIn' |
@@ -69,6 +70,7 @@ export class KeyboardSliderComponent implements OnChanges {
@Input() capturingEnabled: boolean;
@Input() halvesSplit: boolean;
@Input() selectedKey: { layerId: number, moduleId: number, keyId: number };
@Input() keyboardLayout = KeyboardLayout.ANSI;
@Output() keyClick = new EventEmitter();
@Output() keyHover = new EventEmitter();
@Output() capture = new EventEmitter();
@@ -1,12 +1,12 @@
import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { Keymap } from 'uhk-common';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/combineLatest';
import 'rxjs/add/operator/publishReplay';
import { Keymap } from '../../../config-serializer/config-items/keymap';
import { AppState } from '../../../store';
import { KeymapActions } from '../../../store/actions';
@@ -1,5 +1,6 @@
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { Keymap } from 'uhk-common';
import { Observable } from 'rxjs/Observable';
@@ -10,7 +11,6 @@ import 'rxjs/add/operator/switchMap';
import { Store } from '@ngrx/store';
import { Keymap } from '../../../config-serializer/config-items/keymap';
import { AppState } from '../../../store/index';
import { getKeymaps } from '../../../store/reducers/user-configuration';
@@ -1,6 +1,10 @@
<ng-template [ngIf]="keymap$ | async">
<keymap-header [keymap]="keymap$ | async" [deletable]="deletable$ | async" (downloadClick)="downloadKeymap()"></keymap-header>
<svg-keyboard-wrap [keymap]="keymap$ | async" [halvesSplit]="keyboardSplit"></svg-keyboard-wrap>
<keymap-header [keymap]="keymap$ | async"
[deletable]="deletable$ | async"
(downloadClick)="downloadKeymap()"></keymap-header>
<svg-keyboard-wrap [keymap]="keymap$ | async"
[halvesSplit]="keyboardSplit"
[keyboardLayout]="keyboardLayout$ | async"></svg-keyboard-wrap>
</ng-template>
<div *ngIf="!(keymap$ | async)" class="not-found">
@@ -1,8 +1,9 @@
import { Component, HostListener, ViewChild } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Store } from '@ngrx/store';
import { Keymap } from 'uhk-common';
import '@ngrx/core/add/operator/select';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/first';
@@ -15,11 +16,11 @@ import 'rxjs/add/operator/combineLatest';
import { saveAs } from 'file-saver';
import { Keymap } from '../../../config-serializer/config-items/keymap';
import { AppState } from '../../../store';
import { AppState, getKeyboardLayout } from '../../../store';
import { getKeymap, getKeymaps, getUserConfiguration } from '../../../store/reducers/user-configuration';
import 'rxjs/add/operator/pluck';
import { SvgKeyboardWrapComponent } from '../../svg/wrap/svg-keyboard-wrap.component';
import { KeyboardLayout } from '../../../keyboard/keyboard-layout.enum';
@Component({
selector: 'keymap-edit',
@@ -37,6 +38,7 @@ export class KeymapEditComponent {
deletable$: Observable<boolean>;
keymap$: Observable<Keymap>;
keyboardLayout$: Observable<KeyboardLayout>;
constructor(protected store: Store<AppState>,
route: ActivatedRoute) {
@@ -49,6 +51,8 @@ export class KeymapEditComponent {
this.deletable$ = store.let(getKeymaps())
.map((keymaps: Keymap[]) => keymaps.length > 1);
this.keyboardLayout$ = store.select(getKeyboardLayout);
}
downloadKeymap() {
@@ -10,11 +10,10 @@ import {
SimpleChanges,
ViewChild
} from '@angular/core';
import { Keymap } from 'uhk-common';
import { Store } from '@ngrx/store';
import { Keymap } from '../../../config-serializer/config-items/keymap';
import { AppState } from '../../../store';
import { KeymapActions } from '../../../store/actions';
@@ -8,8 +8,8 @@ import {
MoveMouseMacroAction,
MouseButtonMacroAction,
TextMacroAction,
Helper as MacroActionHelper
} from '../../../config-serializer/config-items/macro-action';
MacroActionHelper
} from 'uhk-common';
import { MacroDelayTabComponent, MacroMouseTabComponent, MacroKeyTabComponent, MacroTextTabComponent } from './tab';
enum TabName {
@@ -6,8 +6,8 @@ import {
OnInit,
ViewChild
} from '@angular/core';
import { DelayMacroAction } from 'uhk-common';
import { DelayMacroAction } from '../../../../../config-serializer/config-items/macro-action';
import { MacroBaseComponent } from '../macro-base.component';
const INITIAL_DELAY = 0.5; // In seconds
@@ -1,7 +1,6 @@
import { Component, Input, OnInit, ViewChild } from '@angular/core';
import { KeystrokeAction } from '../../../../../config-serializer/config-items/key-action';
import { KeyMacroAction, MacroSubAction } from '../../../../../config-serializer/config-items/macro-action';
import { KeyMacroAction, KeystrokeAction, MacroSubAction } from 'uhk-common';
import { KeypressTabComponent, Tab } from '../../../../popover/tab';
import { MacroBaseComponent } from '../macro-base.component';
@@ -5,7 +5,7 @@ import {
MoveMouseMacroAction,
ScrollMouseMacroAction,
MacroSubAction
} from '../../../../../config-serializer/config-items/macro-action';
} from 'uhk-common';
import { Tab } from '../../../../popover/tab';
import { MacroBaseComponent } from '../macro-base.component';
@@ -7,8 +7,8 @@ import {
Renderer,
ViewChild
} from '@angular/core';
import { TextMacroAction } from 'uhk-common';
import { TextMacroAction } from '../../../../../config-serializer/config-items/macro-action';
import { MacroBaseComponent } from '../macro-base.component';
@Component({
@@ -1,14 +1,11 @@
import { Component, OnDestroy } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Store } from '@ngrx/store';
import { Macro, MacroAction } from 'uhk-common';
import { Subscription } from 'rxjs/Subscription';
import 'rxjs/add/operator/pluck';
import { Macro } from '../../../config-serializer/config-items/macro';
import { MacroAction } from '../../../config-serializer/config-items/macro-action/macro-action';
import { MacroActions } from '../../../store/actions';
import { AppState } from '../../../store/index';
import { getMacro } from '../../../store/reducers/user-configuration';
@@ -9,10 +9,8 @@ import {
SimpleChanges,
ViewChild
} from '@angular/core';
import { Store } from '@ngrx/store';
import { Macro } from '../../../config-serializer/config-items/macro';
import { Macro } from 'uhk-common';
import { MacroActions } from '../../../store/actions';
import { AppState } from '../../../store/index';
@@ -1,16 +1,15 @@
import { Component, Input, Output, EventEmitter, OnChanges, OnInit, SimpleChanges } from '@angular/core';
import { animate, state, style, transition, trigger } from '@angular/animations';
import { KeyModifiers } from '../../../config-serializer/config-items/key-modifiers';
import {
DelayMacroAction,
KeyMacroAction,
KeyModifiers,
MacroAction,
MouseButtonMacroAction,
MoveMouseMacroAction,
ScrollMouseMacroAction,
TextMacroAction
} from '../../../config-serializer/config-items/macro-action';
} from 'uhk-common';
import { MapperService } from '../../../services/mapper.service';
@@ -1,10 +1,8 @@
import { Component, EventEmitter, Input, Output, QueryList, ViewChildren, forwardRef } from '@angular/core';
import { animate, state, style, transition, trigger } from '@angular/animations';
import { DragulaService } from 'ng2-dragula/ng2-dragula';
import { Macro, MacroAction } from 'uhk-common';
import { Macro } from '../../../config-serializer/config-items/macro';
import { MacroAction } from '../../../config-serializer/config-items/macro-action';
import { MacroItemComponent } from '../item';
@Component({
@@ -1,5 +1,6 @@
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { Macro } from 'uhk-common';
import { Observable } from 'rxjs/Observable';
@@ -10,7 +11,6 @@ import { Store } from '@ngrx/store';
import { AppState } from '../../../store/index';
import { getMacros } from '../../../store/reducers/user-configuration';
import { Macro } from '../../../config-serializer/config-items/macro';
@Injectable()
export class MacroNotFoundGuard implements CanActivate {
@@ -19,13 +19,13 @@ import 'rxjs/add/operator/map';
import {
KeyAction,
Keymap,
KeystrokeAction,
MouseAction,
PlayMacroAction,
SwitchKeymapAction,
SwitchLayerAction
} from '../../config-serializer/config-items/key-action';
import { Keymap } from '../../config-serializer/config-items/keymap';
} from 'uhk-common';
import { Tab } from './tab/tab';
@@ -1,9 +1,7 @@
import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core';
import { Select2OptionData } from 'ng2-select2/ng2-select2';
import { Keymap, KeyAction, SwitchKeymapAction } from 'uhk-common';
import { KeyAction, SwitchKeymapAction } from '../../../../config-serializer/config-items/key-action';
import { Keymap } from '../../../../config-serializer/config-items/keymap';
import { Tab } from '../tab';
@Component({
@@ -1,12 +1,9 @@
import { Component, Input, OnChanges } from '@angular/core';
import { Select2OptionData, Select2TemplateFunction } from 'ng2-select2';
import { KeyAction, KeystrokeAction } from '../../../../config-serializer/config-items/key-action';
import { KeyAction, KeystrokeAction, KeystrokeType } from 'uhk-common';
import { Tab } from '../tab';
import { MapperService } from '../../../../services/mapper.service';
import { KeystrokeType } from '../../../../config-serializer/config-items/key-action/keystroke-type';
@Component({
selector: 'keypress-tab',
@@ -1,6 +1,5 @@
import { Component, HostBinding, Input, OnChanges, SimpleChanges } from '@angular/core';
import { KeyAction, LayerName, SwitchLayerAction } from '../../../../config-serializer/config-items/key-action';
import { KeyAction, LayerName, SwitchLayerAction } from 'uhk-common';
import { Tab } from '../tab';
@@ -1,13 +1,8 @@
import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core';
import { Store } from '@ngrx/store';
import { Subscription } from 'rxjs/Subscription';
import { Select2OptionData } from 'ng2-select2/ng2-select2';
import { KeyAction, PlayMacroAction } from '../../../../config-serializer/config-items/key-action';
import { Macro } from '../../../../config-serializer/config-items/macro';
import { KeyAction, Macro, PlayMacroAction } from 'uhk-common';
import { Tab } from '../tab';
@@ -1,6 +1,6 @@
import { Component, Input, OnChanges } from '@angular/core';
import { KeyAction, MouseAction, MouseActionParam } from 'uhk-common';
import { KeyAction, MouseAction, MouseActionParam } from '../../../../config-serializer/config-items/key-action';
import { Tab } from '../tab';
@Component({
@@ -1,6 +1,5 @@
import { EventEmitter, Output } from '@angular/core';
import { KeyAction } from '../../../config-serializer/config-items/key-action';
import { KeyAction } from 'uhk-common';
export abstract class Tab {
@Output() validAction = new EventEmitter<boolean>();
@@ -1,5 +1,6 @@
import { Component, Renderer } from '@angular/core';
import { animate, state, style, transition, trigger } from '@angular/animations';
import { Keymap, Macro } from 'uhk-common';
import { Store } from '@ngrx/store';
@@ -8,9 +9,6 @@ import 'rxjs/add/operator/do';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/let';
import { Keymap } from '../../config-serializer/config-items/keymap';
import { Macro } from '../../config-serializer/config-items/macro';
import { AppState, showAddonMenu, runningInElectron } from '../../store';
import { MacroActions } from '../../store/actions';
import { getKeymaps, getMacros } from '../../store/reducers/user-configuration';
@@ -1,9 +1,10 @@
import { Component, EventEmitter, Input, OnInit, Output, SimpleChanges, ChangeDetectionStrategy } from '@angular/core';
import { animate, state, trigger, style, transition } from '@angular/animations';
import { Module } from 'uhk-common';
import { Module } from '../../../config-serializer/config-items/module';
import { SvgModule } from '../module';
import { SvgModuleProviderService } from '../../../services/svg-module-provider.service';
import { KeyboardLayout } from '../../../keyboard/keyboard-layout.enum';
@Component({
selector: 'svg-keyboard',
@@ -29,6 +30,7 @@ export class SvgKeyboardComponent implements OnInit {
@Input() selectedKey: { layerId: number, moduleId: number, keyId: number };
@Input() selected: boolean;
@Input() halvesSplit: boolean;
@Input() keyboardLayout = KeyboardLayout.ANSI;
@Output() keyClick = new EventEmitter();
@Output() keyHover = new EventEmitter();
@Output() capture = new EventEmitter();
@@ -45,13 +47,17 @@ export class SvgKeyboardComponent implements OnInit {
}
ngOnInit() {
this.modules = this.svgModuleProvider.getSvgModules();
this.setModules();
}
ngOnChanges(changes: SimpleChanges) {
if (changes.halvesSplit) {
this.updateModuleAnimationStates();
}
if (changes['keyboardLayout']) {
this.setModules();
}
}
onKeyClick(moduleId: number, keyId: number, keyTarget: HTMLElement): void {
@@ -87,4 +93,7 @@ export class SvgKeyboardComponent implements OnInit {
}
}
private setModules() {
this.modules = this.svgModuleProvider.getSvgModules(this.keyboardLayout);
}
}
@@ -10,15 +10,15 @@ import { Subscription } from 'rxjs/Subscription';
import {
KeyAction,
KeyModifiers,
KeystrokeAction,
LayerName,
Macro,
MouseAction,
PlayMacroAction,
SwitchKeymapAction,
SwitchLayerAction
} from '../../../../config-serializer/config-items/key-action';
import { KeyModifiers } from '../../../../config-serializer/config-items/key-modifiers';
import { Macro } from '../../../../config-serializer/config-items/macro';
} from 'uhk-common';
import { CaptureService } from '../../../../services/capture.service';
import { MapperService } from '../../../../services/mapper.service';
@@ -1,7 +1,6 @@
import { Component, Input, OnChanges, OnInit, ChangeDetectionStrategy } from '@angular/core';
import { KeyModifiers, KeystrokeAction } from 'uhk-common';
import { KeystrokeAction } from '../../../../config-serializer/config-items/key-action';
import { KeyModifiers } from '../../../../config-serializer/config-items/key-modifiers';
import { MapperService } from '../../../../services/mapper.service';
class SvgAttributes {
@@ -1,6 +1,6 @@
import { Component, Input, OnChanges, ChangeDetectionStrategy } from '@angular/core';
import { MouseAction, MouseActionParam } from '../../../../config-serializer/config-items/key-action';
import { MouseAction, MouseActionParam } from 'uhk-common';
@Component({
selector: 'g[svg-mouse-key]',
@@ -1,6 +1,5 @@
import { Component, EventEmitter, Input, Output, ChangeDetectionStrategy } from '@angular/core';
import { KeyAction } from '../../../config-serializer/config-items/key-action';
import { KeyAction } from 'uhk-common';
import { SvgKeyboardKey } from '../keys';
@@ -6,6 +6,7 @@
[capturingEnabled]="popoverEnabled"
[selectedKey]="selectedKey"
[halvesSplit]="halvesSplit"
[keyboardLayout]="keyboardLayout"
(keyClick)="onKeyClick($event.moduleId, $event.keyId, $event.keyTarget)"
(keyHover)="onKeyHover($event.moduleId, $event.event, $event.over, $event.keyId)"
(capture)="onCapture($event.moduleId, $event.keyId, $event.captured)"
@@ -17,26 +17,27 @@ import 'rxjs/add/observable/of';
import 'rxjs/add/operator/map';
import { Store } from '@ngrx/store';
import { MapperService } from '../../../services/mapper.service';
import {
camelCaseToSentence,
capitalizeFirstLetter,
KeyAction,
Keymap,
KeystrokeAction,
Layer,
LayerName,
LongPressAction,
MouseAction,
MouseActionParam,
PlayMacroAction,
SwitchKeymapAction,
SwitchLayerAction
} from '../../../config-serializer/config-items/key-action';
import { Keymap } from '../../../config-serializer/config-items/keymap';
import { Layer } from '../../../config-serializer/config-items/layer';
import { LongPressAction } from '../../../config-serializer/config-items/long-press-action';
import { camelCaseToSentence, capitalizeFirstLetter } from 'uhk-common';
} from 'uhk-common';
import { MapperService } from '../../../services/mapper.service';
import { AppState } from '../../../store';
import { KeymapActions } from '../../../store/actions';
import { PopoverComponent } from '../../popover';
import { KeyboardLayout } from '../../../keyboard/keyboard-layout.enum';
interface NameValuePair {
name: string;
@@ -54,6 +55,7 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges {
@Input() popoverEnabled: boolean = true;
@Input() tooltipEnabled: boolean = false;
@Input() halvesSplit: boolean;
@Input() keyboardLayout: KeyboardLayout.ANSI;
@ViewChild(PopoverComponent, { read: ElementRef }) popover: ElementRef;
@@ -1,6 +1,6 @@
import { Injectable } from '@angular/core';
import { UserConfiguration } from 'uhk-common';
import { UserConfiguration } from '../config-serializer/config-items/user-configuration';
import { AutoUpdateSettings } from '../models/auto-update-settings';
@Injectable()

Some files were not shown because too many files have changed in this diff Show More