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 18:57:27 +02:00
committed by László Monda
parent 1122784bdb
commit 9294bede50
130 changed files with 9108 additions and 1991 deletions

View File

@@ -0,0 +1,85 @@
# Configuration serializer
This directory contains the configuration serializer of Agent.
The configuration of the UHK is unusually complex for a keyboard, and is composed of a number of items of different types, including keymaps, layers, macros, and the like. This is a supposed to be a short guide for the aspiring hacker. Let's get right into it!
## Setup
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](../../../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.
The **binary representation** is meant to be written to, and read from the EEPROM of the UHK. It's designed to be very compact in order to maximize the use of the 32kbyte EEPROM space.
## Configuration item types
Each configuration item belongs to a specific type. The following types are available:
**Primitive types** are integers of different sizes, and string. See [UhkBuffer](UhkBuffer.ts) which implements all the primitive types.
**Compound types** are composed of primitive types, and/or compound types. All compound types are saved into the [config-items](config-items) directory.
## Dumping serialization
The serialization of configuration items is a complicated business, and many things can go wrong. That's the exact reason why serialization can be dumped to ease debugging. All you have to do is to set `Serializable.enableDump` to `true`, and you'll see something like the following upon serialization actions:
```
KeyActions.fromJsObject: [{"keyActionType":"none"},{"keyActionType":"keystroke","scancode":110},{"keyActionType":"keystrokeModifiers","modifierMask":33},{"keyActionType":"keystrokeWithM...
NoneAction.fromJsObject: {"keyActionType":"none"} => <NoneAction>
KeystrokeAction.fromJsObject: {"keyActionType":"keystroke","scancode":110} => <KeystrokeAction scancode="110">
KeystrokeModifiersAction.fromJsObject: {"keyActionType":"keystrokeModifiers","modifierMask":33} => <KeystrokeModifiersAction modifierMask="33">
KeystrokeWithModifiersAction.fromJsObject: {"keyActionType":"keystrokeWithModifiers","scancode":120,"modifierMask":16} => <KeystrokeWithModifiersAction scancode="120" modifierMask="16">
SwitchLayerAction.fromJsObject: {"keyActionType":"switchLayer","layer":"fn","toggle":false} => <SwitchLayerAction layer="1" toggle="false">
DualRoleKeystrokeAction.fromJsObject: {"keyActionType":"dualRoleKeystroke","scancode":111,"longPressAction":"mod"} => <DualRoleKeystrokeAction scancode="111" longPressAction="8">
MouseAction.fromJsObject: {"keyActionType":"mouse","mouseAction":"scrollDown"} => <MouseAction mouseAction="8">
PlayMacroAction.fromJsObject: {"keyActionType":"playMacro","macroId":0} => <PlayMacroAction macroId="0">
SwitchKeymapAction.fromJsObject: {"keyActionType":"switchKeymap","keymapId":1} => <SwitchKeymapAction keymapId="1">
KeyActions.toBinary: <KeyActions length="9"> => ['u8(9)]
NoneAction.toBinary: <NoneAction> => ['u8(0)]
KeystrokeAction.toBinary: <KeystrokeAction scancode="110"> => ['u8(1), u8(110)]
KeystrokeModifiersAction.toBinary: <KeystrokeModifiersAction modifierMask="33"> => ['u8(2), u8(33)]
KeystrokeWithModifiersAction.toBinary: <KeystrokeWithModifiersAction scancode="120" modifierMask="16"> => ['u8(3), u8(120), u8(16)]
SwitchLayerAction.toBinary: <SwitchLayerAction layer="1" toggle="false"> => ['u8(5), u8(1)]
DualRoleKeystrokeAction.toBinary: <DualRoleKeystrokeAction scancode="111" longPressAction="8"> => ['u8(4), u8(111), u8(8)]
MouseAction.toBinary: <MouseAction mouseAction="8"> => ['u8(7), u8(8)]
PlayMacroAction.toBinary: <PlayMacroAction macroId="0"> => ['u8(8), u8(0)]
SwitchKeymapAction.toBinary: <SwitchKeymapAction keymapId="1"> => ['u8(6), u8(1)]
KeyActions.fromBinary: [u8(9)]
NoneAction.fromBinary: [u8(0)] => <NoneAction>
KeystrokeAction.fromBinary: [u8(1), u8(110)] => <KeystrokeAction scancode="110">
KeystrokeModifiersAction.fromBinary: [u8(2), u8(33)] => <KeystrokeModifiersAction modifierMask="33">
KeystrokeWithModifiersAction.fromBinary: [u8(3), u8(120), u8(16)] => <KeystrokeWithModifiersAction scancode="120" modifierMask="16">
SwitchLayerAction.fromBinary: [u8(5), u8(1)] => <SwitchLayerAction layer="1" toggle="false">
DualRoleKeystrokeAction.fromBinary: [u8(4), u8(111), u8(8)] => <DualRoleKeystrokeAction scancode="111" longPressAction="8">
MouseAction.fromBinary: [u8(7), u8(8)] => <MouseAction mouseAction="8">
PlayMacroAction.fromBinary: [u8(8), u8(0)] => <PlayMacroAction macroId="0">
SwitchKeymapAction.fromBinary: [u8(6), u8(1)] => <SwitchKeymapAction keymapId="1">
KeyActions.toJsObject: <KeyActions length="9">
NoneAction.toJsObject: <NoneAction> => {"keyActionType":"none"}
KeystrokeAction.toJsObject: <KeystrokeAction scancode="110"> => {"keyActionType":"keystroke","scancode":110}
KeystrokeModifiersAction.toJsObject: <KeystrokeModifiersAction modifierMask="33"> => {"keyActionType":"keystrokeModifiers","modifierMask":33}
KeystrokeWithModifiersAction.toJsObject: <KeystrokeWithModifiersAction scancode="120" modifierMask="16"> => {"keyActionType":"keystrokeWithModifiers","scancode":120,"modifierMask":16}
SwitchLayerAction.toJsObject: <SwitchLayerAction layer="1" toggle="false"> => {"keyActionType":"switchLayer","layer":"fn","toggle":false}
DualRoleKeystrokeAction.toJsObject: <DualRoleKeystrokeAction scancode="111" longPressAction="8"> => {"keyActionType":"dualRoleKeystroke","scancode":111,"longPressAction":"mod"}
MouseAction.toJsObject: <MouseAction mouseAction="8"> => {"keyActionType":"mouse","mouseAction":"scrollDown"}
PlayMacroAction.toJsObject: <PlayMacroAction macroId="0"> => {"keyActionType":"playMacro","macroId":0}
SwitchKeymapAction.toJsObject: <SwitchKeymapAction keymapId="1"> => {"keyActionType":"switchKeymap","keymapId":1}
```
## Testing the serializer
[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:
```
JSON configurations are identical.
Binary configurations are identical.
```

View File

@@ -0,0 +1,78 @@
export function assertUInt8(target: any, key: string) {
return assertInteger(target, key, 0, 0xFF);
}
export function assertInt8(target: any, key: string) {
return assertInteger(target, key, -0x80, 0x7F);
}
export function assertUInt16(target: any, key: string) {
return assertInteger(target, key, 0, 0xFFFF);
}
export function assertInt16(target: any, key: string) {
return assertInteger(target, key, -0x8000, 0x7FFF);
}
export function assertUInt32(target: any, key: string) {
return assertInteger(target, key, 0, 0xFFFFFFFF);
}
export function assertInt32(target: any, key: string) {
return assertInteger(target, key, -0x80000000, 0x7FFFFFFF);
}
export function assertCompactLength(target: any, key: string) {
return assertUInt16(target, key);
}
function assertInteger(target: any, key: string, min: number, max: number) {
const priv = '_' + key;
function getter() {
return this[priv];
}
function setter(newVal: any) {
if (this[priv] !== newVal) {
if (newVal < min || newVal > max) {
throw `${target.constructor.name}.${key}: ` +
`Integer ${newVal} is outside the valid [${min}, ${max}] interval`;
}
this[priv] = newVal;
}
}
Object.defineProperty(target, key, {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
}
export function assertEnum<E>(enumerated: E) {
return function(target: any, key: string) {
const priv = '_' + key;
function getter() {
return this[priv];
}
function setter(newVal: any) {
if (this[priv] !== newVal) {
if (enumerated[newVal] === undefined) {
throw `${target.constructor.name}.${key}: ${newVal} is not enum`;
}
this[priv] = newVal;
}
}
Object.defineProperty(target, key, {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
};
}

View File

@@ -0,0 +1,72 @@
import { assertUInt8, assertUInt32 } from '../assert';
import { UhkBuffer } from '../uhk-buffer';
export class HardwareConfiguration {
signature: string;
@assertUInt8
dataModelVersion: number;
@assertUInt8
hardwareId: number;
@assertUInt8
brandId: number;
@assertUInt32
uuid: number;
isIso: boolean;
hasBacklighting: boolean;
fromJsonObject(jsonObject: any): HardwareConfiguration {
this.signature = jsonObject.signature;
this.dataModelVersion = jsonObject.dataModelVersion;
this.hardwareId = jsonObject.hardwareId;
this.brandId = jsonObject.brandId;
this.uuid = jsonObject.uuid;
this.isIso = jsonObject.isIso;
this.hasBacklighting = jsonObject.hasBacklighting;
return this;
}
fromBinary(buffer: UhkBuffer): HardwareConfiguration {
this.signature = buffer.readString();
this.dataModelVersion = buffer.readUInt16();
this.hardwareId = buffer.readUInt8();
this.uuid = buffer.readUInt32();
this.brandId = buffer.readUInt8();
this.isIso = buffer.readBoolean();
this.hasBacklighting = buffer.readBoolean();
return this;
}
toJsonObject(): any {
return {
signature: this.signature,
dataModelVersion: this.dataModelVersion,
hardwareId: this.hardwareId,
brandId: this.brandId,
uuid: this.uuid,
isIso: this.isIso,
hasBacklighting: this.hasBacklighting
};
}
toBinary(buffer: UhkBuffer): void {
buffer.writeString(this.signature);
buffer.writeUInt16(this.dataModelVersion);
buffer.writeUInt8(this.hardwareId);
buffer.writeUInt8(this.brandId);
buffer.writeUInt32(this.uuid);
buffer.writeBoolean(this.isIso);
buffer.writeBoolean(this.hasBacklighting);
}
toString(): string {
return `<HardwareConfiguration signature="${this.signature}">`;
}
}

View File

@@ -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';

View File

@@ -0,0 +1,84 @@
import { UhkBuffer } from '../../uhk-buffer';
import { Macro } from '../macro';
import { KeyAction, KeyActionId, keyActionType } from './key-action';
import { KeystrokeAction } from './keystroke-action';
import { SwitchLayerAction } from './switch-layer-action';
import { SwitchKeymapAction, UnresolvedSwitchKeymapAction } from './switch-keymap-action';
import { MouseAction } from './mouse-action';
import { PlayMacroAction } from './play-macro-action';
export class Helper {
static createKeyAction(source: KeyAction | UhkBuffer | any, macros?: Macro[]): KeyAction {
if (source instanceof KeyAction) {
return Helper.fromKeyAction(source);
} else if (source instanceof UhkBuffer) {
return Helper.fromUhkBuffer(source, macros);
} else {
return Helper.fromJSONObject(source, macros);
}
}
private static fromUhkBuffer(buffer: UhkBuffer, macros: Macro[]): KeyAction {
const keyActionFirstByte = buffer.readUInt8();
buffer.backtrack();
if (keyActionFirstByte >= KeyActionId.KeystrokeAction && keyActionFirstByte < KeyActionId.LastKeystrokeAction) {
return new KeystrokeAction().fromBinary(buffer);
}
switch (keyActionFirstByte) {
case KeyActionId.NoneAction:
buffer.readUInt8(); // Read type just to skip it
return undefined;
case KeyActionId.SwitchLayerAction:
return new SwitchLayerAction().fromBinary(buffer);
case KeyActionId.SwitchKeymapAction:
return new UnresolvedSwitchKeymapAction().fromBinary(buffer);
case KeyActionId.MouseAction:
return new MouseAction().fromBinary(buffer);
case KeyActionId.PlayMacroAction:
return new PlayMacroAction().fromBinary(buffer, macros);
default:
throw `Invalid KeyAction first byte: ${keyActionFirstByte}`;
}
}
private static fromKeyAction(keyAction: KeyAction): KeyAction {
let newKeyAction: KeyAction;
if (keyAction instanceof KeystrokeAction) {
newKeyAction = new KeystrokeAction(keyAction);
} else if (keyAction instanceof SwitchLayerAction) {
newKeyAction = new SwitchLayerAction(keyAction);
} else if (keyAction instanceof SwitchKeymapAction) {
newKeyAction = new SwitchKeymapAction(keyAction);
} else if (keyAction instanceof MouseAction) {
newKeyAction = new MouseAction(keyAction);
} else if (keyAction instanceof PlayMacroAction) {
newKeyAction = new PlayMacroAction(keyAction);
}
return newKeyAction;
}
private static fromJSONObject(keyAction: any, macros: Macro[]): KeyAction {
if (!keyAction) {
return;
}
switch (keyAction.keyActionType) {
case keyActionType.KeystrokeAction:
return new KeystrokeAction().fromJsonObject(keyAction);
case keyActionType.SwitchLayerAction:
return new SwitchLayerAction().fromJsonObject(keyAction);
case keyActionType.SwitchKeymapAction:
return new SwitchKeymapAction().fromJsonObject(keyAction);
case keyActionType.MouseAction:
return new MouseAction().fromJsonObject(keyAction);
case keyActionType.PlayMacroAction:
return new PlayMacroAction().fromJsonObject(keyAction, macros);
default:
throw `Invalid KeyAction.keyActionType: "${keyAction.keyActionType}"`;
}
}
}

View File

@@ -0,0 +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 { Helper as KeyActionHelper } from './helper';

View File

@@ -0,0 +1,65 @@
import { Macro } from '../macro';
import { UhkBuffer } from '../../uhk-buffer';
import { UserConfiguration } from '../user-configuration';
export enum KeyActionId {
NoneAction = 0,
KeystrokeAction = 1,
/*
1 - 31 are reserved for KeystrokeAction
5 bits:
1: Do we have scancode?
2: Do we have modifiers?
3: Do we have longpress?
4-5: What kind of keystroke? (basic, short/long media, system)
*/
LastKeystrokeAction = 31, // TODO: remove this after refactoring the keyActionId check
SwitchLayerAction = 32,
SwitchKeymapAction = 33,
MouseAction = 34,
PlayMacroAction = 35
}
export let keyActionType = {
NoneAction : 'none',
KeystrokeAction : 'keystroke',
SwitchLayerAction : 'switchLayer',
SwitchKeymapAction : 'switchKeymap',
MouseAction : 'mouse',
PlayMacroAction : 'playMacro'
};
export abstract class KeyAction {
assertKeyActionType(jsObject: any): void {
const keyActionClassname: string = this.getName();
const keyActionTypeString: string = keyActionType[keyActionClassname];
if (jsObject.keyActionType !== keyActionTypeString) {
throw `Invalid ${keyActionClassname}.keyActionType: ${jsObject.keyActionType}`;
}
}
readAndAssertKeyActionId(buffer: UhkBuffer): KeyActionId {
const classname: string = this.getName();
const readKeyActionId: number = buffer.readUInt8();
const keyActionId: number = KeyActionId[classname];
if (keyActionId === KeyActionId.KeystrokeAction) {
if (readKeyActionId < KeyActionId.KeystrokeAction || readKeyActionId > KeyActionId.LastKeystrokeAction) {
throw `Invalid ${classname} first byte: ${readKeyActionId}`;
}
} else if (readKeyActionId !== keyActionId) {
throw `Invalid ${classname} first byte: ${readKeyActionId}`;
}
return readKeyActionId;
}
abstract toJsonObject(macros?: Macro[]): any;
abstract toBinary(buffer: UhkBuffer, userConfiguration?: UserConfiguration): void;
abstract getName(): string;
renameKeymap(oldAbbr: string, newAbbr: string): KeyAction {
return this;
}
}

View File

@@ -0,0 +1,215 @@
import { assertEnum, assertUInt8 } from '../../assert';
import { UhkBuffer } from '../../uhk-buffer';
import { KeyModifiers } from '../key-modifiers';
import { LongPressAction } from '../long-press-action';
import { KeyAction, KeyActionId, keyActionType } from './key-action';
import { KeystrokeType } from './keystroke-type';
export enum KeystrokeActionFlag {
scancode = 1 << 0,
modifierMask = 1 << 1,
longPressAction = 1 << 2
}
const KEYSTROKE_ACTION_FLAG_LENGTH = 3;
interface JsonObjectKeystrokeAction {
keyActionType: string;
scancode?: number;
modifierMask?: number;
longPressAction?: string;
type?: string;
}
const MODIFIERS = ['LCtrl', 'LShift', 'LAlt', 'LSuper', 'RCtrl', 'RShift', 'RAlt', 'RSuper'];
export class KeystrokeAction extends KeyAction {
set scancode(scancode: number) {
this._scancode = scancode;
if (this.type !== KeystrokeType.shortMedia && this.type !== KeystrokeType.longMedia) {
return;
}
this.type = scancode < 256 ? KeystrokeType.shortMedia : KeystrokeType.longMedia;
}
get scancode() {
return this._scancode;
}
@assertUInt8
modifierMask: number;
@assertEnum(LongPressAction)
longPressAction: LongPressAction;
set type(type: KeystrokeType) {
if (type === KeystrokeType.shortMedia || type === KeystrokeType.longMedia) {
type = this.scancode < 256 ? KeystrokeType.shortMedia : KeystrokeType.longMedia;
}
this._type = type;
}
get type() {
return this._type;
}
private _scancode: number;
@assertEnum(KeystrokeType)
private _type: KeystrokeType;
constructor(other?: KeystrokeAction) {
super();
if (!other) {
return;
}
this.type = other.type;
this._scancode = other._scancode;
this.modifierMask = other.modifierMask;
this.longPressAction = other.longPressAction;
}
fromJsonObject(jsonObject: JsonObjectKeystrokeAction): KeystrokeAction {
this.assertKeyActionType(jsonObject);
if (jsonObject.type === 'media') {
this.type = jsonObject.scancode < 256 ? KeystrokeType.shortMedia : KeystrokeType.longMedia;
} else {
this.type = KeystrokeType[jsonObject.type];
}
this._scancode = jsonObject.scancode;
this.modifierMask = jsonObject.modifierMask;
this.longPressAction = LongPressAction[jsonObject.longPressAction];
return this;
}
fromBinary(buffer: UhkBuffer): KeystrokeAction {
const keyActionId: KeyActionId = this.readAndAssertKeyActionId(buffer);
const flags: number = keyActionId - KeyActionId.NoneAction; // NoneAction is the same as an empty KeystrokeAction.
this.type = (flags >> 3) & 0b11;
if (flags & KeystrokeActionFlag.scancode) {
this._scancode = this.type === KeystrokeType.longMedia ? buffer.readUInt16() : buffer.readUInt8();
}
if (flags & KeystrokeActionFlag.modifierMask) {
this.modifierMask = buffer.readUInt8();
}
if (flags & KeystrokeActionFlag.longPressAction) {
this.longPressAction = buffer.readUInt8();
}
return this;
}
toJsonObject(): JsonObjectKeystrokeAction {
const jsonObject: JsonObjectKeystrokeAction = {
keyActionType: keyActionType.KeystrokeAction
};
if (this.type === KeystrokeType.shortMedia || this.type === KeystrokeType.longMedia) {
jsonObject.type = 'media';
} else {
jsonObject.type = KeystrokeType[this.type];
}
if (this.hasScancode()) {
jsonObject.scancode = this._scancode;
}
if (this.hasActiveModifier()) {
jsonObject.modifierMask = this.modifierMask;
}
if (this.hasLongPressAction()) {
jsonObject.longPressAction = LongPressAction[this.longPressAction];
}
return jsonObject;
}
toBinary(buffer: UhkBuffer) {
let flags = 0;
const toWrite: {
data: number,
long: boolean
}[] = [];
if (this.hasScancode()) {
flags |= KeystrokeActionFlag.scancode;
toWrite.push({ data: this._scancode, long: this.type === KeystrokeType.longMedia });
}
if (this.hasActiveModifier()) {
flags |= KeystrokeActionFlag.modifierMask;
toWrite.push({ data: this.modifierMask, long: false });
}
if (this.hasLongPressAction()) {
flags |= KeystrokeActionFlag.longPressAction;
toWrite.push({ data: this.longPressAction, long: false });
}
const TYPE_OFFSET = flags + (this.type << KEYSTROKE_ACTION_FLAG_LENGTH);
buffer.writeUInt8(KeyActionId.NoneAction + TYPE_OFFSET); // NoneAction is the same as an empty KeystrokeAction.
for (let i = 0; i < toWrite.length; ++i) {
if (toWrite[i].long) {
buffer.writeUInt16(toWrite[i].data);
} else {
buffer.writeUInt8(toWrite[i].data);
}
}
}
toString(): string {
const properties: string[] = [];
properties.push(`type="${KeystrokeType[this.type]}"`);
if (this.hasScancode()) {
properties.push(`scancode="${this._scancode}"`);
}
if (this.hasActiveModifier()) {
properties.push(`modifierMask="${this.modifierMask}"`);
}
if (this.hasLongPressAction()) {
properties.push(`longPressAction="${this.longPressAction}"`);
}
return `<KeystrokeAction ${properties.join(' ')}>`;
}
isActive(modifier: KeyModifiers): boolean {
return (this.modifierMask & modifier) > 0;
}
hasActiveModifier(): boolean {
return this.modifierMask > 0;
}
hasLongPressAction(): boolean {
return this.longPressAction !== undefined;
}
hasScancode(): boolean {
return !!this._scancode;
}
hasOnlyOneActiveModifier(): boolean {
return this.modifierMask !== 0 && !(this.modifierMask & this.modifierMask - 1);
}
getModifierList(): string[] {
const modifierList: string[] = [];
let modifierMask = this.modifierMask;
for (let i = 0; modifierMask !== 0; ++i, modifierMask >>= 1) {
if (modifierMask & 1) {
modifierList.push(MODIFIERS[i]);
}
}
return modifierList;
}
public getName(): string {
return 'KeystrokeAction';
}
}

View File

@@ -0,0 +1,6 @@
export enum KeystrokeType {
basic,
shortMedia,
longMedia,
system
}

View File

@@ -0,0 +1,65 @@
import { assertEnum } from '../../assert';
import { UhkBuffer } from '../../uhk-buffer';
import { KeyAction, KeyActionId, keyActionType } from './key-action';
export enum MouseActionParam {
leftClick,
middleClick,
rightClick,
moveUp,
moveDown,
moveLeft,
moveRight,
scrollUp,
scrollDown,
scrollLeft,
scrollRight,
accelerate,
decelerate
}
export class MouseAction extends KeyAction {
@assertEnum(MouseActionParam)
mouseAction: MouseActionParam;
constructor(other?: MouseAction) {
super();
if (!other) {
return;
}
this.mouseAction = other.mouseAction;
}
fromJsonObject(jsObject: any): MouseAction {
this.assertKeyActionType(jsObject);
this.mouseAction = MouseActionParam[<string>jsObject.mouseAction];
return this;
}
fromBinary(buffer: UhkBuffer): MouseAction {
this.readAndAssertKeyActionId(buffer);
this.mouseAction = buffer.readUInt8();
return this;
}
toJsonObject(): any {
return {
keyActionType: keyActionType.MouseAction,
mouseAction: MouseActionParam[this.mouseAction]
};
}
toBinary(buffer: UhkBuffer) {
buffer.writeUInt8(KeyActionId.MouseAction);
buffer.writeUInt8(this.mouseAction);
}
toString(): string {
return `<MouseAction mouseAction="${this.mouseAction}">`;
}
public getName(): string {
return 'MouseAction';
}
}

View File

@@ -0,0 +1,39 @@
import { UhkBuffer } from '../../uhk-buffer';
import { KeyAction, KeyActionId, keyActionType } from './key-action';
/**
* NoneAction is only intended for binary serialization of undefined key actions
* DO NOT use it as a real KeyAction
*
*/
export class NoneAction extends KeyAction {
fromJsonObject(jsonObject: any): NoneAction {
this.assertKeyActionType(jsonObject);
return this;
}
fromBinary(buffer: UhkBuffer): NoneAction {
this.readAndAssertKeyActionId(buffer);
return this;
}
toJsonObject(): any {
return {
keyActionType: keyActionType.NoneAction
};
}
toBinary(buffer: UhkBuffer) {
buffer.writeUInt8(KeyActionId.NoneAction);
}
toString(): string {
return '<NoneAction>';
}
public getName(): string {
return 'NoneAction';
}
}

View File

@@ -0,0 +1,56 @@
import { assertUInt8 } from '../../assert';
import { UhkBuffer } from '../../uhk-buffer';
import { Macro } from '../macro';
import { KeyAction, KeyActionId, keyActionType } from './key-action';
import { UserConfiguration } from '../user-configuration';
export class PlayMacroAction extends KeyAction {
@assertUInt8
macroId: number;
constructor(parameter?: PlayMacroAction | Macro) {
super();
if (!parameter) {
return;
}
if (parameter instanceof PlayMacroAction) {
this.macroId = parameter.macroId;
} else {
this.macroId = parameter.id;
}
}
fromJsonObject(jsonObject: any, macros: Macro[]): PlayMacroAction {
this.assertKeyActionType(jsonObject);
this.macroId = macros[jsonObject.macroIndex].id;
return this;
}
fromBinary(buffer: UhkBuffer, macros: Macro[]): PlayMacroAction {
this.readAndAssertKeyActionId(buffer);
const macroIndex = buffer.readUInt8();
this.macroId = macros[macroIndex].id;
return this;
}
toJsonObject(macros: Macro[]): any {
return {
keyActionType: keyActionType.PlayMacroAction,
macroIndex: macros.findIndex(macro => macro.id === this.macroId)
};
}
toBinary(buffer: UhkBuffer, userConfiguration: UserConfiguration) {
buffer.writeUInt8(KeyActionId.PlayMacroAction);
buffer.writeUInt8(userConfiguration.macros.findIndex(macro => macro.id === this.macroId));
}
toString(): string {
return `<PlayMacroAction macroId="${this.macroId}">`;
}
public getName(): string {
return 'PlayMacroAction';
}
}

View File

@@ -0,0 +1,92 @@
import { assertUInt8 } from '../../assert';
import { UhkBuffer } from '../../uhk-buffer';
import { Keymap } from '../keymap';
import { KeyAction, KeyActionId, keyActionType } from './key-action';
import { UserConfiguration } from '../user-configuration';
export class SwitchKeymapAction extends KeyAction {
keymapAbbreviation: string;
constructor(parameter?: SwitchKeymapAction | Keymap | string) {
super();
if (!parameter) {
return;
}
if (parameter instanceof SwitchKeymapAction) {
this.keymapAbbreviation = parameter.keymapAbbreviation;
} else if (parameter instanceof Keymap) {
this.keymapAbbreviation = parameter.abbreviation;
} else {
this.keymapAbbreviation = parameter;
}
}
fromJsonObject(jsonObject: any): SwitchKeymapAction {
this.assertKeyActionType(jsonObject);
this.keymapAbbreviation = jsonObject.keymapAbbreviation;
return this;
}
toJsonObject(): any {
return {
keyActionType: keyActionType.SwitchKeymapAction,
keymapAbbreviation: this.keymapAbbreviation
};
}
toBinary(buffer: UhkBuffer, userConfiguration: UserConfiguration): void {
const keymapIndex = userConfiguration.keymaps.findIndex(keymap => keymap.abbreviation === this.keymapAbbreviation);
buffer.writeUInt8(KeyActionId.SwitchKeymapAction);
buffer.writeUInt8(keymapIndex);
}
toString(): string {
return `<SwitchKeymapAction keymapAbbreviation="${this.keymapAbbreviation}">`;
}
renameKeymap(oldAbbr: string, newAbbr: string): KeyAction {
if (this.keymapAbbreviation !== oldAbbr) {
return this;
}
return new SwitchKeymapAction(newAbbr);
}
public getName(): string {
return 'SwitchKeymapAction';
}
}
export class UnresolvedSwitchKeymapAction extends KeyAction {
@assertUInt8
keymapIndex: number;
constructor(keymapIndex?: number) {
super();
this.keymapIndex = keymapIndex;
}
fromBinary(buffer: UhkBuffer): UnresolvedSwitchKeymapAction {
buffer.readUInt8(); // Skip key action id
this.keymapIndex = buffer.readUInt8();
return this;
}
toBinary(buffer: UhkBuffer) {
buffer.writeUInt8(KeyActionId.SwitchKeymapAction);
buffer.writeUInt8(this.keymapIndex);
}
toJsonObject(): any {
throw new Error('UnresolvedSwitchKeymapAction cannot be serialized directly. Convert it to SwitchKeymapAction first.');
}
resolve(keymaps: Keymap[]): SwitchKeymapAction {
return new SwitchKeymapAction(keymaps[this.keymapIndex]);
}
public getName(): string {
return 'UnresolvedSwitchKeymapAction';
}
}

View File

@@ -0,0 +1,62 @@
import { assertEnum } from '../../assert';
import { UhkBuffer } from '../../uhk-buffer';
import { KeyAction, KeyActionId, keyActionType } from './key-action';
export enum LayerName {
mod,
fn,
mouse
}
export class SwitchLayerAction extends KeyAction {
isLayerToggleable: boolean;
@assertEnum(LayerName)
layer: LayerName;
constructor(other?: SwitchLayerAction) {
super();
if (!other) {
return;
}
this.isLayerToggleable = other.isLayerToggleable;
this.layer = other.layer;
}
fromJsonObject(jsonObject: any): SwitchLayerAction {
this.assertKeyActionType(jsonObject);
this.layer = LayerName[<string>jsonObject.layer];
this.isLayerToggleable = jsonObject.toggle;
return this;
}
fromBinary(buffer: UhkBuffer): SwitchLayerAction {
this.readAndAssertKeyActionId(buffer);
this.layer = buffer.readUInt8();
this.isLayerToggleable = buffer.readBoolean();
return this;
}
toJsonObject(): any {
return {
keyActionType: keyActionType.SwitchLayerAction,
layer: LayerName[this.layer],
toggle: this.isLayerToggleable
};
}
toBinary(buffer: UhkBuffer) {
buffer.writeUInt8(KeyActionId.SwitchLayerAction);
buffer.writeUInt8(this.layer);
buffer.writeBoolean(this.isLayerToggleable);
}
toString(): string {
return `<SwitchLayerAction layer="${this.layer}" toggle="${this.isLayerToggleable}">`;
}
public getName(): string {
return 'SwitchLayerAction';
}
}

View File

@@ -0,0 +1,10 @@
export enum KeyModifiers {
leftCtrl = 1 << 0,
leftShift = 1 << 1,
leftAlt = 1 << 2,
leftGui = 1 << 3,
rightCtrl = 1 << 4,
rightShift = 1 << 5,
rightAlt = 1 << 6,
rightGui = 1 << 7
}

View File

@@ -0,0 +1,126 @@
import { UhkBuffer } from '../uhk-buffer';
import { Layer } from './layer';
import { Macro } from './macro';
import { SwitchLayerAction } from './key-action/switch-layer-action';
import { KeyAction } from './key-action/key-action';
import { UserConfiguration } from './user-configuration';
export class Keymap {
name: string;
description: string;
abbreviation: string;
isDefault: boolean;
layers: Layer[];
constructor(keymap?: Keymap) {
if (!keymap) {
return;
}
this.name = keymap.name;
this.description = keymap.description;
this.abbreviation = keymap.abbreviation;
this.isDefault = keymap.isDefault;
this.layers = keymap.layers.map(layer => new Layer(layer));
}
fromJsonObject(jsonObject: any, macros?: Macro[]): Keymap {
this.isDefault = jsonObject.isDefault;
this.abbreviation = jsonObject.abbreviation;
this.name = jsonObject.name;
this.description = jsonObject.description;
this.layers = jsonObject.layers.map((layer: any) => new Layer().fromJsonObject(layer, macros));
this.normalize();
return this;
}
fromBinary(buffer: UhkBuffer, macros?: Macro[]): Keymap {
this.abbreviation = buffer.readString();
this.isDefault = buffer.readBoolean();
this.name = buffer.readString();
this.description = buffer.readString();
this.layers = buffer.readArray<Layer>(uhkBuffer => {
return new Layer().fromBinary(uhkBuffer, macros);
});
this.normalize();
return this;
}
toJsonObject(macros?: Macro[]): any {
return {
isDefault: this.isDefault,
abbreviation: this.abbreviation,
name: this.name,
description: this.description,
layers: this.layers.map(layer => layer.toJsonObject(macros))
};
}
toBinary(buffer: UhkBuffer, userConfiguration: UserConfiguration): void {
buffer.writeString(this.abbreviation);
buffer.writeBoolean(this.isDefault);
buffer.writeString(this.name);
buffer.writeString(this.description);
buffer.writeArray(this.layers, (uhkBuffer: UhkBuffer, layer: Layer) => {
layer.toBinary(uhkBuffer, userConfiguration);
});
}
toString(): string {
return `<Keymap abbreviation="${this.abbreviation}" name="${this.name}">`;
}
renameKeymap(oldAbbr: string, newAbbr: string): Keymap {
let layers: Layer[];
let layerModified = false;
this.layers.forEach((layer, index) => {
const newLayer = layer.renameKeymap(oldAbbr, newAbbr);
if (newLayer !== layer) {
if (!layerModified) {
layers = this.layers.slice();
layerModified = true;
}
layers[index] = newLayer;
}
});
if (layerModified) {
const newKeymap = Object.assign(new Keymap(), this);
newKeymap.layers = layers;
return newKeymap;
}
return this;
}
private normalize() {
// Removes all the SwitchLayerActions from any non base layer
for (let i = 1; i < this.layers.length; ++i) {
for (const module of this.layers[i].modules) {
module.keyActions = module.keyActions.map(keyAction => {
if (keyAction instanceof SwitchLayerAction) {
return undefined;
}
return keyAction;
});
}
}
// Adds the SwitchLayerActions from the base layer to any none base layer
const baseLayerModules = this.layers[0].modules;
for (let i = 0; i < baseLayerModules.length; ++i) {
baseLayerModules[i].keyActions.forEach((keyAction: KeyAction, keyActionIndex: number) => {
if (keyAction instanceof SwitchLayerAction) {
for (let j = 1; j < this.layers.length; ++j) {
this.layers[j].modules[i].keyActions[keyActionIndex] = new SwitchLayerAction(keyAction);
}
}
});
}
}
}

View File

@@ -0,0 +1,66 @@
import { UhkBuffer } from '../uhk-buffer';
import { Macro } from './macro';
import { Module } from './module';
import { UserConfiguration } from './user-configuration';
export class Layer {
modules: Module[];
constructor(layers?: Layer) {
if (!layers) {
return;
}
this.modules = layers.modules.map(module => new Module(module));
}
fromJsonObject(jsonObject: any, macros?: Macro[]): Layer {
this.modules = jsonObject.modules.map((module: any) => new Module().fromJsonObject(module, macros));
return this;
}
fromBinary(buffer: UhkBuffer, macros?: Macro[]): Layer {
this.modules = buffer.readArray<Module>(uhkBuffer => {
return new Module().fromBinary(uhkBuffer, macros);
});
return this;
}
toJsonObject(macros?: Macro[]): any {
return {
modules: this.modules.map(module => module.toJsonObject(macros))
};
}
toBinary(buffer: UhkBuffer, userConfiguration: UserConfiguration): void {
buffer.writeArray(this.modules, (uhkBuffer: UhkBuffer, module: Module) => {
module.toBinary(uhkBuffer, userConfiguration);
});
}
toString(): string {
return `<Layer>`;
}
renameKeymap(oldAbbr: string, newAbbr: string): Layer {
let modules: Module[];
let moduleModified = false;
this.modules.forEach((module, index) => {
const newModule = module.renameKeymap(oldAbbr, newAbbr);
if (newModule !== module) {
if (!moduleModified) {
modules = this.modules.slice();
moduleModified = true;
}
modules[index] = newModule;
}
});
if (moduleModified) {
const newLayer = Object.assign(new Layer(), this);
newLayer.modules = modules;
return newLayer;
}
return this;
}
}

View File

@@ -0,0 +1,13 @@
export enum LongPressAction {
leftCtrl,
leftShift,
leftAlt,
leftSuper,
rightCtrl,
rightShift,
rightAlt,
rightSuper,
mod,
fn,
mouse
}

View File

@@ -0,0 +1,49 @@
import { assertUInt16 } from '../../assert';
import { UhkBuffer } from '../../uhk-buffer';
import { MacroAction, MacroActionId, macroActionType } from './macro-action';
export class DelayMacroAction extends MacroAction {
@assertUInt16
delay: number;
constructor(other?: DelayMacroAction) {
super();
if (!other) {
return;
}
this.delay = other.delay;
}
fromJsonObject(jsObject: any): DelayMacroAction {
this.assertMacroActionType(jsObject);
this.delay = jsObject.delay;
return this;
}
fromBinary(buffer: UhkBuffer): DelayMacroAction {
this.readAndAssertMacroActionId(buffer);
this.delay = buffer.readUInt16();
return this;
}
toJsonObject(): any {
return {
macroActionType: macroActionType.DelayMacroAction,
delay: this.delay
};
}
toBinary(buffer: UhkBuffer) {
buffer.writeUInt8(MacroActionId.DelayMacroAction);
buffer.writeUInt16(this.delay);
}
toString(): string {
return `<DelayMacroAction delay="${this.delay}">`;
}
public getName(): string {
return 'DelayMacroAction';
}
}

View File

@@ -0,0 +1,84 @@
import { UhkBuffer } from '../../uhk-buffer';
import { MacroAction, MacroActionId, macroActionType } from './macro-action';
import { KeyMacroAction } from './key-macro-action';
import { MouseButtonMacroAction } from './mouse-button-macro-action';
import { MoveMouseMacroAction } from './move-mouse-macro-action';
import { ScrollMouseMacroAction } from './scroll-mouse-macro-action';
import { DelayMacroAction } from './delay-macro-action';
import { TextMacroAction } from './text-macro-action';
export class Helper {
static createMacroAction(source: MacroAction | UhkBuffer | any): MacroAction {
if (source instanceof MacroAction) {
return Helper.fromMacroAction(source);
} else if (source instanceof UhkBuffer) {
return Helper.fromUhkBuffer(source);
} else {
return Helper.fromJSONObject(source);
}
}
private static fromUhkBuffer(buffer: UhkBuffer): MacroAction {
const macroActionFirstByte = buffer.readUInt8();
buffer.backtrack();
if (macroActionFirstByte >= MacroActionId.KeyMacroAction && macroActionFirstByte <= MacroActionId.LastKeyMacroAction) {
return new KeyMacroAction().fromBinary(buffer);
} else if (
macroActionFirstByte >= MacroActionId.MouseButtonMacroAction &&
macroActionFirstByte <= MacroActionId.LastMouseButtonMacroAction
) {
return new MouseButtonMacroAction().fromBinary(buffer);
}
switch (macroActionFirstByte) {
case MacroActionId.MoveMouseMacroAction:
return new MoveMouseMacroAction().fromBinary(buffer);
case MacroActionId.ScrollMouseMacroAction:
return new ScrollMouseMacroAction().fromBinary(buffer);
case MacroActionId.DelayMacroAction:
return new DelayMacroAction().fromBinary(buffer);
case MacroActionId.TextMacroAction:
return new TextMacroAction().fromBinary(buffer);
default:
throw `Invalid MacroAction first byte: ${macroActionFirstByte}`;
}
}
private static fromMacroAction(macroAction: MacroAction): MacroAction {
let newMacroAction: MacroAction;
if (macroAction instanceof KeyMacroAction) {
newMacroAction = new KeyMacroAction(macroAction);
} else if (macroAction instanceof MouseButtonMacroAction) {
newMacroAction = new MouseButtonMacroAction(macroAction);
} else if (macroAction instanceof MoveMouseMacroAction) {
newMacroAction = new MoveMouseMacroAction(macroAction);
} else if (macroAction instanceof ScrollMouseMacroAction) {
newMacroAction = new ScrollMouseMacroAction(macroAction);
} else if (macroAction instanceof DelayMacroAction) {
newMacroAction = new DelayMacroAction(macroAction);
} else if (macroAction instanceof TextMacroAction) {
newMacroAction = new TextMacroAction(macroAction);
}
return newMacroAction;
}
private static fromJSONObject(macroAction: any): MacroAction {
switch (macroAction.macroActionType) {
case macroActionType.KeyMacroAction:
return new KeyMacroAction().fromJsonObject(macroAction);
case macroActionType.MouseButtonMacroAction:
return new MouseButtonMacroAction().fromJsonObject(macroAction);
case macroActionType.MoveMouseMacroAction:
return new MoveMouseMacroAction().fromJsonObject(macroAction);
case macroActionType.ScrollMouseMacroAction:
return new ScrollMouseMacroAction().fromJsonObject(macroAction);
case macroActionType.DelayMacroAction:
return new DelayMacroAction().fromJsonObject(macroAction);
case macroActionType.TextMacroAction:
return new TextMacroAction().fromJsonObject(macroAction);
default:
throw `Invalid MacroAction.macroActionType: "${macroAction.macroActionType}"`;
}
}
}

View File

@@ -0,0 +1,8 @@
export * from './delay-macro-action';
export * from './key-macro-action';
export * from './macro-action';
export * from './move-mouse-macro-action';
export * from './mouse-button-macro-action';
export * from './scroll-mouse-macro-action';
export * from './text-macro-action';
export { Helper as MacroActionHelper } from './helper';

View File

@@ -0,0 +1,139 @@
import { assertEnum, assertUInt8 } from '../../assert';
import { UhkBuffer } from '../../uhk-buffer';
import { KeyModifiers } from '../key-modifiers';
import { MacroAction, MacroActionId, MacroSubAction, macroActionType } from './macro-action';
import { KeystrokeType } from '../key-action/keystroke-type';
interface JsObjectKeyMacroAction {
macroActionType: string;
action: string;
type?: string;
scancode?: number;
modifierMask?: number;
}
export class KeyMacroAction extends MacroAction {
@assertEnum(MacroSubAction)
action: MacroSubAction;
@assertEnum(KeystrokeType)
type: KeystrokeType;
@assertUInt8
scancode: number;
@assertUInt8
modifierMask: number;
constructor(other?: KeyMacroAction) {
super();
if (!other) {
return;
}
this.action = other.action;
this.type = other.type;
this.scancode = other.scancode;
this.modifierMask = other.modifierMask;
}
fromJsonObject(jsObject: JsObjectKeyMacroAction): KeyMacroAction {
this.assertMacroActionType(jsObject);
this.action = MacroSubAction[jsObject.action];
if (jsObject.type === 'media') {
this.type = jsObject.scancode < 256 ? KeystrokeType.shortMedia : KeystrokeType.longMedia;
} else {
this.type = KeystrokeType[jsObject.type];
}
this.scancode = jsObject.scancode;
this.modifierMask = jsObject.modifierMask;
return this;
}
fromBinary(buffer: UhkBuffer): KeyMacroAction {
const macroActionId: MacroActionId = this.readAndAssertMacroActionId(buffer);
let keyMacroType: number = macroActionId - MacroActionId.KeyMacroAction;
this.action = keyMacroType & 0b11;
keyMacroType >>= 2;
this.type = keyMacroType & 0b11;
keyMacroType >>= 2;
if (keyMacroType & 0b10) {
this.scancode = buffer.readUInt8();
}
if (keyMacroType & 0b01) {
this.modifierMask = buffer.readUInt8();
}
return this;
}
toJsonObject(): any {
const jsObject: JsObjectKeyMacroAction = {
macroActionType: macroActionType.KeyMacroAction,
action: MacroSubAction[this.action]
};
if (this.hasScancode()) {
if (this.type === KeystrokeType.shortMedia || this.type === KeystrokeType.longMedia) {
jsObject.type = 'media';
} else {
jsObject.type = KeystrokeType[this.type];
}
jsObject.scancode = this.scancode;
}
if (this.hasModifiers()) {
jsObject.modifierMask = this.modifierMask;
}
return jsObject;
}
toBinary(buffer: UhkBuffer) {
let TYPE_OFFSET = 0;
TYPE_OFFSET |= this.action;
TYPE_OFFSET |= this.type << 2;
TYPE_OFFSET |= ((this.hasScancode() ? 2 : 0) + (this.hasModifiers() ? 1 : 0)) << 4;
const keyMacroType: number = MacroActionId.KeyMacroAction + TYPE_OFFSET;
buffer.writeUInt8(keyMacroType);
if (this.hasScancode()) {
buffer.writeUInt8(this.scancode);
}
if (this.hasModifiers()) {
buffer.writeUInt8(this.modifierMask);
}
}
toString(): string {
return `<KeyMacroAction action="${this.action}" scancode="${this.scancode}" modifierMask="${this.modifierMask}">`;
}
isModifierActive(modifier: KeyModifiers): boolean {
return (this.modifierMask & modifier) > 0;
}
hasScancode(): boolean {
return !!this.scancode;
}
hasModifiers(): boolean {
return !!this.modifierMask;
}
isHoldAction(): boolean {
return this.action === MacroSubAction.hold;
}
isPressAction(): boolean {
return this.action === MacroSubAction.press;
}
isReleaseAction(): boolean {
return this.action === MacroSubAction.release;
}
public getName(): string {
return 'KeyMacroAction';
}
}

View File

@@ -0,0 +1,74 @@
import { UhkBuffer } from '../../uhk-buffer';
export enum MacroActionId {
KeyMacroAction = 0,
/*
0 - 63 are reserved for KeyMacroAction
2 bits for: PressKeyMacroAction / HoldKeyMacroAction / ReleaseKeyMacroAction / undefined
2 bits for: with only scancode / only modifiers / both scancode and modifiers / undefined
2 bits for: scancode type basic, short media, long media, system. It should be only used if scancode does exist.
*/
LastKeyMacroAction = 63,
MouseButtonMacroAction = 64,
/*
64 - 66 are reserved for MouseButtonMacroAction
PressMouseButtonsMacroAction = 64,
HoldMouseButtonsMacroAction = 65,
ReleaseMouseButtonsMacroAction = 66,
*/
LastMouseButtonMacroAction = 66,
MoveMouseMacroAction = 67,
ScrollMouseMacroAction = 68,
DelayMacroAction = 69,
TextMacroAction = 70
}
export enum MacroSubAction {
press = 0,
hold = 1,
release = 2
}
export let macroActionType = {
KeyMacroAction : 'key',
MouseButtonMacroAction : 'mouseButton',
MoveMouseMacroAction : 'moveMouse',
ScrollMouseMacroAction : 'scrollMouse',
DelayMacroAction : 'delay',
TextMacroAction : 'text'
};
export abstract class MacroAction {
assertMacroActionType(jsObject: any) {
const macroActionClassname = this.getName();
const macroActionTypeString = macroActionType[macroActionClassname];
if (jsObject.macroActionType !== macroActionTypeString) {
throw `Invalid ${macroActionClassname}.macroActionType: ${jsObject.macroActionType}`;
}
}
readAndAssertMacroActionId(buffer: UhkBuffer): MacroActionId {
const classname: string = this.getName();
const readMacroActionId: MacroActionId = buffer.readUInt8();
const macroActionId: MacroActionId = MacroActionId[classname];
if (macroActionId === MacroActionId.KeyMacroAction) {
if (readMacroActionId < MacroActionId.KeyMacroAction || readMacroActionId > MacroActionId.LastKeyMacroAction) {
throw `Invalid ${classname} first byte: ${readMacroActionId}`;
}
} else if (macroActionId === MacroActionId.MouseButtonMacroAction) {
if (readMacroActionId < MacroActionId.MouseButtonMacroAction ||
readMacroActionId > MacroActionId.LastMouseButtonMacroAction) {
throw `Invalid ${classname} first byte: ${readMacroActionId}`;
}
} else if (readMacroActionId !== macroActionId) {
throw `Invalid ${classname} first byte: ${readMacroActionId}`;
}
return readMacroActionId;
}
abstract toJsonObject(): any;
abstract toBinary(buffer: UhkBuffer): void;
abstract getName(): string;
}

View File

@@ -0,0 +1,99 @@
import { assertEnum, assertUInt8 } from '../../assert';
import { UhkBuffer } from '../../uhk-buffer';
import { MacroAction, MacroActionId, MacroSubAction, macroActionType } from './macro-action';
export enum MouseButtons {
Left = 1 << 0,
Middle = 1 << 1,
Right = 1 << 2
}
interface JsObjectMouseButtonMacroAction {
macroActionType: string;
action: string;
mouseButtonsMask?: number;
}
export class MouseButtonMacroAction extends MacroAction {
@assertEnum(MacroSubAction)
action: MacroSubAction;
@assertUInt8
mouseButtonsMask: number;
constructor(other?: MouseButtonMacroAction) {
super();
if (!other) {
return;
}
this.action = other.action;
this.mouseButtonsMask = other.mouseButtonsMask;
}
fromJsonObject(jsObject: JsObjectMouseButtonMacroAction): MouseButtonMacroAction {
this.assertMacroActionType(jsObject);
this.action = MacroSubAction[jsObject.action];
this.mouseButtonsMask = jsObject.mouseButtonsMask;
return this;
}
fromBinary(buffer: UhkBuffer): MouseButtonMacroAction {
const macroActionId: MacroActionId = this.readAndAssertMacroActionId(buffer);
this.action = macroActionId - MacroActionId.MouseButtonMacroAction;
this.mouseButtonsMask = buffer.readUInt8();
return this;
}
toJsonObject(): any {
return {
macroActionType: macroActionType.MouseButtonMacroAction,
action: MacroSubAction[this.action],
mouseButtonsMask: this.mouseButtonsMask
};
}
toBinary(buffer: UhkBuffer): void {
buffer.writeUInt8(MacroActionId.MouseButtonMacroAction + this.action);
buffer.writeUInt8(this.mouseButtonsMask);
}
setMouseButtons(buttonStates: boolean[]): void {
let bitmask = 0;
for (let i = 0; i < buttonStates.length; i++) {
bitmask |= Number(buttonStates[i]) << i;
}
this.mouseButtonsMask = bitmask;
}
getMouseButtons(): boolean[] {
const enabledMouseButtons: boolean[] = [];
for (let bitmask = this.mouseButtonsMask; bitmask; bitmask >>>= 1) {
enabledMouseButtons.push(Boolean(bitmask & 1));
}
return enabledMouseButtons;
}
toString(): string {
return `<MouseButtonMacroAction mouseButtonsMask="${this.mouseButtonsMask}">`;
}
hasButtons(): boolean {
return this.mouseButtonsMask !== 0;
}
isOnlyHoldAction(): boolean {
return this.action === MacroSubAction.hold;
}
isOnlyPressAction(): boolean {
return this.action === MacroSubAction.press;
}
isOnlyReleaseAction(): boolean {
return this.action === MacroSubAction.release;
}
public getName(): string {
return 'MouseButtonMacroAction';
}
}

View File

@@ -0,0 +1,57 @@
import { assertInt16 } from '../../assert';
import { UhkBuffer } from '../../uhk-buffer';
import { MacroAction, MacroActionId, macroActionType } from './macro-action';
export class MoveMouseMacroAction extends MacroAction {
@assertInt16
x: number;
@assertInt16
y: number;
constructor(other?: MoveMouseMacroAction) {
super();
if (!other) {
return;
}
this.x = other.x;
this.y = other.y;
}
fromJsonObject(jsObject: any): MoveMouseMacroAction {
this.assertMacroActionType(jsObject);
this.x = jsObject.x;
this.y = jsObject.y;
return this;
}
fromBinary(buffer: UhkBuffer): MoveMouseMacroAction {
this.readAndAssertMacroActionId(buffer);
this.x = buffer.readInt16();
this.y = buffer.readInt16();
return this;
}
toJsonObject(): any {
return {
macroActionType: macroActionType.MoveMouseMacroAction,
x: this.x,
y: this.y
};
}
toBinary(buffer: UhkBuffer) {
buffer.writeUInt8(MacroActionId.MoveMouseMacroAction);
buffer.writeInt16(this.x);
buffer.writeInt16(this.y);
}
toString(): string {
return `<MoveMouseMacroAction pos="(${this.x},${this.y})">`;
}
public getName(): string {
return 'MoveMouseMacroAction';
}
}

View File

@@ -0,0 +1,57 @@
import { assertInt16 } from '../../assert';
import { UhkBuffer } from '../../uhk-buffer';
import { MacroAction, MacroActionId, macroActionType } from './macro-action';
export class ScrollMouseMacroAction extends MacroAction {
@assertInt16
x: number;
@assertInt16
y: number;
constructor(other?: ScrollMouseMacroAction) {
super();
if (!other) {
return;
}
this.x = other.x;
this.y = other.y;
}
fromJsonObject(jsObject: any): ScrollMouseMacroAction {
this.assertMacroActionType(jsObject);
this.x = jsObject.x;
this.y = jsObject.y;
return this;
}
fromBinary(buffer: UhkBuffer): ScrollMouseMacroAction {
this.readAndAssertMacroActionId(buffer);
this.x = buffer.readInt16();
this.y = buffer.readInt16();
return this;
}
toJsonObject(): any {
return {
macroActionType: macroActionType.ScrollMouseMacroAction,
x: this.x,
y: this.y
};
}
toBinary(buffer: UhkBuffer) {
buffer.writeUInt8(MacroActionId.ScrollMouseMacroAction);
buffer.writeInt16(this.x);
buffer.writeInt16(this.y);
}
toString(): string {
return `<ScrollMouseMacroAction pos="(${this.x},${this.y})">`;
}
public getName(): string {
return 'ScrollMouseMacroAction';
}
}

View File

@@ -0,0 +1,47 @@
import { UhkBuffer } from '../../uhk-buffer';
import { MacroAction, MacroActionId, macroActionType } from './macro-action';
export class TextMacroAction extends MacroAction {
text: string;
constructor(other?: TextMacroAction) {
super();
if (!other) {
return;
}
this.text = other.text;
}
fromJsonObject(jsObject: any): TextMacroAction {
this.assertMacroActionType(jsObject);
this.text = jsObject.text;
return this;
}
fromBinary(buffer: UhkBuffer): TextMacroAction {
this.readAndAssertMacroActionId(buffer);
this.text = buffer.readString();
return this;
}
toJsonObject(): any {
return {
macroActionType: macroActionType.TextMacroAction,
text: this.text
};
}
toBinary(buffer: UhkBuffer) {
buffer.writeUInt8(MacroActionId.TextMacroAction);
buffer.writeString(this.text);
}
toString(): string {
return `<TextMacroAction text="${this.text}">`;
}
public getName(): string {
return 'TextMacroAction';
}
}

View File

@@ -0,0 +1,69 @@
import { assertUInt8 } from '../assert';
import { UhkBuffer } from '../uhk-buffer';
import { MacroAction } from './macro-action';
import { Helper as MacroActionHelper } from './macro-action/helper';
export class Macro {
@assertUInt8
id: number;
isLooped: boolean;
isPrivate: boolean;
name: string;
macroActions: MacroAction[];
constructor(other?: Macro) {
if (!other) {
return;
}
this.id = other.id;
this.isLooped = other.isLooped;
this.isPrivate = other.isPrivate;
this.name = other.name;
this.macroActions = other.macroActions.map(macroAction => MacroActionHelper.createMacroAction(macroAction));
}
fromJsonObject(jsonObject: any): Macro {
this.isLooped = jsonObject.isLooped;
this.isPrivate = jsonObject.isPrivate;
this.name = jsonObject.name;
this.macroActions = jsonObject.macroActions.map((macroAction: any) => MacroActionHelper.createMacroAction(macroAction));
return this;
}
fromBinary(buffer: UhkBuffer): Macro {
this.isLooped = buffer.readBoolean();
this.isPrivate = buffer.readBoolean();
this.name = buffer.readString();
const macroActionsLength: number = buffer.readCompactLength();
this.macroActions = [];
for (let i = 0; i < macroActionsLength; ++i) {
this.macroActions.push(MacroActionHelper.createMacroAction(buffer));
}
return this;
}
toJsonObject(): any {
return {
isLooped: this.isLooped,
isPrivate: this.isPrivate,
name: this.name,
macroActions: this.macroActions.map(macroAction => macroAction.toJsonObject())
};
}
toBinary(buffer: UhkBuffer): void {
buffer.writeBoolean(this.isLooped);
buffer.writeBoolean(this.isPrivate);
buffer.writeString(this.name);
buffer.writeArray(this.macroActions);
}
toString(): string {
return `<Macro id="${this.id}" name="${this.name}">`;
}
}

View File

@@ -0,0 +1,58 @@
import { assertUInt8 } from '../assert';
import { UhkBuffer } from '../uhk-buffer';
export class ModuleConfiguration {
/*
* module id enumeration is a separate story
*/
@assertUInt8
id: number;
@assertUInt8
initialPointerSpeed: number;
@assertUInt8
pointerAcceleration: number;
@assertUInt8
maxPointerSpeed: number;
fromJsonObject(jsonObject: any): ModuleConfiguration {
this.id = jsonObject.id;
this.initialPointerSpeed = jsonObject.initialPointerSpeed;
this.pointerAcceleration = jsonObject.pointerAcceleration;
this.maxPointerSpeed = jsonObject.maxPointerSpeed;
return this;
}
fromBinary(buffer: UhkBuffer): ModuleConfiguration {
this.id = buffer.readUInt8();
this.initialPointerSpeed = buffer.readUInt8();
this.pointerAcceleration = buffer.readUInt8();
this.maxPointerSpeed = buffer.readUInt8();
return this;
}
toJsonObject(): any {
return {
id: this.id,
initialPointerSpeed: this.initialPointerSpeed,
pointerAcceleration: this.pointerAcceleration,
maxPointerSpeed: this.maxPointerSpeed
};
}
toBinary(buffer: UhkBuffer): void {
buffer.writeUInt8(this.id);
buffer.writeUInt8(this.initialPointerSpeed);
buffer.writeUInt8(this.pointerAcceleration);
buffer.writeUInt8(this.maxPointerSpeed);
}
toString(): string {
return `<ModuleConfiguration id="${this.id}" >`;
}
}

View File

@@ -0,0 +1,108 @@
import { assertEnum, assertUInt8 } from '../assert';
import { UhkBuffer } from '../uhk-buffer';
import { KeyActionHelper, KeyAction, NoneAction, PlayMacroAction, SwitchKeymapAction } from './key-action';
import { Macro } from './macro';
import { UserConfiguration } from './user-configuration';
enum PointerRole {
none,
move,
scroll
}
export class Module {
@assertUInt8
id: number;
keyActions: KeyAction[];
@assertEnum(PointerRole)
pointerRole: PointerRole;
constructor(other?: Module) {
if (!other) {
return;
}
this.id = other.id;
this.keyActions = other.keyActions.map(keyAction => KeyActionHelper.createKeyAction(keyAction));
this.pointerRole = other.pointerRole;
}
fromJsonObject(jsonObject: any, macros?: Macro[]): Module {
this.id = jsonObject.id;
this.pointerRole = PointerRole[<string>jsonObject.pointerRole];
this.keyActions = jsonObject.keyActions.map((keyAction: any) => {
return KeyActionHelper.createKeyAction(keyAction, macros);
});
return this;
}
fromBinary(buffer: UhkBuffer, macros?: Macro[]): Module {
this.id = buffer.readUInt8();
this.pointerRole = buffer.readUInt8();
const keyActionsLength: number = buffer.readCompactLength();
this.keyActions = [];
for (let i = 0; i < keyActionsLength; ++i) {
this.keyActions.push(KeyActionHelper.createKeyAction(buffer, macros));
}
return this;
}
toJsonObject(macros?: Macro[]): any {
return {
id: this.id,
pointerRole: PointerRole[this.pointerRole],
keyActions: this.keyActions.map(keyAction => {
if (keyAction && (macros || !(keyAction instanceof PlayMacroAction || keyAction instanceof SwitchKeymapAction))) {
return keyAction.toJsonObject(macros);
}
})
};
}
toBinary(buffer: UhkBuffer, userConfiguration: UserConfiguration): void {
buffer.writeUInt8(this.id);
buffer.writeUInt8(this.pointerRole);
const noneAction = new NoneAction();
const keyActions: KeyAction[] = this.keyActions.map(keyAction => {
if (keyAction) {
return keyAction;
}
return noneAction;
});
buffer.writeArray(keyActions, (uhkBuffer: UhkBuffer, keyAction: KeyAction) => {
keyAction.toBinary(uhkBuffer, userConfiguration);
});
}
toString(): string {
return `<Module id="${this.id}" pointerRole="${this.pointerRole}">`;
}
renameKeymap(oldAbbr: string, newAbbr: string): Module {
let keyActions: KeyAction[];
let keyActionModified = false;
this.keyActions.forEach((keyAction, index) => {
if (!keyAction) { return; }
const newKeyAction = keyAction.renameKeymap(oldAbbr, newAbbr);
if (newKeyAction !== keyAction) {
if (!keyActionModified) {
keyActions = this.keyActions.slice();
keyActionModified = true;
}
keyActions[index] = newKeyAction;
}
});
if (keyActionModified) {
const newModule = Object.assign(new Module(), this);
newModule.keyActions = keyActions;
return newModule;
}
return this;
}
}

View File

@@ -0,0 +1,78 @@
import { assertUInt16 } from '../assert';
import { UhkBuffer } from '../uhk-buffer';
import { Keymap } from './keymap';
import { Macro } from './macro';
import { ModuleConfiguration } from './module-configuration';
import { ConfigSerializer } from '../config-serializer';
export class UserConfiguration {
@assertUInt16
dataModelVersion: number;
moduleConfigurations: ModuleConfiguration[] = [];
keymaps: Keymap[] = [];
macros: Macro[] = [];
fromJsonObject(jsonObject: any): UserConfiguration {
this.dataModelVersion = jsonObject.dataModelVersion;
this.moduleConfigurations = jsonObject.moduleConfigurations.map((moduleConfiguration: any) => {
return new ModuleConfiguration().fromJsonObject(moduleConfiguration);
});
this.macros = jsonObject.macros.map((macroJsonObject: any, index: number) => {
const macro = new Macro().fromJsonObject(macroJsonObject);
macro.id = index;
return macro;
});
this.keymaps = jsonObject.keymaps.map((keymap: any) => new Keymap().fromJsonObject(keymap, this.macros));
return this;
}
fromBinary(buffer: UhkBuffer): UserConfiguration {
this.dataModelVersion = buffer.readUInt16();
this.moduleConfigurations = buffer.readArray<ModuleConfiguration>(uhkBuffer => {
return new ModuleConfiguration().fromBinary(uhkBuffer);
});
this.macros = buffer.readArray<Macro>((uhkBuffer, index) => {
const macro = new Macro().fromBinary(uhkBuffer);
macro.id = index;
return macro;
});
this.keymaps = buffer.readArray<Keymap>(uhkBuffer => new Keymap().fromBinary(uhkBuffer, this.macros));
ConfigSerializer.resolveSwitchKeymapActions(this.keymaps);
return this;
}
toJsonObject(): any {
return {
dataModelVersion: this.dataModelVersion,
moduleConfigurations: this.moduleConfigurations.map(moduleConfiguration => moduleConfiguration.toJsonObject()),
keymaps: this.keymaps.map(keymap => keymap.toJsonObject(this.macros)),
macros: this.macros.map(macro => macro.toJsonObject())
};
}
toBinary(buffer: UhkBuffer): void {
buffer.writeUInt16(this.dataModelVersion);
buffer.writeArray(this.moduleConfigurations);
buffer.writeArray(this.macros);
buffer.writeArray(this.keymaps, (uhkBuffer: UhkBuffer, keymap: Keymap) => {
keymap.toBinary(uhkBuffer, this);
});
}
toString(): string {
return `<UserConfiguration dataModelVersion="${this.dataModelVersion}">`;
}
getKeymap(keymapAbbreviation: string): Keymap {
return this.keymaps.find(keymap => keymapAbbreviation === keymap.abbreviation);
}
getMacro(macroId: number): Macro {
return this.macros.find(macro => macroId === macro.id);
}
}

View File

@@ -0,0 +1,20 @@
import { Keymap } from './config-items/keymap';
import { UnresolvedSwitchKeymapAction } from './config-items/key-action';
export namespace ConfigSerializer {
export function resolveSwitchKeymapActions(keymaps: Keymap[]) {
for (const keymap of keymaps) {
for (const layer of keymap.layers) {
for (const module of layer.modules) {
for (let i = 0; i < module.keyActions.length; ++i) {
const keyAction = module.keyActions[i];
if (keyAction instanceof UnresolvedSwitchKeymapAction) {
module.keyActions[i] = keyAction.resolve(keymaps);
}
}
}
}
}
}
}

View File

@@ -0,0 +1,4 @@
export * from './config-items';
export * from './assert';
export * from './config-serializer';
export * from './uhk-buffer';

View File

@@ -0,0 +1,232 @@
export class UhkBuffer {
static simpleElementWriter<T>(buffer: UhkBuffer, element: T): void {
(<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;
private static stringEncoding = 'utf8';
private static isFirstElementToDump = false;
offset: number;
private _enableDump = false;
private buffer: Buffer;
private bytesToBacktrack: number;
constructor() {
this.offset = 0;
this.bytesToBacktrack = 0;
this.buffer = new Buffer(UhkBuffer.eepromSize);
this.buffer.fill(0);
}
readInt8(): number {
const value = this.buffer.readInt8(this.offset);
this.dump(`i8(${value})`);
this.bytesToBacktrack = 1;
this.offset += this.bytesToBacktrack;
return value;
}
writeInt8(value: number): void {
this.dump(`i8(${value})`);
this.buffer.writeInt8(value, this.offset);
this.offset += 1;
}
readUInt8(): number {
const value = this.buffer.readUInt8(this.offset);
this.dump(`u8(${value})`);
this.bytesToBacktrack = 1;
this.offset += this.bytesToBacktrack;
return value;
}
writeUInt8(value: number): void {
this.dump(`u8(${value})`);
this.buffer.writeUInt8(value, this.offset);
this.offset += 1;
}
readInt16(): number {
const value = this.buffer.readInt16LE(this.offset);
this.dump(`i16(${value})`);
this.bytesToBacktrack = 2;
this.offset += this.bytesToBacktrack;
return value;
}
writeInt16(value: number): void {
this.dump(`i16(${value})`);
this.buffer.writeInt16LE(value, this.offset);
this.offset += 2;
}
readUInt16(): number {
const value = this.buffer.readUInt16LE(this.offset);
this.dump(`u16(${value})`);
this.bytesToBacktrack = 2;
this.offset += this.bytesToBacktrack;
return value;
}
writeUInt16(value: number): void {
this.dump(`u16(${value})`);
this.buffer.writeUInt16LE(value, this.offset);
this.offset += 2;
}
readInt32(): number {
const value = this.buffer.readInt32LE(this.offset);
this.dump(`i32(${value})`);
this.bytesToBacktrack = 4;
this.offset += this.bytesToBacktrack;
return value;
}
writeInt32(value: number): void {
this.dump(`i32(${value})`);
this.buffer.writeInt32LE(value, this.offset);
this.offset += 4;
}
readUInt32(): number {
const value = this.buffer.readUInt32LE(this.offset);
this.dump(`u32(${value})`);
this.bytesToBacktrack = 4;
this.offset += this.bytesToBacktrack;
return value;
}
writeUInt32(value: number): void {
this.dump(`u32(${value})`);
this.buffer.writeUInt32LE(value, this.offset);
this.offset += 4;
}
readCompactLength(): number {
let length = this.readUInt8();
if (length === UhkBuffer.longCompactLengthPrefix) {
length = this.readUInt16();
}
return length;
}
writeCompactLength(length: number) {
if (length >= UhkBuffer.longCompactLengthPrefix) {
this.writeUInt8(UhkBuffer.longCompactLengthPrefix);
this.writeUInt16(length);
} else {
this.writeUInt8(length);
}
}
readString(): string {
const stringByteLength = this.readCompactLength();
const str = this.buffer.toString(UhkBuffer.stringEncoding, this.offset, this.offset + stringByteLength);
this.dump(`${UhkBuffer.stringEncoding}(${str})`);
this.bytesToBacktrack = stringByteLength;
this.offset += stringByteLength;
return str;
}
writeString(str: string): void {
const stringByteLength = Buffer.byteLength(str, UhkBuffer.stringEncoding);
if (stringByteLength > UhkBuffer.maxCompactLength) {
throw `Cannot serialize string: ${stringByteLength} bytes is larger
than the maximum allowed length of ${UhkBuffer.maxCompactLength} bytes`;
}
this.writeCompactLength(stringByteLength);
this.dump(`${UhkBuffer.stringEncoding}(${str})`);
this.buffer.write(str, this.offset, stringByteLength, UhkBuffer.stringEncoding);
this.offset += stringByteLength;
}
readBoolean(): boolean {
return this.readUInt8() !== 0;
}
writeBoolean(bool: boolean) {
this.writeUInt8(bool ? 1 : 0);
}
readArray<T>(elementReader: (buffer: UhkBuffer, index?: number) => T): T[] {
const array: T[] = [];
const length = this.readCompactLength();
for (let i = 0; i < length; ++i) {
array.push(elementReader(this, i));
}
return array;
}
writeArray<T>(
array: T[],
elementWriter: (buffer: UhkBuffer, element: T, index?: number) => void = UhkBuffer.simpleElementWriter
): void {
const length = array.length;
this.writeCompactLength(length);
for (let i = 0; i < length; ++i) {
elementWriter(this, array[i], i);
}
}
backtrack(): void {
this.offset -= this.bytesToBacktrack;
this.bytesToBacktrack = 0;
}
getBufferContent(): Buffer {
return this.buffer.slice(0, this.offset);
}
get enableDump() {
return this._enableDump;
}
set enableDump(value) {
if (value) {
UhkBuffer.isFirstElementToDump = true;
}
this._enableDump = value;
}
dump(value: any) {
if (!this.enableDump) {
return;
}
if (!UhkBuffer.isFirstElementToDump) {
process.stdout.write(', ');
}
process.stdout.write(value);
if (UhkBuffer.isFirstElementToDump) {
UhkBuffer.isFirstElementToDump = false;
}
}
}

View File

@@ -0,0 +1,6 @@
export interface ConfigurationReply {
success: boolean;
userConfiguration?: string;
hardwareConfiguration?: string;
error?: string;
}

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';

View File

@@ -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 {

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 {

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 {

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])))/;
}