Seperate electron and web target building
This commit is contained in:
committed by
József Farkas
parent
517aed1b1c
commit
983eb72892
3
shared/src/config-serializer/Function.d.ts
vendored
Normal file
3
shared/src/config-serializer/Function.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
interface Function {
|
||||
name: string;
|
||||
}
|
||||
85
shared/src/config-serializer/README.md
Normal file
85
shared/src/config-serializer/README.md
Normal 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 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 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](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.
|
||||
```
|
||||
214
shared/src/config-serializer/UhkBuffer.ts
Normal file
214
shared/src/config-serializer/UhkBuffer.ts
Normal file
@@ -0,0 +1,214 @@
|
||||
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;
|
||||
|
||||
static simpleElementWriter<T>(buffer: UhkBuffer, element: T): void {
|
||||
(<any>element).toBinary(buffer); // TODO: Remove any
|
||||
}
|
||||
|
||||
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.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[] {
|
||||
let array: T[] = [];
|
||||
let 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
78
shared/src/config-serializer/assert.ts
Normal file
78
shared/src/config-serializer/assert.ts
Normal 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
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import { assertUInt8 } from '../assert';
|
||||
import { UhkBuffer } from '../UhkBuffer';
|
||||
|
||||
export class HardwareConfiguration {
|
||||
|
||||
signature: string;
|
||||
|
||||
@assertUInt8
|
||||
dataModelVersion: number;
|
||||
|
||||
@assertUInt8
|
||||
hardwareId: number;
|
||||
|
||||
@assertUInt8
|
||||
brandId: 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.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.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,
|
||||
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.writeBoolean(this.isIso);
|
||||
buffer.writeBoolean(this.hasBacklighting);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<HardwareConfiguration signature="${this.signature}">`;
|
||||
}
|
||||
|
||||
}
|
||||
10
shared/src/config-serializer/config-items/KeyModifiers.ts
Normal file
10
shared/src/config-serializer/config-items/KeyModifiers.ts
Normal 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
|
||||
}
|
||||
72
shared/src/config-serializer/config-items/Keymap.ts
Normal file
72
shared/src/config-serializer/config-items/Keymap.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { UhkBuffer } from '../UhkBuffer';
|
||||
import { Layer } from './Layer';
|
||||
import { Macro } from './Macro';
|
||||
|
||||
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));
|
||||
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);
|
||||
});
|
||||
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, macros?: Macro[]): 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, macros);
|
||||
});
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<Keymap abbreviation="${this.abbreviation}" name="${this.name}">`;
|
||||
}
|
||||
}
|
||||
45
shared/src/config-serializer/config-items/Layer.ts
Normal file
45
shared/src/config-serializer/config-items/Layer.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { UhkBuffer } from '../UhkBuffer';
|
||||
import { Keymap } from './Keymap';
|
||||
import { Macro } from './Macro';
|
||||
import { Module } from './Module';
|
||||
|
||||
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, macros?: Macro[]): void {
|
||||
buffer.writeArray(this.modules, (uhkBuffer: UhkBuffer, module: Module) => {
|
||||
module.toBinary(uhkBuffer, macros);
|
||||
});
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<Layer>`;
|
||||
}
|
||||
|
||||
}
|
||||
13
shared/src/config-serializer/config-items/LongPressAction.ts
Normal file
13
shared/src/config-serializer/config-items/LongPressAction.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
export enum LongPressAction {
|
||||
leftCtrl,
|
||||
leftShift,
|
||||
leftAlt,
|
||||
leftSuper,
|
||||
rightCtrl,
|
||||
rightShift,
|
||||
rightAlt,
|
||||
rightSuper,
|
||||
mod,
|
||||
fn,
|
||||
mouse
|
||||
};
|
||||
68
shared/src/config-serializer/config-items/Macro.ts
Normal file
68
shared/src/config-serializer/config-items/Macro.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { assertUInt8 } from '../assert';
|
||||
import { UhkBuffer } from '../UhkBuffer';
|
||||
import { Helper as MacroActionHelper, MacroAction } from './macro-action';
|
||||
|
||||
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();
|
||||
let 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}">`;
|
||||
}
|
||||
}
|
||||
86
shared/src/config-serializer/config-items/Module.ts
Normal file
86
shared/src/config-serializer/config-items/Module.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import { assertEnum, assertUInt8 } from '../assert';
|
||||
import { UhkBuffer } from '../UhkBuffer';
|
||||
import { Helper as KeyActionHelper, KeyAction, NoneAction } from './key-action';
|
||||
import { Keymap } from './Keymap';
|
||||
import { Macro } from './Macro';
|
||||
|
||||
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();
|
||||
let 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) {
|
||||
return keyAction.toJsonObject(macros);
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
toBinary(buffer: UhkBuffer, macros?: Macro[]): 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, macros);
|
||||
});
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<Module id="${this.id}" pointerRole="${this.pointerRole}">`;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import { assertUInt8 } from '../assert';
|
||||
import { UhkBuffer } from '../UhkBuffer';
|
||||
|
||||
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}" >`;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
import { assertUInt16 } from '../assert';
|
||||
import { UhkBuffer } from '../UhkBuffer';
|
||||
import { Keymap } from './Keymap';
|
||||
import { Macro } from './Macro';
|
||||
import { ModuleConfiguration } from './ModuleConfiguration';
|
||||
|
||||
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));
|
||||
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.macros);
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/// <reference path="../../Function.d.ts" />
|
||||
|
||||
import { Macro } from '../Macro';
|
||||
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 {
|
||||
|
||||
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 toJsonObject(macros?: Macro[]): any;
|
||||
abstract toBinary(buffer: UhkBuffer, macros?: Macro[]): any;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
import { assertEnum, assertUInt8 } from '../../assert';
|
||||
import { UhkBuffer } from '../../UhkBuffer';
|
||||
import { KeyModifiers } from '../KeyModifiers';
|
||||
import { LongPressAction } from '../LongPressAction';
|
||||
import { KeyAction, KeyActionId, keyActionType } from './KeyAction';
|
||||
|
||||
export enum KeystrokeActionFlag {
|
||||
scancode = 1 << 0,
|
||||
modifierMask = 1 << 1,
|
||||
longPressAction = 1 << 2
|
||||
}
|
||||
|
||||
interface JsonObjectKeystrokeAction {
|
||||
keyActionType: string;
|
||||
scancode?: number;
|
||||
modifierMask?: number;
|
||||
longPressAction?: string;
|
||||
}
|
||||
|
||||
const MODIFIERS = ['LCtrl', 'LShift', 'LAlt', 'LSuper', 'RCtrl', 'RShift', 'RAlt', 'RSuper'];
|
||||
|
||||
export class KeystrokeAction extends KeyAction {
|
||||
|
||||
@assertUInt8
|
||||
scancode: number;
|
||||
|
||||
@assertUInt8
|
||||
modifierMask: number;
|
||||
|
||||
@assertEnum(LongPressAction)
|
||||
longPressAction: LongPressAction;
|
||||
|
||||
constructor(other?: KeystrokeAction) {
|
||||
super();
|
||||
if (!other) {
|
||||
return;
|
||||
}
|
||||
this.scancode = other.scancode;
|
||||
this.modifierMask = other.modifierMask;
|
||||
this.longPressAction = other.longPressAction;
|
||||
}
|
||||
|
||||
fromJsonObject(jsonObject: JsonObjectKeystrokeAction): KeystrokeAction {
|
||||
this.assertKeyActionType(jsonObject);
|
||||
this.scancode = jsonObject.scancode;
|
||||
this.modifierMask = jsonObject.modifierMask;
|
||||
this.longPressAction = LongPressAction[jsonObject.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;
|
||||
}
|
||||
|
||||
toJsonObject(): JsonObjectKeystrokeAction {
|
||||
let jsonObject: JsonObjectKeystrokeAction = {
|
||||
keyActionType: keyActionType.KeystrokeAction
|
||||
};
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
getModifierList(): string[] {
|
||||
let modifierList: string[] = [];
|
||||
let modifierMask = this.modifierMask;
|
||||
for (let i = 0; modifierMask !== 0; ++i, modifierMask >>= 1) {
|
||||
if (modifierMask & 1) {
|
||||
modifierList.push(MODIFIERS[i]);
|
||||
}
|
||||
}
|
||||
return modifierList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import { assertEnum } from '../../assert';
|
||||
import { UhkBuffer } from '../../UhkBuffer';
|
||||
import { KeyAction, KeyActionId, keyActionType } from './KeyAction';
|
||||
|
||||
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}">`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { UhkBuffer } from '../../UhkBuffer';
|
||||
import { KeyAction, KeyActionId, keyActionType } from './KeyAction';
|
||||
|
||||
/**
|
||||
* 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>';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import { assertUInt8 } from '../../assert';
|
||||
import { UhkBuffer } from '../../UhkBuffer';
|
||||
import { Macro } from '../Macro';
|
||||
import { KeyAction, KeyActionId, keyActionType } from './KeyAction';
|
||||
|
||||
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, macros: Macro[]) {
|
||||
buffer.writeUInt8(KeyActionId.PlayMacroAction);
|
||||
buffer.writeUInt8(macros.findIndex(macro => macro.id === this.macroId));
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<PlayMacroAction macroId="${this.macroId}">`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { UhkBuffer } from '../../UhkBuffer';
|
||||
import { Keymap } from '../Keymap';
|
||||
import { KeyAction, KeyActionId, keyActionType } from './KeyAction';
|
||||
|
||||
export class SwitchKeymapAction extends KeyAction {
|
||||
|
||||
keymapAbbreviation: string;
|
||||
|
||||
constructor(parameter?: SwitchKeymapAction | Keymap) {
|
||||
super();
|
||||
if (!parameter) {
|
||||
return;
|
||||
}
|
||||
if (parameter instanceof SwitchKeymapAction) {
|
||||
this.keymapAbbreviation = parameter.keymapAbbreviation;
|
||||
} else {
|
||||
this.keymapAbbreviation = parameter.abbreviation;
|
||||
}
|
||||
}
|
||||
|
||||
fromJsonObject(jsonObject: any): SwitchKeymapAction {
|
||||
this.assertKeyActionType(jsonObject);
|
||||
this.keymapAbbreviation = jsonObject.keymapAbbreviation;
|
||||
return this;
|
||||
}
|
||||
|
||||
fromBinary(buffer: UhkBuffer): SwitchKeymapAction {
|
||||
this.readAndAssertKeyActionId(buffer);
|
||||
this.keymapAbbreviation = buffer.readString();
|
||||
return this;
|
||||
}
|
||||
|
||||
toJsonObject(): any {
|
||||
return {
|
||||
keyActionType: keyActionType.SwitchKeymapAction,
|
||||
keymapAbbreviation: this.keymapAbbreviation
|
||||
};
|
||||
}
|
||||
|
||||
toBinary(buffer: UhkBuffer) {
|
||||
buffer.writeUInt8(KeyActionId.SwitchKeymapAction);
|
||||
buffer.writeString(this.keymapAbbreviation);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<SwitchKeymapAction keymapAbbreviation="${this.keymapAbbreviation}">`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import { assertEnum } from '../../assert';
|
||||
import { UhkBuffer } from '../../UhkBuffer';
|
||||
import { KeyAction, KeyActionId, keyActionType } from './KeyAction';
|
||||
|
||||
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}">`;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
import { UhkBuffer } from '../../UhkBuffer';
|
||||
import {
|
||||
KeyAction,
|
||||
KeyActionId,
|
||||
KeystrokeAction,
|
||||
MouseAction,
|
||||
PlayMacroAction,
|
||||
SwitchKeymapAction,
|
||||
SwitchLayerAction,
|
||||
keyActionType
|
||||
} from './index';
|
||||
|
||||
import { Keymap } from '../Keymap';
|
||||
import { Macro } from '../Macro';
|
||||
|
||||
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 {
|
||||
let 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 SwitchKeymapAction().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}"`;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
export * from './KeyAction';
|
||||
export * from './KeystrokeAction';
|
||||
export * from './MouseAction';
|
||||
export * from './NoneAction';
|
||||
export * from './PlayMacroAction';
|
||||
export * from './SwitchKeymapAction';
|
||||
export * from './SwitchLayerAction';
|
||||
export * from './helper';
|
||||
@@ -0,0 +1,45 @@
|
||||
import { assertUInt16 } from '../../assert';
|
||||
import { UhkBuffer } from '../../UhkBuffer';
|
||||
import { MacroAction, MacroActionId, macroActionType } from './MacroAction';
|
||||
|
||||
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}">`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
import { KeyAction, KeystrokeAction, keyActionType } from '../key-action';
|
||||
import { DelayMacroAction } from './DelayMacroAction';
|
||||
import { KeyMacroAction } from './KeyMacroAction';
|
||||
import { MacroAction, MacroSubAction, macroActionType } from './MacroAction';
|
||||
import { MouseButtonMacroAction } from './MouseButtonMacroAction';
|
||||
import { MoveMouseMacroAction } from './MoveMouseMacroAction';
|
||||
import { ScrollMouseMacroAction } from './ScrollMouseMacroAction';
|
||||
import { TextMacroAction } from './TextMacroAction';
|
||||
|
||||
interface JsObjectEditableMacroAction {
|
||||
macroActionType: string;
|
||||
action?: string;
|
||||
scancode?: number;
|
||||
modifierMask?: number;
|
||||
mouseButtonsMask?: number;
|
||||
x?: number;
|
||||
y?: number;
|
||||
delay?: number;
|
||||
text?: string;
|
||||
}
|
||||
|
||||
export class EditableMacroAction {
|
||||
macroActionType: string;
|
||||
action: MacroSubAction;
|
||||
// Key macro action properties
|
||||
scancode: number;
|
||||
modifierMask: number;
|
||||
// Mouse macro action properties
|
||||
mouseButtonsMask: number;
|
||||
moveX: number;
|
||||
moveY: number;
|
||||
scrollX: number;
|
||||
scrollY: number;
|
||||
// Delay macro action properties
|
||||
delay: number;
|
||||
// Text macro action properties
|
||||
text: string;
|
||||
|
||||
constructor(jsObject?: JsObjectEditableMacroAction) {
|
||||
if (!jsObject) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.macroActionType = jsObject.macroActionType;
|
||||
|
||||
switch (this.macroActionType) {
|
||||
case macroActionType.KeyMacroAction:
|
||||
this.action = MacroSubAction[jsObject.action];
|
||||
this.scancode = jsObject.scancode;
|
||||
this.modifierMask = jsObject.modifierMask;
|
||||
break;
|
||||
case macroActionType.MouseButtonMacroAction:
|
||||
this.action = MacroSubAction[jsObject.action];
|
||||
this.mouseButtonsMask = jsObject.mouseButtonsMask;
|
||||
break;
|
||||
case macroActionType.MoveMouseMacroAction:
|
||||
this.moveX = jsObject.x;
|
||||
this.moveY = jsObject.y;
|
||||
break;
|
||||
case macroActionType.ScrollMouseMacroAction:
|
||||
this.scrollX = jsObject.x;
|
||||
this.scrollY = jsObject.y;
|
||||
break;
|
||||
case macroActionType.TextMacroAction:
|
||||
this.text = jsObject.text;
|
||||
break;
|
||||
case macroActionType.DelayMacroAction:
|
||||
this.delay = jsObject.delay;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
toJsObject(): any {
|
||||
return {
|
||||
macroActionType: this.macroActionType,
|
||||
action: this.action,
|
||||
delay: this.delay,
|
||||
text: this.text,
|
||||
scancode: this.scancode,
|
||||
modifierMask: this.modifierMask,
|
||||
mouseButtonsMask: this.mouseButtonsMask,
|
||||
mouseMove: {
|
||||
x: this.moveX,
|
||||
y: this.moveY
|
||||
},
|
||||
mouseScroll: {
|
||||
x: this.scrollX,
|
||||
y: this.scrollY
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fromKeyAction(keyAction: KeyAction): void {
|
||||
let data = keyAction.toJsonObject();
|
||||
this.scancode = data.scancode;
|
||||
this.modifierMask = data.modifierMask;
|
||||
}
|
||||
|
||||
toKeystrokeAction(): KeystrokeAction {
|
||||
let data = this.toJsObject();
|
||||
data.keyActionType = keyActionType.KeystrokeAction;
|
||||
return <KeystrokeAction>(new KeystrokeAction().fromJsonObject(data));
|
||||
}
|
||||
|
||||
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[] {
|
||||
let enabledMouseButtons: boolean[] = [];
|
||||
for (let bitmask = this.mouseButtonsMask; bitmask; bitmask >>>= 1) {
|
||||
enabledMouseButtons.push(Boolean(bitmask & 1));
|
||||
}
|
||||
return enabledMouseButtons;
|
||||
}
|
||||
|
||||
toClass(): MacroAction {
|
||||
switch (this.macroActionType) {
|
||||
// Delay action
|
||||
case macroActionType.DelayMacroAction:
|
||||
return new DelayMacroAction().fromJsonObject({
|
||||
macroActionType: this.macroActionType,
|
||||
delay: this.delay
|
||||
});
|
||||
// Text action
|
||||
case macroActionType.TextMacroAction:
|
||||
return new TextMacroAction().fromJsonObject({
|
||||
macroActionType: this.macroActionType,
|
||||
text: this.text
|
||||
});
|
||||
// Keypress action
|
||||
case macroActionType.KeyMacroAction:
|
||||
return new KeyMacroAction().fromJsonObject({
|
||||
macroActionType: this.macroActionType,
|
||||
action: MacroSubAction[this.action],
|
||||
scancode: this.scancode,
|
||||
modifierMask: this.modifierMask
|
||||
});
|
||||
// Mouse actions
|
||||
case macroActionType.MouseButtonMacroAction:
|
||||
return new MouseButtonMacroAction().fromJsonObject({
|
||||
macroActionType: this.macroActionType,
|
||||
action: MacroSubAction[this.action],
|
||||
mouseButtonsMask: this.mouseButtonsMask
|
||||
});
|
||||
case macroActionType.MoveMouseMacroAction:
|
||||
return new MoveMouseMacroAction().fromJsonObject({
|
||||
macroActionType: this.macroActionType,
|
||||
x: this.moveX,
|
||||
y: this.moveY
|
||||
});
|
||||
case macroActionType.ScrollMouseMacroAction:
|
||||
return new ScrollMouseMacroAction().fromJsonObject({
|
||||
macroActionType: this.macroActionType,
|
||||
x: this.scrollX,
|
||||
y: this.scrollY
|
||||
});
|
||||
default:
|
||||
throw new Error('Macro action type is missing or not implemented.');
|
||||
}
|
||||
}
|
||||
|
||||
isKeyAction(): boolean {
|
||||
return this.macroActionType === macroActionType.KeyMacroAction;
|
||||
}
|
||||
|
||||
isMouseButtonAction(): boolean {
|
||||
return this.macroActionType === macroActionType.MouseButtonMacroAction;
|
||||
}
|
||||
|
||||
isOnlyHoldAction(): boolean {
|
||||
return this.action === MacroSubAction.hold;
|
||||
}
|
||||
|
||||
isOnlyPressAction(): boolean {
|
||||
return this.action === MacroSubAction.press;
|
||||
}
|
||||
|
||||
isOnlyReleaseAction(): boolean {
|
||||
return this.action === MacroSubAction.release;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
import { assertEnum, assertUInt8 } from '../../assert';
|
||||
import { UhkBuffer } from '../../UhkBuffer';
|
||||
import { KeyModifiers } from '../KeyModifiers';
|
||||
import { MacroAction, MacroActionId, MacroSubAction, macroActionType } from './MacroAction';
|
||||
|
||||
const NUM_OF_COMBINATIONS = 3; // Cases: scancode, modifer, both
|
||||
|
||||
interface JsObjectKeyMacroAction {
|
||||
macroActionType: string;
|
||||
action: string;
|
||||
scancode?: number;
|
||||
modifierMask?: number;
|
||||
}
|
||||
|
||||
export class KeyMacroAction extends MacroAction {
|
||||
|
||||
@assertEnum(MacroSubAction)
|
||||
action: MacroSubAction;
|
||||
|
||||
@assertUInt8
|
||||
scancode: number;
|
||||
|
||||
@assertUInt8
|
||||
modifierMask: number;
|
||||
|
||||
constructor(other?: KeyMacroAction) {
|
||||
super();
|
||||
if (!other) {
|
||||
return;
|
||||
}
|
||||
this.action = other.action;
|
||||
this.scancode = other.scancode;
|
||||
this.modifierMask = other.modifierMask;
|
||||
}
|
||||
|
||||
fromJsonObject(jsObject: JsObjectKeyMacroAction): KeyMacroAction {
|
||||
this.assertMacroActionType(jsObject);
|
||||
this.action = MacroSubAction[jsObject.action];
|
||||
this.scancode = jsObject.scancode;
|
||||
this.modifierMask = jsObject.modifierMask;
|
||||
return this;
|
||||
}
|
||||
|
||||
fromBinary(buffer: UhkBuffer): KeyMacroAction {
|
||||
let macroActionId: MacroActionId = this.readAndAssertMacroActionId(buffer);
|
||||
let keyMacroType: number = macroActionId - MacroActionId.KeyMacroAction;
|
||||
this.action = Math.floor(keyMacroType / NUM_OF_COMBINATIONS);
|
||||
keyMacroType %= NUM_OF_COMBINATIONS;
|
||||
if (keyMacroType % 2 === 0) {
|
||||
this.scancode = buffer.readUInt8();
|
||||
}
|
||||
if (keyMacroType !== 0) {
|
||||
this.modifierMask = buffer.readUInt8();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
toJsonObject(): any {
|
||||
let jsObject: JsObjectKeyMacroAction = {
|
||||
macroActionType: macroActionType.KeyMacroAction,
|
||||
action: MacroSubAction[this.action]
|
||||
};
|
||||
|
||||
if (this.hasScancode()) {
|
||||
jsObject.scancode = this.scancode;
|
||||
}
|
||||
|
||||
if (this.hasModifiers()) {
|
||||
jsObject.modifierMask = this.modifierMask;
|
||||
}
|
||||
|
||||
return jsObject;
|
||||
}
|
||||
|
||||
toBinary(buffer: UhkBuffer) {
|
||||
let keyMacroType: number = MacroActionId.KeyMacroAction;
|
||||
keyMacroType += NUM_OF_COMBINATIONS * this.action;
|
||||
|
||||
if (this.hasModifiers()) {
|
||||
++keyMacroType;
|
||||
if (this.hasScancode()) {
|
||||
++keyMacroType;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
import { UhkBuffer } from '../../UhkBuffer';
|
||||
|
||||
export enum MacroActionId {
|
||||
KeyMacroAction = 0,
|
||||
/*
|
||||
0 - 8 are reserved for KeyMacroAction
|
||||
PressKeyMacroAction with scancode: 0
|
||||
PressKeyMacroAction with modifiers: 1
|
||||
PressKeyMacroAction with scancode and modifiers 2
|
||||
HoldKeyMacroAction with scancode: 3
|
||||
HoldKeyMacroAction with modifiers: 4
|
||||
HoldKeyMacroAction with scancode and modifiers 5
|
||||
ReleaseKeyMacroAction with scancode: 6
|
||||
ReleaseKeyMacroAction with modifiers: 7
|
||||
ReleaseKeyMacroAction with scancode and modifiers 8
|
||||
*/
|
||||
LastKeyMacroAction = 8,
|
||||
MouseButtonMacroAction = 9,
|
||||
/*
|
||||
9 - 11 are reserved for MouseButtonMacroAction
|
||||
PressMouseButtonsMacroAction = 9,
|
||||
HoldMouseButtonsMacroAction = 10,
|
||||
ReleaseMouseButtonsMacroAction = 11,
|
||||
*/
|
||||
LastMouseButtonMacroAction = 11,
|
||||
MoveMouseMacroAction = 12,
|
||||
ScrollMouseMacroAction = 13,
|
||||
DelayMacroAction = 14,
|
||||
TextMacroAction = 15
|
||||
}
|
||||
|
||||
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) {
|
||||
let macroActionClassname = this.constructor.name;
|
||||
let macroActionTypeString = macroActionType[macroActionClassname];
|
||||
if (jsObject.macroActionType !== macroActionTypeString) {
|
||||
throw `Invalid ${macroActionClassname}.macroActionType: ${jsObject.macroActionType}`;
|
||||
}
|
||||
}
|
||||
|
||||
readAndAssertMacroActionId(buffer: UhkBuffer): MacroActionId {
|
||||
let classname: string = this.constructor.name;
|
||||
let readMacroActionId: MacroActionId = buffer.readUInt8();
|
||||
let 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;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
import { assertEnum, assertUInt8 } from '../../assert';
|
||||
import { UhkBuffer } from '../../UhkBuffer';
|
||||
import { MacroAction, MacroActionId, MacroSubAction, macroActionType } from './MacroAction';
|
||||
|
||||
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 {
|
||||
let 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[] {
|
||||
let 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import { assertInt16 } from '../../assert';
|
||||
import { UhkBuffer } from '../../UhkBuffer';
|
||||
import { MacroAction, MacroActionId, macroActionType } from './MacroAction';
|
||||
|
||||
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})">`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import { assertInt16 } from '../../assert';
|
||||
import { UhkBuffer } from '../../UhkBuffer';
|
||||
import { MacroAction, MacroActionId, macroActionType } from './MacroAction';
|
||||
|
||||
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})">`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { UhkBuffer } from '../../UhkBuffer';
|
||||
import { MacroAction, MacroActionId, macroActionType } from './MacroAction';
|
||||
|
||||
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}">`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import { UhkBuffer } from '../../UhkBuffer';
|
||||
import {
|
||||
DelayMacroAction,
|
||||
KeyMacroAction,
|
||||
MacroAction,
|
||||
MacroActionId,
|
||||
MouseButtonMacroAction,
|
||||
MoveMouseMacroAction,
|
||||
ScrollMouseMacroAction,
|
||||
TextMacroAction,
|
||||
macroActionType
|
||||
} from './index';
|
||||
|
||||
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 {
|
||||
let 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}"`;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
export * from './DelayMacroAction';
|
||||
export * from './EditableMacroAction';
|
||||
export * from './KeyMacroAction';
|
||||
export * from './MacroAction';
|
||||
export * from './MoveMouseMacroAction';
|
||||
export * from './MouseButtonMacroAction';
|
||||
export * from './ScrollMouseMacroAction';
|
||||
export * from './TextMacroAction';
|
||||
export * from './helper';
|
||||
156
shared/src/config-serializer/config-schema.json
Normal file
156
shared/src/config-serializer/config-schema.json
Normal file
@@ -0,0 +1,156 @@
|
||||
{
|
||||
"$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": [
|
||||
"null",
|
||||
"object"
|
||||
],
|
||||
"properties": {
|
||||
"keyActionType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"keystroke",
|
||||
"switchLayer",
|
||||
"switchKeymap",
|
||||
"playMacro",
|
||||
"mouse"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"keyActionType"
|
||||
],
|
||||
"anyOf": [
|
||||
{
|
||||
"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"
|
||||
]
|
||||
},
|
||||
"macroIndex": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
8
shared/src/config-serializer/hardware-config.json
Normal file
8
shared/src/config-serializer/hardware-config.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"signature": "UHK",
|
||||
"dataModelVersion": 0,
|
||||
"hardwareId": 0,
|
||||
"brandId": 0,
|
||||
"isIso": false,
|
||||
"hasBacklighting": false
|
||||
}
|
||||
1757
shared/src/config-serializer/preset-keymaps.json
Normal file
1757
shared/src/config-serializer/preset-keymaps.json
Normal file
File diff suppressed because it is too large
Load Diff
1550
shared/src/config-serializer/user-config.json
Normal file
1550
shared/src/config-serializer/user-config.json
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user