Folder restructuring (#86)

This commit is contained in:
József Farkas
2016-08-28 21:30:48 +02:00
committed by GitHub
parent baf2d41f71
commit bb3a2d77b6
93 changed files with 213 additions and 178 deletions

View File

@@ -0,0 +1,54 @@
import {Serializable} from './Serializable';
import {UhkBuffer} from './UhkBuffer';
export abstract class ClassArray<T extends Serializable<T>> extends Serializable<ClassArray<T>> {
elements: T[] = [];
_fromJsObject(jsObjects: any): ClassArray<T> {
for (let jsObject of jsObjects) {
this.elements.push(this.jsObjectToClass(jsObject));
}
return this;
}
_fromBinary(buffer: UhkBuffer): ClassArray<T> {
let arrayLength = buffer.readCompactLength();
if (buffer.enableDump) {
buffer.enableDump = false;
}
for (let i = 0; i < arrayLength; i++) {
this.elements.push(this.binaryToClass(buffer));
}
return this;
}
_toJsObject(): any {
let array: any[] = [];
for (let element of this.elements) {
array.push(element.toJsObject());
}
return array;
}
_toBinary(buffer: UhkBuffer) {
buffer.writeCompactLength(this.elements.length);
if (buffer.enableDump) {
buffer.enableDump = false;
}
for (let element of this.elements) {
element.toBinary(buffer);
}
}
toString(): string {
return `<${this.constructor.name} length="${this.elements.length}">`;
}
abstract jsObjectToClass(jsObject: any): T;
abstract binaryToClass(buffer: UhkBuffer): T;
}

3
src/config-serializer/Function.d.ts vendored Normal file
View File

@@ -0,0 +1,3 @@
interface Function {
name: string;
}

View File

@@ -0,0 +1,87 @@
# 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 build the configuration serializer tester by executing `npm run build:test` in this directory, then start the test by running `node test-serializer.js`.
## 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 [uhk-config.json](uhk-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 must descend from the [Serializable](Serializable.ts) class, and saved into the [config-items](config-items) directory.
**Array type** is a special compound type which is composed of a sequence of items of a specific type. Array items must descend from the [ClassArray](ClassArray.ts) class.
## 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 [uhk-config.json](uhk-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,74 @@
/// <references path="Function.d.ts">
import {UhkBuffer} from './UhkBuffer';
export abstract class Serializable<T> {
private static depth = 0;
private static maxDisplayedJsonLength = 160;
private static enableDump = false;
fromJsObject(jsObject: any): T {
this.dump(`${this.getIndentation()}${this.constructor.name}.fromJsObject: ` +
`${this.strintifyJsObject(jsObject)}\n`);
Serializable.depth++;
let value = this._fromJsObject(jsObject);
Serializable.depth--;
this.dump(`${this.getIndentation()}=> ${value}\n`);
return value;
}
fromBinary(buffer: UhkBuffer): T {
this.dump(`\n${this.getIndentation()}${this.constructor.name}.fromBinary: [`);
Serializable.depth++;
buffer.enableDump = Serializable.enableDump;
let value = this._fromBinary(buffer);
buffer.enableDump = false;
Serializable.depth--;
this.dump(`]\n${this.getIndentation()}=> ${value}`);
return value;
}
toJsObject(): any {
this.dump(`${this.getIndentation()}${this.constructor.name}.toJsObject: ${this}\n`);
Serializable.depth++;
let value = this._toJsObject();
Serializable.depth--;
this.dump(`${this.getIndentation()}=> ${this.strintifyJsObject(value)}\n`);
return value;
}
// TODO: remove parameter and return the buffer
toBinary(buffer: UhkBuffer): void {
this.dump(`\n${this.getIndentation()}${this.constructor.name}.toBinary: ${this} [`);
Serializable.depth++;
buffer.enableDump = Serializable.enableDump;
let value = this._toBinary(buffer);
buffer.enableDump = false;
Serializable.depth--;
this.dump(`]`);
return value;
}
abstract _fromJsObject(jsObject: any): T;
abstract _fromBinary(buffer: UhkBuffer): T;
abstract _toJsObject(): any;
abstract _toBinary(buffer: UhkBuffer): void;
private dump(value: any) {
if (Serializable.enableDump) {
process.stdout.write(value);
}
}
private getIndentation() {
return new Array(Serializable.depth + 1).join(' ');
}
private strintifyJsObject(jsObject: any): string {
let json = JSON.stringify(jsObject);
return json.length > Serializable.maxDisplayedJsonLength
? json.substr(0, Serializable.maxDisplayedJsonLength) + '...'
: json;
}
}

View File

@@ -0,0 +1,189 @@
export class 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 {
let 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 {
let 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 {
let 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 {
let 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 {
let 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 {
let 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.readUInt8() << 8;
}
return length;
}
writeCompactLength(length: number) {
if (length >= UhkBuffer.longCompactLengthPrefix) {
this.writeUInt8(UhkBuffer.longCompactLengthPrefix);
this.writeUInt16(length);
} else {
this.writeUInt8(length);
}
}
readString(): string {
let stringByteLength = this.readCompactLength();
let 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 {
let 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.maxStringByteLength} 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);
}
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,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,37 @@
import {UhkBuffer} from '../UhkBuffer';
import {MacroAction, macroActionType, MacroActionId} from './MacroAction';
import {assertUInt16} from '../assert';
export class DelayMacroAction extends MacroAction {
@assertUInt16
delay: number;
_fromJsObject(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;
}
_toJsObject(): 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}">`;
}
}

View File

@@ -0,0 +1,37 @@
import {UhkBuffer} from '../UhkBuffer';
import {MacroAction, MacroActionId, macroActionType} from './MacroAction';
import {assertUInt8} from '../assert';
export class HoldKeyMacroAction extends MacroAction {
@assertUInt8
scancode: number;
_fromJsObject(jsObject: any): HoldKeyMacroAction {
this.assertMacroActionType(jsObject);
this.scancode = jsObject.scancode;
return this;
}
_fromBinary(buffer: UhkBuffer): HoldKeyMacroAction {
this.readAndAssertMacroActionId(buffer);
this.scancode = buffer.readUInt8();
return this;
}
_toJsObject(): any {
return {
macroActionType: macroActionType.HoldKeyMacroAction,
scancode: this.scancode
};
}
_toBinary(buffer: UhkBuffer) {
buffer.writeUInt8(MacroActionId.HoldKeyMacroAction);
buffer.writeUInt8(this.scancode);
}
toString(): string {
return `<HoldKeyMacroAction scancode="${this.scancode}">`;
}
}

View File

@@ -0,0 +1,42 @@
import {MacroAction, MacroActionId, macroActionType} from './MacroAction';
import {KeyModifiers} from './KeyModifiers';
import {UhkBuffer} from '../UhkBuffer';
import {assertUInt8} from '../assert';
export class HoldModifiersMacroAction extends MacroAction {
@assertUInt8
modifierMask: number;
_fromJsObject(jsObject: any): HoldModifiersMacroAction {
this.assertMacroActionType(jsObject);
this.modifierMask = jsObject.modifierMask;
return this;
}
_fromBinary(buffer: UhkBuffer): HoldModifiersMacroAction {
this.readAndAssertMacroActionId(buffer);
this.modifierMask = buffer.readUInt8();
return this;
}
_toJsObject(): any {
return {
macroActionType: macroActionType.HoldModifiersMacroAction,
modifierMask: this.modifierMask
};
}
_toBinary(buffer: UhkBuffer) {
buffer.writeUInt8(MacroActionId.HoldModifiersMacroAction);
buffer.writeUInt8(this.modifierMask);
}
toString(): string {
return `<HoldModifiersMacroAction modifierMask="${this.modifierMask}">`;
}
isModifierActive(modifier: KeyModifiers): boolean {
return (this.modifierMask & modifier) > 0;
}
}

View File

@@ -0,0 +1,37 @@
import {UhkBuffer} from '../UhkBuffer';
import {MacroAction, MacroActionId, macroActionType} from './MacroAction';
import {assertUInt8} from '../assert';
export class HoldMouseButtonsMacroAction extends MacroAction {
@assertUInt8
mouseButtonsMask: number;
_fromJsObject(jsObject: any): HoldMouseButtonsMacroAction {
this.assertMacroActionType(jsObject);
this.mouseButtonsMask = jsObject.mouseButtonsMask;
return this;
}
_fromBinary(buffer: UhkBuffer): HoldMouseButtonsMacroAction {
this.readAndAssertMacroActionId(buffer);
this.mouseButtonsMask = buffer.readUInt8();
return this;
}
_toJsObject(): any {
return {
macroActionType: macroActionType.HoldMouseButtonsMacroAction,
mouseButtonsMask: this.mouseButtonsMask
};
}
_toBinary(buffer: UhkBuffer) {
buffer.writeUInt8(MacroActionId.HoldMouseButtonsMacroAction);
buffer.writeUInt8(this.mouseButtonsMask);
}
toString(): string {
return `<HoldMouseButtonsMacroAction mouseButtonsMask="${this.mouseButtonsMask}">`;
}
}

View File

@@ -0,0 +1,60 @@
/// <reference path="../Function.d.ts" />
import {Serializable} from '../Serializable';
import {UhkBuffer} from '../UhkBuffer';
export enum KeyActionId {
NoneAction = 0,
KeystrokeAction = 1,
/*
1 - 7 are reserved for KeystrokeAction
3 bits:
1: Do we have scancode?
2: Do we have modifiers?
3: Do we have longpress?
*/
LastKeystrokeAction = 7, // TODO: remove this after refactoring the keyActionId check
SwitchLayerAction = 8,
SwitchKeymapAction = 9,
MouseAction = 10,
PlayMacroAction = 11
}
export let keyActionType = {
NoneAction : 'none',
KeystrokeAction : 'keystroke',
SwitchLayerAction : 'switchLayer',
SwitchKeymapAction : 'switchKeymap',
MouseAction : 'mouse',
PlayMacroAction : 'playMacro'
};
export abstract class KeyAction extends Serializable<KeyAction> {
assertKeyActionType(jsObject: any): void {
let keyActionClassname: string = this.constructor.name;
let keyActionTypeString: string = keyActionType[keyActionClassname];
if (jsObject.keyActionType !== keyActionTypeString) {
throw `Invalid ${keyActionClassname}.keyActionType: ${jsObject.keyActionType}`;
}
}
readAndAssertKeyActionId(buffer: UhkBuffer): KeyActionId {
let classname: string = this.constructor.name;
let readKeyActionId: number = buffer.readUInt8();
let 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 _fromJsObject(jsObject: any): KeyAction;
abstract _fromBinary(buffer: UhkBuffer): KeyAction;
abstract _toJsObject(): any;
abstract _toBinary(buffer: UhkBuffer): void;
}

View File

@@ -0,0 +1,60 @@
import {ClassArray} from '../ClassArray';
import {UhkBuffer} from '../UhkBuffer';
import {NoneAction} from './NoneAction';
import {KeystrokeAction} from './KeystrokeAction';
import {keyActionType, KeyActionId, KeyAction} from './KeyAction';
import {SwitchLayerAction} from './SwitchLayerAction';
import {SwitchKeymapAction} from './SwitchKeymapAction';
import {MouseAction} from './MouseAction';
import {PlayMacroAction} from './PlayMacroAction';
export class KeyActions extends ClassArray<KeyAction> {
jsObjectToClass(jsObject: any): KeyAction {
switch (jsObject.keyActionType) {
case keyActionType.NoneAction:
return new NoneAction().fromJsObject(jsObject);
case keyActionType.KeystrokeAction:
return new KeystrokeAction().fromJsObject(jsObject);
case keyActionType.SwitchLayerAction:
return new SwitchLayerAction().fromJsObject(jsObject);
case keyActionType.SwitchKeymapAction:
return new SwitchKeymapAction().fromJsObject(jsObject);
case keyActionType.MouseAction:
return new MouseAction().fromJsObject(jsObject);
case keyActionType.PlayMacroAction:
return new PlayMacroAction().fromJsObject(jsObject);
default:
throw `Invalid KeyAction.keyActionType: "${jsObject.keyActionType}"`;
}
}
binaryToClass(buffer: UhkBuffer): KeyAction {
let keyActionFirstByte = buffer.readUInt8();
buffer.backtrack();
if (buffer.enableDump) {
process.stdout.write(']\n');
buffer.enableDump = false;
}
if (keyActionFirstByte >= KeyActionId.KeystrokeAction && keyActionFirstByte < KeyActionId.LastKeystrokeAction) {
return new KeystrokeAction().fromBinary(buffer);
}
switch (keyActionFirstByte) {
case KeyActionId.NoneAction:
return new NoneAction().fromBinary(buffer);
case KeyActionId.SwitchLayerAction:
return new SwitchLayerAction().fromBinary(buffer);
case KeyActionId.SwitchKeymapAction:
return new SwitchKeymapAction().fromBinary(buffer);
case KeyActionId.MouseAction:
return new MouseAction().fromBinary(buffer);
case KeyActionId.PlayMacroAction:
return new PlayMacroAction().fromBinary(buffer);
default:
throw `Invalid KeyAction first byte: ${keyActionFirstByte}`;
}
}
}

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,58 @@
import {Serializable} from '../Serializable';
import {UhkBuffer} from '../UhkBuffer';
import {Layers} from './Layers';
import {assertUInt8} from '../assert';
export class Keymap extends Serializable<Keymap> {
@assertUInt8
id: number;
name: string;
abbreviation: string;
isDefault: boolean;
layers: Layers;
_fromJsObject(jsObject: any): Keymap {
this.id = jsObject.id;
this.isDefault = jsObject.isDefault;
this.abbreviation = jsObject.abbreviation;
this.name = jsObject.name;
this.layers = new Layers().fromJsObject(jsObject.layers);
return this;
}
_fromBinary(buffer: UhkBuffer): Keymap {
this.id = buffer.readUInt8();
this.isDefault = buffer.readBoolean();
this.abbreviation = buffer.readString();
this.name = buffer.readString();
this.layers = new Layers().fromBinary(buffer);
return this;
}
_toJsObject(): any {
return {
id: this.id,
isDefault: this.isDefault,
abbreviation: this.abbreviation,
name: this.name,
layers: this.layers.toJsObject()
};
}
_toBinary(buffer: UhkBuffer): void {
buffer.writeUInt8(this.id);
buffer.writeBoolean(this.isDefault);
buffer.writeString(this.abbreviation);
buffer.writeString(this.name);
this.layers.toBinary(buffer);
}
toString(): string {
return `<Keymap id="${this.id}" name="${this.name}">`;
}
}

View File

@@ -0,0 +1,15 @@
import {ClassArray} from '../ClassArray';
import {UhkBuffer} from '../UhkBuffer';
import {Keymap} from './Keymap';
export class Keymaps extends ClassArray<Keymap> {
jsObjectToClass(jsObject: any): Keymap {
return new Keymap().fromJsObject(jsObject);
}
binaryToClass(buffer: UhkBuffer): Keymap {
return new Keymap().fromBinary(buffer);
}
}

View File

@@ -0,0 +1,133 @@
import {UhkBuffer} from '../UhkBuffer';
import {keyActionType, KeyActionId, KeyAction} from './KeyAction';
import {KeyModifiers} from './KeyModifiers';
import {assertUInt8, assertEnum} from '../assert';
import {LongPressAction} from './LongPressAction';
export enum KeystrokeActionFlag {
scancode = 1 << 0,
modifierMask = 1 << 1,
longPressAction = 1 << 2,
}
interface JsObjectKeystrokeAction {
keyActionType: string;
scancode?: number;
modifierMask?: number;
longPressAction?: string;
}
export class KeystrokeAction extends KeyAction {
@assertUInt8
scancode: number;
@assertUInt8
modifierMask: number;
@assertEnum(LongPressAction)
longPressAction: LongPressAction;
_fromJsObject(jsObject: JsObjectKeystrokeAction): KeystrokeAction {
this.assertKeyActionType(jsObject);
this.scancode = jsObject.scancode;
this.modifierMask = jsObject.modifierMask;
this.longPressAction = LongPressAction[jsObject.longPressAction];
return this;
}
_fromBinary(buffer: UhkBuffer): KeystrokeAction {
let keyActionId: KeyActionId = this.readAndAssertKeyActionId(buffer);
let flags: number = keyActionId - KeyActionId.KeystrokeAction;
if (flags & KeystrokeActionFlag.scancode) {
this.scancode = buffer.readUInt8();
}
if (flags & KeystrokeActionFlag.modifierMask) {
this.modifierMask = buffer.readUInt8();
}
if (flags & KeystrokeActionFlag.longPressAction) {
this.longPressAction = buffer.readUInt8();
}
return this;
}
_toJsObject(): JsObjectKeystrokeAction {
let jsObject: JsObjectKeystrokeAction = {
keyActionType: keyActionType.KeystrokeAction
};
if (this.hasScancode()) {
jsObject.scancode = this.scancode;
}
if (this.hasActiveModifier()) {
jsObject.modifierMask = this.modifierMask;
}
if (this.hasLongPressAction()) {
jsObject.longPressAction = LongPressAction[this.longPressAction];
}
return jsObject;
}
_toBinary(buffer: UhkBuffer) {
let flags = 0;
let bufferData: number[] = [];
if (this.hasScancode()) {
flags |= KeystrokeActionFlag.scancode;
bufferData.push(this.scancode);
}
if (this.hasActiveModifier()) {
flags |= KeystrokeActionFlag.modifierMask;
bufferData.push(this.modifierMask);
}
if (this.hasLongPressAction()) {
flags |= KeystrokeActionFlag.longPressAction;
bufferData.push(this.longPressAction);
}
buffer.writeUInt8(KeyActionId.KeystrokeAction + flags);
for (let i = 0; i < bufferData.length; ++i) {
buffer.writeUInt8(bufferData[i]);
}
}
toString(): string {
let properties: string[] = [];
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);
}
}

View File

@@ -0,0 +1,35 @@
import { Serializable } from '../Serializable';
import { Modules } from './Modules';
import { UhkBuffer } from '../UhkBuffer';
import { AnimationKeyboard } from '../../components/svg/wrap';
export class Layer extends Serializable<Layer> {
modules: Modules;
animation: AnimationKeyboard = 'none';
_fromJsObject(jsObject: any): Layer {
this.modules = new Modules().fromJsObject(jsObject.modules);
return this;
}
_fromBinary(buffer: UhkBuffer): Layer {
this.modules = new Modules().fromBinary(buffer);
return this;
}
_toJsObject(): any {
return {
modules: this.modules.toJsObject()
};
}
_toBinary(buffer: UhkBuffer): void {
this.modules.toBinary(buffer);
}
toString(): string {
return `<Layer>`;
}
}

View File

@@ -0,0 +1,15 @@
import {ClassArray} from '../ClassArray';
import {UhkBuffer} from '../UhkBuffer';
import {Layer} from './Layer';
export class Layers extends ClassArray<Layer> {
jsObjectToClass(jsObject: any): Layer {
return new Layer().fromJsObject(jsObject);
}
binaryToClass(buffer: UhkBuffer): Layer {
return new Layer().fromBinary(buffer);
}
}

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,58 @@
import {Serializable} from '../Serializable';
import {UhkBuffer} from '../UhkBuffer';
import {MacroActions} from './MacroActions';
import {assertUInt8} from '../assert';
export class Macro extends Serializable<Macro> {
@assertUInt8
id: number;
isLooped: boolean;
isPrivate: boolean;
name: string;
macroActions: MacroActions;
_fromJsObject(jsObject: any): Macro {
this.id = jsObject.id;
this.isLooped = jsObject.isLooped;
this.isPrivate = jsObject.isPrivate;
this.name = jsObject.name;
this.macroActions = new MacroActions().fromJsObject(jsObject.macroActions);
return this;
}
_fromBinary(buffer: UhkBuffer): Macro {
this.id = buffer.readUInt8();
this.isLooped = buffer.readBoolean();
this.isPrivate = buffer.readBoolean();
this.name = buffer.readString();
this.macroActions = new MacroActions().fromBinary(buffer);
return this;
}
_toJsObject(): any {
return {
id: this.id,
isLooped: this.isLooped,
isPrivate: this.isPrivate,
name: this.name,
macroActions: this.macroActions.toJsObject()
};
}
_toBinary(buffer: UhkBuffer): void {
buffer.writeUInt8(this.id);
buffer.writeBoolean(this.isLooped);
buffer.writeBoolean(this.isPrivate);
buffer.writeString(this.name);
this.macroActions.toBinary(buffer);
}
toString(): string {
return `<Macro id="${this.id}" name="${this.name}">`;
}
}

View File

@@ -0,0 +1,58 @@
import {Serializable} from '../Serializable';
import {UhkBuffer} from '../UhkBuffer';
export enum MacroActionId {
PressKeyMacroAction = 0,
HoldKeyMacroAction = 1,
ReleaseKeyMacroAction = 2,
PressModifiersMacroAction = 3,
HoldModifiersMacroAction = 4,
ReleaseModifiersMacroAction = 5,
PressMouseButtonsMacroAction = 6,
HoldMouseButtonsMacroAction = 7,
ReleaseMouseButtonsMacroAction = 8,
MoveMouseMacroAction = 9,
ScrollMouseMacroAction = 10,
DelayMacroAction = 11,
TextMacroAction = 12
}
export let macroActionType = {
PressKeyMacroAction : 'pressKey',
HoldKeyMacroAction : 'holdKey',
ReleaseKeyMacroAction : 'releaseKey',
PressModifiersMacroAction : 'pressModifiers',
HoldModifiersMacroAction : 'holdModifiers',
ReleaseModifiersMacroAction : 'releaseModifiers',
PressMouseButtonsMacroAction : 'pressMouseButtons',
HoldMouseButtonsMacroAction : 'holdMouseButtons',
ReleaseMouseButtonsMacroAction : 'releaseMouseButtons',
MoveMouseMacroAction : 'moveMouse',
ScrollMouseMacroAction : 'scrollMouse',
DelayMacroAction : 'delay',
TextMacroAction : 'text'
};
export abstract class MacroAction extends Serializable<MacroAction> {
assertMacroActionType(jsObject: any) {
let macroActionClassname = this.constructor.name;
let macroActionTypeString = macroActionType[macroActionClassname];
if (jsObject.macroActionType !== macroActionTypeString) {
throw `Invalid ${macroActionClassname}.macroActionType: ${jsObject.macroActionType}`;
}
}
readAndAssertMacroActionId(buffer: UhkBuffer) {
let classname = this.constructor.name;
let readMacroActionId = buffer.readUInt8();
let macroActionId = MacroActionId[<string> classname];
if (readMacroActionId !== macroActionId) {
throw `Invalid ${classname} first byte: ${readMacroActionId}`;
}
}
abstract _fromJsObject(jsObject: any): MacroAction;
abstract _fromBinary(buffer: UhkBuffer): MacroAction;
abstract _toJsObject(): any;
abstract _toBinary(buffer: UhkBuffer): void;
}

View File

@@ -0,0 +1,93 @@
import {ClassArray} from '../ClassArray';
import {UhkBuffer} from '../UhkBuffer';
import {DelayMacroAction} from './DelayMacroAction';
import {MacroAction, macroActionType, MacroActionId} from './MacroAction';
import {HoldKeyMacroAction} from './HoldKeyMacroAction';
import {HoldModifiersMacroAction} from './HoldModifiersMacroAction';
import {HoldMouseButtonsMacroAction} from './HoldMouseButtonsMacroAction';
import {MoveMouseMacroAction} from './MoveMouseMacroAction';
import {PressKeyMacroAction} from './PressKeyMacroAction';
import {PressModifiersMacroAction} from './PressModifiersMacroAction';
import {PressMouseButtonsMacroAction} from './PressMouseButtonsMacroAction';
import {ReleaseKeyMacroAction} from './ReleaseKeyMacroAction';
import {ReleaseModifiersMacroAction} from './ReleaseModifiersMacroAction';
import {ReleaseMouseButtonsMacroAction} from './ReleaseMouseButtonsMacroAction';
import {ScrollMouseMacroAction} from './ScrollMouseMacroAction';
import {TextMacroAction} from './TextMacroAction';
export class MacroActions extends ClassArray<MacroAction> {
jsObjectToClass(jsObject: any): MacroAction {
switch (jsObject.macroActionType) {
case macroActionType.PressKeyMacroAction:
return new PressKeyMacroAction().fromJsObject(jsObject);
case macroActionType.HoldKeyMacroAction:
return new HoldKeyMacroAction().fromJsObject(jsObject);
case macroActionType.ReleaseKeyMacroAction:
return new ReleaseKeyMacroAction().fromJsObject(jsObject);
case macroActionType.PressModifiersMacroAction:
return new PressModifiersMacroAction().fromJsObject(jsObject);
case macroActionType.HoldModifiersMacroAction:
return new HoldModifiersMacroAction().fromJsObject(jsObject);
case macroActionType.ReleaseModifiersMacroAction:
return new ReleaseModifiersMacroAction().fromJsObject(jsObject);
case macroActionType.PressMouseButtonsMacroAction:
return new PressMouseButtonsMacroAction().fromJsObject(jsObject);
case macroActionType.HoldMouseButtonsMacroAction:
return new HoldMouseButtonsMacroAction().fromJsObject(jsObject);
case macroActionType.ReleaseMouseButtonsMacroAction:
return new ReleaseMouseButtonsMacroAction().fromJsObject(jsObject);
case macroActionType.MoveMouseMacroAction:
return new MoveMouseMacroAction().fromJsObject(jsObject);
case macroActionType.ScrollMouseMacroAction:
return new ScrollMouseMacroAction().fromJsObject(jsObject);
case macroActionType.DelayMacroAction:
return new DelayMacroAction().fromJsObject(jsObject);
case macroActionType.TextMacroAction:
return new TextMacroAction().fromJsObject(jsObject);
default:
throw `Invalid MacroAction.macroActionType: "${jsObject.macroActionType}"`;
}
}
binaryToClass(buffer: UhkBuffer): MacroAction {
let macroActionFirstByte = buffer.readUInt8();
buffer.backtrack();
if (buffer.enableDump) {
process.stdout.write(']\n');
buffer.enableDump = false;
}
switch (macroActionFirstByte) {
case MacroActionId.PressKeyMacroAction:
return new PressKeyMacroAction().fromBinary(buffer);
case MacroActionId.HoldKeyMacroAction:
return new HoldKeyMacroAction().fromBinary(buffer);
case MacroActionId.ReleaseKeyMacroAction:
return new ReleaseKeyMacroAction().fromBinary(buffer);
case MacroActionId.PressModifiersMacroAction:
return new PressModifiersMacroAction().fromBinary(buffer);
case MacroActionId.HoldModifiersMacroAction:
return new HoldModifiersMacroAction().fromBinary(buffer);
case MacroActionId.ReleaseModifiersMacroAction:
return new ReleaseModifiersMacroAction().fromBinary(buffer);
case MacroActionId.PressMouseButtonsMacroAction:
return new PressMouseButtonsMacroAction().fromBinary(buffer);
case MacroActionId.HoldMouseButtonsMacroAction:
return new HoldMouseButtonsMacroAction().fromBinary(buffer);
case MacroActionId.ReleaseMouseButtonsMacroAction:
return new ReleaseMouseButtonsMacroAction().fromBinary(buffer);
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}`;
}
}
}

View File

@@ -0,0 +1,15 @@
import {ClassArray} from '../ClassArray';
import {Macro} from './Macro';
import {UhkBuffer} from '../UhkBuffer';
export class Macros extends ClassArray<Macro> {
jsObjectToClass(jsObject: any): Macro {
return new Macro().fromJsObject(jsObject);
}
binaryToClass(buffer: UhkBuffer): Macro {
return new Macro().fromBinary(buffer);
}
}

View File

@@ -0,0 +1,54 @@
import {Serializable} from '../Serializable';
import {KeyActions} from './KeyActions';
import {UhkBuffer} from '../UhkBuffer';
import {assertUInt8, assertEnum} from '../assert';
enum PointerRole {
none,
move,
scroll
}
export class Module extends Serializable<Module> {
@assertUInt8
id: number;
keyActions: KeyActions;
@assertEnum(PointerRole)
private pointerRole: PointerRole;
_fromJsObject(jsObject: any): Module {
this.id = jsObject.id;
this.pointerRole = PointerRole[<string> jsObject.pointerRole];
this.keyActions = new KeyActions().fromJsObject(jsObject.keyActions);
return this;
}
_fromBinary(buffer: UhkBuffer): Module {
this.id = buffer.readUInt8();
this.pointerRole = buffer.readUInt8();
this.keyActions = new KeyActions().fromBinary(buffer);
return this;
}
_toJsObject(): any {
return {
id: this.id,
pointerRole: PointerRole[this.pointerRole],
keyActions: this.keyActions.toJsObject()
};
}
_toBinary(buffer: UhkBuffer): void {
buffer.writeUInt8(this.id);
buffer.writeUInt8(this.pointerRole);
this.keyActions.toBinary(buffer);
}
toString(): string {
return `<Module id="${this.id}" pointerRole="${this.pointerRole}">`;
}
}

View File

@@ -0,0 +1,59 @@
import {Serializable} from '../Serializable';
import {UhkBuffer} from '../UhkBuffer';
import {assertUInt8} from '../assert';
export class ModuleConfiguration extends Serializable<ModuleConfiguration> {
/*
* module id enumeration is a separate story
*/
@assertUInt8
id: number;
@assertUInt8
initialPointerSpeed: number;
@assertUInt8
pointerAcceleration: number;
@assertUInt8
maxPointerSpeed: number;
_fromJsObject(jsObject: any): ModuleConfiguration {
this.id = jsObject.id;
this.initialPointerSpeed = jsObject.initialPointerSpeed;
this.pointerAcceleration = jsObject.pointerAcceleration;
this.maxPointerSpeed = jsObject.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;
}
_toJsObject(): 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,15 @@
import {ClassArray} from '../ClassArray';
import {ModuleConfiguration} from './ModuleConfiguration';
import {UhkBuffer} from '../UhkBuffer';
export class ModuleConfigurations extends ClassArray<ModuleConfiguration> {
jsObjectToClass(jsObject: any): ModuleConfiguration {
return new ModuleConfiguration().fromJsObject(jsObject);
}
binaryToClass(buffer: UhkBuffer): ModuleConfiguration {
return new ModuleConfiguration().fromBinary(buffer);
}
}

View File

@@ -0,0 +1,15 @@
import {ClassArray} from '../ClassArray';
import {Module} from './Module';
import {UhkBuffer} from '../UhkBuffer';
export class Modules extends ClassArray<Module> {
jsObjectToClass(jsObject: any): Module {
return new Module().fromJsObject(jsObject);
}
binaryToClass(buffer: UhkBuffer): Module {
return new Module().fromBinary(buffer);
}
}

View File

@@ -0,0 +1,53 @@
import {keyActionType, KeyActionId, KeyAction} from './KeyAction';
import {UhkBuffer} from '../UhkBuffer';
import {assertEnum} from '../assert';
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;
_fromJsObject(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;
}
_toJsObject(): 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}">`;
}
}

View File

@@ -0,0 +1,44 @@
import {MacroAction, macroActionType, MacroActionId} from './MacroAction';
import {UhkBuffer} from '../UhkBuffer';
import {assertInt16} from '../assert';
export class MoveMouseMacroAction extends MacroAction {
@assertInt16
x: number;
@assertInt16
y: number;
_fromJsObject(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;
}
_toJsObject(): 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})">`;
}
}

View File

@@ -0,0 +1,29 @@
import {keyActionType, KeyActionId, KeyAction} from './KeyAction';
import {UhkBuffer} from '../UhkBuffer';
export class NoneAction extends KeyAction {
_fromJsObject(jsObject: any): NoneAction {
this.assertKeyActionType(jsObject);
return this;
}
_fromBinary(buffer: UhkBuffer): NoneAction {
this.readAndAssertKeyActionId(buffer);
return this;
}
_toJsObject(): any {
return {
keyActionType: keyActionType.NoneAction
};
}
_toBinary(buffer: UhkBuffer) {
buffer.writeUInt8(KeyActionId.NoneAction);
}
toString(): string {
return '<NoneAction>';
}
}

View File

@@ -0,0 +1,37 @@
import {keyActionType, KeyActionId, KeyAction} from './KeyAction';
import {UhkBuffer} from '../UhkBuffer';
import {assertUInt8} from '../assert';
export class PlayMacroAction extends KeyAction {
@assertUInt8
macroId: number;
_fromJsObject(jsObject: any): PlayMacroAction {
this.assertKeyActionType(jsObject);
this.macroId = jsObject.macroId;
return this;
}
_fromBinary(buffer: UhkBuffer): PlayMacroAction {
this.readAndAssertKeyActionId(buffer);
this.macroId = buffer.readUInt8();
return this;
}
_toJsObject(): any {
return {
keyActionType: keyActionType.PlayMacroAction,
macroId: this.macroId
};
}
_toBinary(buffer: UhkBuffer) {
buffer.writeUInt8(KeyActionId.PlayMacroAction);
buffer.writeUInt8(this.macroId);
}
toString(): string {
return `<PlayMacroAction macroId="${this.macroId}">`;
}
}

View File

@@ -0,0 +1,37 @@
import {MacroAction, MacroActionId, macroActionType} from './MacroAction';
import {UhkBuffer} from '../UhkBuffer';
import {assertUInt8} from '../assert';
export class PressKeyMacroAction extends MacroAction {
@assertUInt8
scancode: number;
_fromJsObject(jsObject: any): PressKeyMacroAction {
this.assertMacroActionType(jsObject);
this.scancode = jsObject.scancode;
return this;
}
_fromBinary(buffer: UhkBuffer): PressKeyMacroAction {
this.readAndAssertMacroActionId(buffer);
this.scancode = buffer.readUInt8();
return this;
}
_toJsObject(): any {
return {
macroActionType: macroActionType.PressKeyMacroAction,
scancode: this.scancode
};
}
_toBinary(buffer: UhkBuffer) {
buffer.writeUInt8(MacroActionId.PressKeyMacroAction);
buffer.writeUInt8(this.scancode);
}
toString(): string {
return `<PressKeyMacroAction scancode="${this.scancode}">`;
}
}

View File

@@ -0,0 +1,42 @@
import {MacroAction, MacroActionId, macroActionType} from './MacroAction';
import {KeyModifiers} from './KeyModifiers';
import {UhkBuffer} from '../UhkBuffer';
import {assertUInt8} from '../assert';
export class PressModifiersMacroAction extends MacroAction {
@assertUInt8
modifierMask: number;
_fromJsObject(jsObject: any): PressModifiersMacroAction {
this.assertMacroActionType(jsObject);
this.modifierMask = jsObject.modifierMask;
return this;
}
_fromBinary(buffer: UhkBuffer): PressModifiersMacroAction {
this.readAndAssertMacroActionId(buffer);
this.modifierMask = buffer.readUInt8();
return this;
}
_toJsObject(): any {
return {
macroActionType: macroActionType.PressModifiersMacroAction,
modifierMask: this.modifierMask
};
}
_toBinary(buffer: UhkBuffer) {
buffer.writeUInt8(MacroActionId.PressModifiersMacroAction);
buffer.writeUInt8(this.modifierMask);
}
toString(): string {
return `<PressModifiersMacroAction modifierMask="${this.modifierMask}">`;
}
isModifierActive(modifier: KeyModifiers): boolean {
return (this.modifierMask & modifier) > 0;
}
}

View File

@@ -0,0 +1,37 @@
import {MacroAction, MacroActionId, macroActionType} from './MacroAction';
import {UhkBuffer} from '../UhkBuffer';
import {assertUInt8} from '../assert';
export class PressMouseButtonsMacroAction extends MacroAction {
@assertUInt8
mouseButtonsMask: number;
_fromJsObject(jsObject: any): PressMouseButtonsMacroAction {
this.assertMacroActionType(jsObject);
this.mouseButtonsMask = jsObject.mouseButtonsMask;
return this;
}
_fromBinary(buffer: UhkBuffer): PressMouseButtonsMacroAction {
this.readAndAssertMacroActionId(buffer);
this.mouseButtonsMask = buffer.readUInt8();
return this;
}
_toJsObject(): any {
return {
macroActionType: macroActionType.PressMouseButtonsMacroAction,
mouseButtonsMask: this.mouseButtonsMask
};
}
_toBinary(buffer: UhkBuffer) {
buffer.writeUInt8(MacroActionId.PressMouseButtonsMacroAction);
buffer.writeUInt8(this.mouseButtonsMask);
}
toString(): string {
return `<PressMouseButtonsMacroAction mouseButtonsMask="${this.mouseButtonsMask}">`;
}
}

View File

@@ -0,0 +1,37 @@
import {MacroAction, MacroActionId, macroActionType} from './MacroAction';
import {UhkBuffer} from '../UhkBuffer';
import {assertUInt8} from '../assert';
export class ReleaseKeyMacroAction extends MacroAction {
@assertUInt8
scancode: number;
_fromJsObject(jsObject: any): ReleaseKeyMacroAction {
this.assertMacroActionType(jsObject);
this.scancode = jsObject.scancode;
return this;
}
_fromBinary(buffer: UhkBuffer): ReleaseKeyMacroAction {
this.readAndAssertMacroActionId(buffer);
this.scancode = buffer.readUInt8();
return this;
}
_toJsObject(): any {
return {
macroActionType: macroActionType.ReleaseKeyMacroAction,
scancode: this.scancode
};
}
_toBinary(buffer: UhkBuffer) {
buffer.writeUInt8(MacroActionId.ReleaseKeyMacroAction);
buffer.writeUInt8(this.scancode);
}
toString(): string {
return `<ReleaseKeyMacroAction scancode="${this.scancode}">`;
}
}

View File

@@ -0,0 +1,42 @@
import {MacroAction, MacroActionId, macroActionType} from './MacroAction';
import {KeyModifiers} from './KeyModifiers';
import {UhkBuffer} from '../UhkBuffer';
import {assertUInt8} from '../assert';
export class ReleaseModifiersMacroAction extends MacroAction {
@assertUInt8
modifierMask: number;
_fromJsObject(jsObject: any): ReleaseModifiersMacroAction {
this.assertMacroActionType(jsObject);
this.modifierMask = jsObject.modifierMask;
return this;
}
_fromBinary(buffer: UhkBuffer): ReleaseModifiersMacroAction {
this.readAndAssertMacroActionId(buffer);
this.modifierMask = buffer.readUInt8();
return this;
}
_toJsObject(): any {
return {
macroActionType: macroActionType.ReleaseModifiersMacroAction,
modifierMask: this.modifierMask
};
}
_toBinary(buffer: UhkBuffer) {
buffer.writeUInt8(MacroActionId.ReleaseModifiersMacroAction);
buffer.writeUInt8(this.modifierMask);
}
toString(): string {
return `<ReleaseModifiersMacroAction modifierMask="${this.modifierMask}">`;
}
isModifierActive(modifier: KeyModifiers): boolean {
return (this.modifierMask & modifier) > 0;
}
}

View File

@@ -0,0 +1,37 @@
import {MacroAction, MacroActionId, macroActionType} from './MacroAction';
import {UhkBuffer} from '../UhkBuffer';
import {assertUInt8} from '../assert';
export class ReleaseMouseButtonsMacroAction extends MacroAction {
@assertUInt8
mouseButtonsMask: number;
_fromJsObject(jsObject: any): ReleaseMouseButtonsMacroAction {
this.assertMacroActionType(jsObject);
this.mouseButtonsMask = jsObject.mouseButtonsMask;
return this;
}
_fromBinary(buffer: UhkBuffer): ReleaseMouseButtonsMacroAction {
this.readAndAssertMacroActionId(buffer);
this.mouseButtonsMask = buffer.readUInt8();
return this;
}
_toJsObject(): any {
return {
macroActionType: macroActionType.ReleaseMouseButtonsMacroAction,
mouseButtonsMask: this.mouseButtonsMask
};
}
_toBinary(buffer: UhkBuffer) {
buffer.writeUInt8(MacroActionId.ReleaseMouseButtonsMacroAction);
buffer.writeUInt8(this.mouseButtonsMask);
}
toString(): string {
return `<ReleaseMouseButtonsMacroAction mouseButtonsMask="${this.mouseButtonsMask}">`;
}
}

View File

@@ -0,0 +1,44 @@
import {MacroAction, MacroActionId, macroActionType} from './MacroAction';
import {UhkBuffer} from '../UhkBuffer';
import {assertInt16} from '../assert';
export class ScrollMouseMacroAction extends MacroAction {
@assertInt16
x: number;
@assertInt16
y: number;
_fromJsObject(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;
}
_toJsObject(): 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})">`;
}
}

View File

@@ -0,0 +1,37 @@
import {keyActionType, KeyActionId, KeyAction} from './KeyAction';
import {UhkBuffer} from '../UhkBuffer';
import {assertUInt8} from '../assert';
export class SwitchKeymapAction extends KeyAction {
@assertUInt8
keymapId: number;
_fromJsObject(jsObject: any): SwitchKeymapAction {
this.assertKeyActionType(jsObject);
this.keymapId = jsObject.keymapId;
return this;
}
_fromBinary(buffer: UhkBuffer): SwitchKeymapAction {
this.readAndAssertKeyActionId(buffer);
this.keymapId = buffer.readUInt8();
return this;
}
_toJsObject(): any {
return {
keyActionType: keyActionType.SwitchKeymapAction,
keymapId: this.keymapId
};
}
_toBinary(buffer: UhkBuffer) {
buffer.writeUInt8(KeyActionId.SwitchKeymapAction);
buffer.writeUInt8(this.keymapId);
}
toString(): string {
return `<SwitchKeymapAction keymapId="${this.keymapId}">`;
}
}

View File

@@ -0,0 +1,50 @@
import {keyActionType, KeyActionId, KeyAction} from './KeyAction';
import {UhkBuffer} from '../UhkBuffer';
import {assertEnum} from '../assert';
export enum LayerName {
mod,
fn,
mouse
}
export class SwitchLayerAction extends KeyAction {
isLayerToggleable: boolean;
@assertEnum(LayerName)
layer: LayerName;
_fromJsObject(jsObject: any): SwitchLayerAction {
this.assertKeyActionType(jsObject);
this.layer = LayerName[<string> jsObject.layer];
this.isLayerToggleable = jsObject.toggle;
return this;
}
_fromBinary(buffer: UhkBuffer): SwitchLayerAction {
this.readAndAssertKeyActionId(buffer);
this.layer = buffer.readUInt8();
this.isLayerToggleable = buffer.readBoolean();
return this;
}
_toJsObject(): 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}">`;
}
}

View File

@@ -0,0 +1,35 @@
import {MacroAction, MacroActionId, macroActionType} from './MacroAction';
import {UhkBuffer} from '../UhkBuffer';
export class TextMacroAction extends MacroAction {
text: string;
_fromJsObject(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;
}
_toJsObject(): 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}">`;
}
}

View File

@@ -0,0 +1,103 @@
import {Serializable} from '../Serializable';
import {ModuleConfigurations} from './ModuleConfigurations';
import {Keymap} from './Keymap';
import {Keymaps} from './Keymaps';
import {Macro} from './Macro';
import {Macros} from './Macros';
import {UhkBuffer} from '../UhkBuffer';
import {assertUInt8, assertUInt32} from '../assert';
export class UhkConfiguration extends Serializable<UhkConfiguration> {
signature: string;
@assertUInt8
dataModelVersion: number;
@assertUInt32
prologue: number;
@assertUInt8
hardwareId: number;
@assertUInt8
brandId: number;
moduleConfigurations: ModuleConfigurations;
keymaps: Keymaps;
macros: Macros;
@assertUInt32
epilogue: number;
_fromJsObject(jsObject: any): UhkConfiguration {
this.signature = jsObject.signature;
this.dataModelVersion = jsObject.dataModelVersion;
this.prologue = jsObject.prologue;
this.hardwareId = jsObject.hardwareId;
this.brandId = jsObject.brandId;
this.moduleConfigurations = new ModuleConfigurations().fromJsObject(jsObject.moduleConfigurations);
this.keymaps = new Keymaps().fromJsObject(jsObject.keymaps);
this.macros = new Macros().fromJsObject(jsObject.macros);
this.epilogue = jsObject.epilogue;
return this;
}
_fromBinary(buffer: UhkBuffer): UhkConfiguration {
this.signature = buffer.readString();
this.dataModelVersion = buffer.readUInt8();
this.prologue = buffer.readUInt32();
this.hardwareId = buffer.readUInt8();
this.brandId = buffer.readUInt8();
this.moduleConfigurations = new ModuleConfigurations().fromBinary(buffer);
this.keymaps = new Keymaps().fromBinary(buffer);
this.macros = new Macros().fromBinary(buffer);
this.epilogue = buffer.readUInt32();
return this;
}
_toJsObject(): any {
return {
signature: this.signature,
dataModelVersion: this.dataModelVersion,
prologue: this.prologue,
hardwareId: this.hardwareId,
brandId: this.brandId,
moduleConfigurations: this.moduleConfigurations.toJsObject(),
keymaps: this.keymaps.toJsObject(),
macros: this.macros.toJsObject(),
epilogue: this.epilogue
};
}
_toBinary(buffer: UhkBuffer): void {
buffer.writeString(this.signature);
buffer.writeUInt8(this.dataModelVersion);
buffer.writeUInt32(this.prologue);
buffer.writeUInt8(this.hardwareId);
buffer.writeUInt8(this.brandId);
this.moduleConfigurations.toBinary(buffer);
this.keymaps.toBinary(buffer);
this.macros.toBinary(buffer);
buffer.writeUInt32(this.epilogue);
}
toString(): string {
return `<UhkConfiguration signature="${this.signature}">`;
}
getKeymap(keymapId: number): Keymap {
let keymaps: Keymap[] = this.keymaps.elements;
for (let i = 0; i < keymaps.length; ++i) {
if (keymapId === keymaps[i].id) {
return keymaps[i];
}
}
}
getMacro(macroId: number): Macro {
return this.macros.elements.find(macro => macroId === macro.id);
}
}

View File

@@ -0,0 +1,164 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "UHK Configuration",
"description": "UHK Configuration",
"type": "object",
"properties": {
"prologue": {
"description": "Prologue",
"type": "integer"
},
"keymaps": {
"description": "Array of keymaps",
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"description": "Id of the keymap",
"type": "integer"
},
"isDefault": {
"type": "boolean"
},
"layers": {
"type": "array",
"items": {
"type": "object",
"properties": {
"modules": {
"type": "array",
"items": {
"type": "object",
"properties": {
"keyActions": {
"type": "array",
"items": {
"type": "object",
"properties": {
"keyActionType": {
"type": "string",
"enum": [
"none",
"keystroke",
"switchLayer",
"switchKeymap",
"playMacro",
"mouse"
]
}
},
"required": [
"keyActionType"
],
"oneOf": [
{
"properties": {
"keyActionType": {
"type": "string",
"enum": [
"mouse"
]
},
"mouseAction": {
"type": "string",
"enum": [
"leftClick",
"middleClick",
"rightClick",
"moveUp",
"moveDown",
"moveLeft",
"moveRight",
"scrollUp",
"scrollDown",
"scrollLeft",
"scrollRight",
"accelerate",
"decelerate"
]
}
}
},
{
"type": "object",
"properties": {
"keyActionType": {
"type": "string",
"enum": [
"keystroke"
]
},
"scancode": {
"type": "integer"
}
}
},
{
"type": "object",
"properties": {
"keyActionType": {
"type": "string",
"enum": [
"switchLayer"
]
},
"layer": {
"type": "string"
},
"toggle": {
"type": "boolean"
}
}
},
{
"type": "object",
"properties": {
"keyActionType": {
"type": "string",
"enum": [
"switchKeymap"
]
},
"keymapId": {
"type": "integer"
}
}
},
{
"properties": {
"keyActionType": {
"type": "string",
"enum": [
"playMacro"
]
},
"macroId": {
"type": "integer"
}
}
},
{
"properties": {
"keyActionType": {
"type": "string",
"enum": [
"none"
]
}
}
}
]
}
}
}
}
}
}
}
}
}
}
}
}
}

File diff suppressed because it is too large Load Diff