feat(config): Read / write hardware configuration area (#423)
* add write-hca.js * refactor: Move config serializer into the uhk-common package * refactor: Move getTransferBuffers into the uhk-usb package * refactor: delete obsoleted classes * build: add uhk-usb build command * refactor: move eeprom transfer to uhk-usb package * fix: Fix write-hca.js * feat: load hardware config from the device and * style: fix ts lint errors * build: fix rxjs dependency resolve * test: Add jasmine unit test framework to the tet serializer * fix(user-config): A "type": "basic", properties to the "keystroke" action types * feat(usb): set chmod+x on write-hca.js * feat(usb): Create USB logger * style: Fix type * build: Add chalk to dependencies. Chalk will colorize the output
This commit is contained in:
committed by
László Monda
parent
1122784bdb
commit
9294bede50
@@ -2,6 +2,7 @@ import { Component, HostListener, ViewEncapsulation } from '@angular/core';
|
||||
import { animate, style, transition, trigger } from '@angular/animations';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { Action, Store } from '@ngrx/store';
|
||||
import { UhkBuffer } from 'uhk-common';
|
||||
|
||||
import 'rxjs/add/operator/last';
|
||||
|
||||
@@ -14,7 +15,6 @@ import {
|
||||
saveToKeyboardState
|
||||
} from './store';
|
||||
import { getUserConfiguration } from './store/reducers/user-configuration';
|
||||
import { UhkBuffer } from './config-serializer/uhk-buffer';
|
||||
import { ProgressButtonState } from './store/reducers/progress-button-state';
|
||||
|
||||
@Component({
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
<svg-keyboard *ngFor="let layer of layers; let index = index; trackBy: trackKeyboard"
|
||||
[@layerState]="layerAnimationState[index]"
|
||||
[moduleConfig]="layer.modules"
|
||||
[keybindAnimationEnabled]="keybindAnimationEnabled"
|
||||
[halvesSplit]="halvesSplit"
|
||||
[capturingEnabled]="capturingEnabled"
|
||||
[selectedKey]="selectedKey"
|
||||
[selected]="selectedKey?.layerId === index"
|
||||
(keyClick)="keyClick.emit($event)"
|
||||
(keyHover)="keyHover.emit($event)"
|
||||
(capture)="capture.emit($event)"
|
||||
[@layerState]="layerAnimationState[index]"
|
||||
[moduleConfig]="layer.modules"
|
||||
[keybindAnimationEnabled]="keybindAnimationEnabled"
|
||||
[halvesSplit]="halvesSplit"
|
||||
[capturingEnabled]="capturingEnabled"
|
||||
[selectedKey]="selectedKey"
|
||||
[selected]="selectedKey?.layerId === index"
|
||||
[keyboardLayout]="keyboardLayout"
|
||||
(keyClick)="keyClick.emit($event)"
|
||||
(keyHover)="keyHover.emit($event)"
|
||||
(capture)="capture.emit($event)"
|
||||
>
|
||||
</svg-keyboard>
|
||||
|
||||
|
Before Width: | Height: | Size: 511 B After Width: | Height: | Size: 659 B |
@@ -1,7 +1,8 @@
|
||||
import { Component, ChangeDetectionStrategy, Input, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core';
|
||||
import { animate, keyframes, state, style, transition, trigger } from '@angular/animations';
|
||||
import { Layer } from 'uhk-common';
|
||||
|
||||
import { Layer } from '../../../config-serializer/config-items/layer';
|
||||
import { KeyboardLayout } from '../../../keyboard/keyboard-layout.enum';
|
||||
|
||||
type AnimationKeyboard =
|
||||
'leftIn' |
|
||||
@@ -69,6 +70,7 @@ export class KeyboardSliderComponent implements OnChanges {
|
||||
@Input() capturingEnabled: boolean;
|
||||
@Input() halvesSplit: boolean;
|
||||
@Input() selectedKey: { layerId: number, moduleId: number, keyId: number };
|
||||
@Input() keyboardLayout = KeyboardLayout.ANSI;
|
||||
@Output() keyClick = new EventEmitter();
|
||||
@Output() keyHover = new EventEmitter();
|
||||
@Output() capture = new EventEmitter();
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Keymap } from 'uhk-common';
|
||||
|
||||
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import 'rxjs/add/operator/combineLatest';
|
||||
import 'rxjs/add/operator/publishReplay';
|
||||
|
||||
import { Keymap } from '../../../config-serializer/config-items/keymap';
|
||||
import { AppState } from '../../../store';
|
||||
import { KeymapActions } from '../../../store/actions';
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CanActivate, Router } from '@angular/router';
|
||||
import { Keymap } from 'uhk-common';
|
||||
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
@@ -10,7 +11,6 @@ import 'rxjs/add/operator/switchMap';
|
||||
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
import { Keymap } from '../../../config-serializer/config-items/keymap';
|
||||
import { AppState } from '../../../store/index';
|
||||
import { getKeymaps } from '../../../store/reducers/user-configuration';
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<ng-template [ngIf]="keymap$ | async">
|
||||
<keymap-header [keymap]="keymap$ | async" [deletable]="deletable$ | async" (downloadClick)="downloadKeymap()"></keymap-header>
|
||||
<svg-keyboard-wrap [keymap]="keymap$ | async" [halvesSplit]="keyboardSplit"></svg-keyboard-wrap>
|
||||
<keymap-header [keymap]="keymap$ | async"
|
||||
[deletable]="deletable$ | async"
|
||||
(downloadClick)="downloadKeymap()"></keymap-header>
|
||||
<svg-keyboard-wrap [keymap]="keymap$ | async"
|
||||
[halvesSplit]="keyboardSplit"
|
||||
[keyboardLayout]="keyboardLayout$ | async"></svg-keyboard-wrap>
|
||||
</ng-template>
|
||||
|
||||
<div *ngIf="!(keymap$ | async)" class="not-found">
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { Component, HostListener, ViewChild } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Keymap } from 'uhk-common';
|
||||
|
||||
import '@ngrx/core/add/operator/select';
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import 'rxjs/add/operator/first';
|
||||
@@ -15,11 +16,11 @@ import 'rxjs/add/operator/combineLatest';
|
||||
|
||||
import { saveAs } from 'file-saver';
|
||||
|
||||
import { Keymap } from '../../../config-serializer/config-items/keymap';
|
||||
import { AppState } from '../../../store';
|
||||
import { AppState, getKeyboardLayout } from '../../../store';
|
||||
import { getKeymap, getKeymaps, getUserConfiguration } from '../../../store/reducers/user-configuration';
|
||||
import 'rxjs/add/operator/pluck';
|
||||
import { SvgKeyboardWrapComponent } from '../../svg/wrap/svg-keyboard-wrap.component';
|
||||
import { KeyboardLayout } from '../../../keyboard/keyboard-layout.enum';
|
||||
|
||||
@Component({
|
||||
selector: 'keymap-edit',
|
||||
@@ -37,6 +38,7 @@ export class KeymapEditComponent {
|
||||
|
||||
deletable$: Observable<boolean>;
|
||||
keymap$: Observable<Keymap>;
|
||||
keyboardLayout$: Observable<KeyboardLayout>;
|
||||
|
||||
constructor(protected store: Store<AppState>,
|
||||
route: ActivatedRoute) {
|
||||
@@ -49,6 +51,8 @@ export class KeymapEditComponent {
|
||||
|
||||
this.deletable$ = store.let(getKeymaps())
|
||||
.map((keymaps: Keymap[]) => keymaps.length > 1);
|
||||
|
||||
this.keyboardLayout$ = store.select(getKeyboardLayout);
|
||||
}
|
||||
|
||||
downloadKeymap() {
|
||||
|
||||
@@ -10,11 +10,10 @@ import {
|
||||
SimpleChanges,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import { Keymap } from 'uhk-common';
|
||||
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
import { Keymap } from '../../../config-serializer/config-items/keymap';
|
||||
|
||||
import { AppState } from '../../../store';
|
||||
import { KeymapActions } from '../../../store/actions';
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ import {
|
||||
MoveMouseMacroAction,
|
||||
MouseButtonMacroAction,
|
||||
TextMacroAction,
|
||||
Helper as MacroActionHelper
|
||||
} from '../../../config-serializer/config-items/macro-action';
|
||||
MacroActionHelper
|
||||
} from 'uhk-common';
|
||||
import { MacroDelayTabComponent, MacroMouseTabComponent, MacroKeyTabComponent, MacroTextTabComponent } from './tab';
|
||||
|
||||
enum TabName {
|
||||
|
||||
@@ -6,8 +6,8 @@ import {
|
||||
OnInit,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import { DelayMacroAction } from 'uhk-common';
|
||||
|
||||
import { DelayMacroAction } from '../../../../../config-serializer/config-items/macro-action';
|
||||
import { MacroBaseComponent } from '../macro-base.component';
|
||||
|
||||
const INITIAL_DELAY = 0.5; // In seconds
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Component, Input, OnInit, ViewChild } from '@angular/core';
|
||||
|
||||
import { KeystrokeAction } from '../../../../../config-serializer/config-items/key-action';
|
||||
import { KeyMacroAction, MacroSubAction } from '../../../../../config-serializer/config-items/macro-action';
|
||||
import { KeyMacroAction, KeystrokeAction, MacroSubAction } from 'uhk-common';
|
||||
import { KeypressTabComponent, Tab } from '../../../../popover/tab';
|
||||
import { MacroBaseComponent } from '../macro-base.component';
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
MoveMouseMacroAction,
|
||||
ScrollMouseMacroAction,
|
||||
MacroSubAction
|
||||
} from '../../../../../config-serializer/config-items/macro-action';
|
||||
} from 'uhk-common';
|
||||
import { Tab } from '../../../../popover/tab';
|
||||
import { MacroBaseComponent } from '../macro-base.component';
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ import {
|
||||
Renderer,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import { TextMacroAction } from 'uhk-common';
|
||||
|
||||
import { TextMacroAction } from '../../../../../config-serializer/config-items/macro-action';
|
||||
import { MacroBaseComponent } from '../macro-base.component';
|
||||
|
||||
@Component({
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
import { Component, OnDestroy } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Macro, MacroAction } from 'uhk-common';
|
||||
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
import 'rxjs/add/operator/pluck';
|
||||
|
||||
import { Macro } from '../../../config-serializer/config-items/macro';
|
||||
import { MacroAction } from '../../../config-serializer/config-items/macro-action/macro-action';
|
||||
|
||||
import { MacroActions } from '../../../store/actions';
|
||||
import { AppState } from '../../../store/index';
|
||||
import { getMacro } from '../../../store/reducers/user-configuration';
|
||||
|
||||
@@ -9,10 +9,8 @@ import {
|
||||
SimpleChanges,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
import { Macro } from '../../../config-serializer/config-items/macro';
|
||||
import { Macro } from 'uhk-common';
|
||||
|
||||
import { MacroActions } from '../../../store/actions';
|
||||
import { AppState } from '../../../store/index';
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
import { Component, Input, Output, EventEmitter, OnChanges, OnInit, SimpleChanges } from '@angular/core';
|
||||
import { animate, state, style, transition, trigger } from '@angular/animations';
|
||||
|
||||
import { KeyModifiers } from '../../../config-serializer/config-items/key-modifiers';
|
||||
import {
|
||||
DelayMacroAction,
|
||||
KeyMacroAction,
|
||||
KeyModifiers,
|
||||
MacroAction,
|
||||
MouseButtonMacroAction,
|
||||
MoveMouseMacroAction,
|
||||
ScrollMouseMacroAction,
|
||||
TextMacroAction
|
||||
} from '../../../config-serializer/config-items/macro-action';
|
||||
} from 'uhk-common';
|
||||
|
||||
import { MapperService } from '../../../services/mapper.service';
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { Component, EventEmitter, Input, Output, QueryList, ViewChildren, forwardRef } from '@angular/core';
|
||||
import { animate, state, style, transition, trigger } from '@angular/animations';
|
||||
|
||||
import { DragulaService } from 'ng2-dragula/ng2-dragula';
|
||||
import { Macro, MacroAction } from 'uhk-common';
|
||||
|
||||
import { Macro } from '../../../config-serializer/config-items/macro';
|
||||
import { MacroAction } from '../../../config-serializer/config-items/macro-action';
|
||||
import { MacroItemComponent } from '../item';
|
||||
|
||||
@Component({
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CanActivate, Router } from '@angular/router';
|
||||
import { Macro } from 'uhk-common';
|
||||
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
@@ -10,7 +11,6 @@ import { Store } from '@ngrx/store';
|
||||
|
||||
import { AppState } from '../../../store/index';
|
||||
import { getMacros } from '../../../store/reducers/user-configuration';
|
||||
import { Macro } from '../../../config-serializer/config-items/macro';
|
||||
|
||||
@Injectable()
|
||||
export class MacroNotFoundGuard implements CanActivate {
|
||||
|
||||
@@ -19,13 +19,13 @@ import 'rxjs/add/operator/map';
|
||||
|
||||
import {
|
||||
KeyAction,
|
||||
Keymap,
|
||||
KeystrokeAction,
|
||||
MouseAction,
|
||||
PlayMacroAction,
|
||||
SwitchKeymapAction,
|
||||
SwitchLayerAction
|
||||
} from '../../config-serializer/config-items/key-action';
|
||||
import { Keymap } from '../../config-serializer/config-items/keymap';
|
||||
} from 'uhk-common';
|
||||
|
||||
import { Tab } from './tab/tab';
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core';
|
||||
|
||||
import { Select2OptionData } from 'ng2-select2/ng2-select2';
|
||||
import { Keymap, KeyAction, SwitchKeymapAction } from 'uhk-common';
|
||||
|
||||
import { KeyAction, SwitchKeymapAction } from '../../../../config-serializer/config-items/key-action';
|
||||
import { Keymap } from '../../../../config-serializer/config-items/keymap';
|
||||
import { Tab } from '../tab';
|
||||
|
||||
@Component({
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import { Component, Input, OnChanges } from '@angular/core';
|
||||
|
||||
import { Select2OptionData, Select2TemplateFunction } from 'ng2-select2';
|
||||
|
||||
import { KeyAction, KeystrokeAction } from '../../../../config-serializer/config-items/key-action';
|
||||
import { KeyAction, KeystrokeAction, KeystrokeType } from 'uhk-common';
|
||||
|
||||
import { Tab } from '../tab';
|
||||
import { MapperService } from '../../../../services/mapper.service';
|
||||
import { KeystrokeType } from '../../../../config-serializer/config-items/key-action/keystroke-type';
|
||||
|
||||
@Component({
|
||||
selector: 'keypress-tab',
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Component, HostBinding, Input, OnChanges, SimpleChanges } from '@angular/core';
|
||||
|
||||
import { KeyAction, LayerName, SwitchLayerAction } from '../../../../config-serializer/config-items/key-action';
|
||||
import { KeyAction, LayerName, SwitchLayerAction } from 'uhk-common';
|
||||
|
||||
import { Tab } from '../tab';
|
||||
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core';
|
||||
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
|
||||
import { Select2OptionData } from 'ng2-select2/ng2-select2';
|
||||
|
||||
import { KeyAction, PlayMacroAction } from '../../../../config-serializer/config-items/key-action';
|
||||
import { Macro } from '../../../../config-serializer/config-items/macro';
|
||||
import { KeyAction, Macro, PlayMacroAction } from 'uhk-common';
|
||||
|
||||
import { Tab } from '../tab';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Component, Input, OnChanges } from '@angular/core';
|
||||
import { KeyAction, MouseAction, MouseActionParam } from 'uhk-common';
|
||||
|
||||
import { KeyAction, MouseAction, MouseActionParam } from '../../../../config-serializer/config-items/key-action';
|
||||
import { Tab } from '../tab';
|
||||
|
||||
@Component({
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { EventEmitter, Output } from '@angular/core';
|
||||
|
||||
import { KeyAction } from '../../../config-serializer/config-items/key-action';
|
||||
import { KeyAction } from 'uhk-common';
|
||||
|
||||
export abstract class Tab {
|
||||
@Output() validAction = new EventEmitter<boolean>();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Component, Renderer } from '@angular/core';
|
||||
import { animate, state, style, transition, trigger } from '@angular/animations';
|
||||
import { Keymap, Macro } from 'uhk-common';
|
||||
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
@@ -8,9 +9,6 @@ import 'rxjs/add/operator/do';
|
||||
import 'rxjs/add/operator/map';
|
||||
import 'rxjs/add/operator/let';
|
||||
|
||||
import { Keymap } from '../../config-serializer/config-items/keymap';
|
||||
import { Macro } from '../../config-serializer/config-items/macro';
|
||||
|
||||
import { AppState, showAddonMenu, runningInElectron } from '../../store';
|
||||
import { MacroActions } from '../../store/actions';
|
||||
import { getKeymaps, getMacros } from '../../store/reducers/user-configuration';
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { Component, EventEmitter, Input, OnInit, Output, SimpleChanges, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { animate, state, trigger, style, transition } from '@angular/animations';
|
||||
import { Module } from 'uhk-common';
|
||||
|
||||
import { Module } from '../../../config-serializer/config-items/module';
|
||||
import { SvgModule } from '../module';
|
||||
import { SvgModuleProviderService } from '../../../services/svg-module-provider.service';
|
||||
import { KeyboardLayout } from '../../../keyboard/keyboard-layout.enum';
|
||||
|
||||
@Component({
|
||||
selector: 'svg-keyboard',
|
||||
@@ -29,6 +30,7 @@ export class SvgKeyboardComponent implements OnInit {
|
||||
@Input() selectedKey: { layerId: number, moduleId: number, keyId: number };
|
||||
@Input() selected: boolean;
|
||||
@Input() halvesSplit: boolean;
|
||||
@Input() keyboardLayout = KeyboardLayout.ANSI;
|
||||
@Output() keyClick = new EventEmitter();
|
||||
@Output() keyHover = new EventEmitter();
|
||||
@Output() capture = new EventEmitter();
|
||||
@@ -45,13 +47,17 @@ export class SvgKeyboardComponent implements OnInit {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.modules = this.svgModuleProvider.getSvgModules();
|
||||
this.setModules();
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes.halvesSplit) {
|
||||
this.updateModuleAnimationStates();
|
||||
}
|
||||
|
||||
if (changes['keyboardLayout']) {
|
||||
this.setModules();
|
||||
}
|
||||
}
|
||||
|
||||
onKeyClick(moduleId: number, keyId: number, keyTarget: HTMLElement): void {
|
||||
@@ -87,4 +93,7 @@ export class SvgKeyboardComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
private setModules() {
|
||||
this.modules = this.svgModuleProvider.getSvgModules(this.keyboardLayout);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,15 +10,15 @@ import { Subscription } from 'rxjs/Subscription';
|
||||
|
||||
import {
|
||||
KeyAction,
|
||||
KeyModifiers,
|
||||
KeystrokeAction,
|
||||
LayerName,
|
||||
Macro,
|
||||
MouseAction,
|
||||
PlayMacroAction,
|
||||
SwitchKeymapAction,
|
||||
SwitchLayerAction
|
||||
} from '../../../../config-serializer/config-items/key-action';
|
||||
import { KeyModifiers } from '../../../../config-serializer/config-items/key-modifiers';
|
||||
import { Macro } from '../../../../config-serializer/config-items/macro';
|
||||
} from 'uhk-common';
|
||||
|
||||
import { CaptureService } from '../../../../services/capture.service';
|
||||
import { MapperService } from '../../../../services/mapper.service';
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Component, Input, OnChanges, OnInit, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { KeyModifiers, KeystrokeAction } from 'uhk-common';
|
||||
|
||||
import { KeystrokeAction } from '../../../../config-serializer/config-items/key-action';
|
||||
import { KeyModifiers } from '../../../../config-serializer/config-items/key-modifiers';
|
||||
import { MapperService } from '../../../../services/mapper.service';
|
||||
|
||||
class SvgAttributes {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Component, Input, OnChanges, ChangeDetectionStrategy } from '@angular/core';
|
||||
|
||||
import { MouseAction, MouseActionParam } from '../../../../config-serializer/config-items/key-action';
|
||||
import { MouseAction, MouseActionParam } from 'uhk-common';
|
||||
|
||||
@Component({
|
||||
selector: 'g[svg-mouse-key]',
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Component, EventEmitter, Input, Output, ChangeDetectionStrategy } from '@angular/core';
|
||||
|
||||
import { KeyAction } from '../../../config-serializer/config-items/key-action';
|
||||
import { KeyAction } from 'uhk-common';
|
||||
|
||||
import { SvgKeyboardKey } from '../keys';
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
[capturingEnabled]="popoverEnabled"
|
||||
[selectedKey]="selectedKey"
|
||||
[halvesSplit]="halvesSplit"
|
||||
[keyboardLayout]="keyboardLayout"
|
||||
(keyClick)="onKeyClick($event.moduleId, $event.keyId, $event.keyTarget)"
|
||||
(keyHover)="onKeyHover($event.moduleId, $event.event, $event.over, $event.keyId)"
|
||||
(capture)="onCapture($event.moduleId, $event.keyId, $event.captured)"
|
||||
|
||||
@@ -17,26 +17,27 @@ import 'rxjs/add/observable/of';
|
||||
import 'rxjs/add/operator/map';
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
import { MapperService } from '../../../services/mapper.service';
|
||||
|
||||
import {
|
||||
camelCaseToSentence,
|
||||
capitalizeFirstLetter,
|
||||
KeyAction,
|
||||
Keymap,
|
||||
KeystrokeAction,
|
||||
Layer,
|
||||
LayerName,
|
||||
LongPressAction,
|
||||
MouseAction,
|
||||
MouseActionParam,
|
||||
PlayMacroAction,
|
||||
SwitchKeymapAction,
|
||||
SwitchLayerAction
|
||||
} from '../../../config-serializer/config-items/key-action';
|
||||
import { Keymap } from '../../../config-serializer/config-items/keymap';
|
||||
import { Layer } from '../../../config-serializer/config-items/layer';
|
||||
import { LongPressAction } from '../../../config-serializer/config-items/long-press-action';
|
||||
import { camelCaseToSentence, capitalizeFirstLetter } from 'uhk-common';
|
||||
} from 'uhk-common';
|
||||
|
||||
import { MapperService } from '../../../services/mapper.service';
|
||||
import { AppState } from '../../../store';
|
||||
import { KeymapActions } from '../../../store/actions';
|
||||
import { PopoverComponent } from '../../popover';
|
||||
import { KeyboardLayout } from '../../../keyboard/keyboard-layout.enum';
|
||||
|
||||
interface NameValuePair {
|
||||
name: string;
|
||||
@@ -54,6 +55,7 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges {
|
||||
@Input() popoverEnabled: boolean = true;
|
||||
@Input() tooltipEnabled: boolean = false;
|
||||
@Input() halvesSplit: boolean;
|
||||
@Input() keyboardLayout: KeyboardLayout.ANSI;
|
||||
|
||||
@ViewChild(PopoverComponent, { read: ElementRef }) popover: ElementRef;
|
||||
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
# 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 [user-config.json](user-config.json) for an example configuration.
|
||||
|
||||
The **TypeScript representation** is structurally similar to the JavaScript representation, but it features strongly typed TypeScript objects instead of typeless JavaScript objects. This representation is meant to be used by Agent. Extensive, per-property [assertion](assert.ts) takes place upon initializing the TypeScript objects to ensure the integrity of the configuration.
|
||||
|
||||
The **binary representation** is meant to be written to, and read from the EEPROM of the UHK. It's designed to be very compact in order to maximize the use of the 32kbyte EEPROM space.
|
||||
|
||||
## Configuration item types
|
||||
|
||||
Each configuration item belongs to a specific type. The following types are available:
|
||||
|
||||
**Primitive types** are integers of different sizes, and string. See [UhkBuffer](UhkBuffer.ts) which implements all the primitive types.
|
||||
|
||||
**Compound types** are composed of primitive types, and/or compound types. All compound types are saved into the [config-items](config-items) directory.
|
||||
|
||||
## Dumping serialization
|
||||
|
||||
The serialization of configuration items is a complicated business, and many things can go wrong. That's the exact reason why serialization can be dumped to ease debugging. All you have to do is to set `Serializable.enableDump` to `true`, and you'll see something like the following upon serialization actions:
|
||||
|
||||
```
|
||||
KeyActions.fromJsObject: [{"keyActionType":"none"},{"keyActionType":"keystroke","scancode":110},{"keyActionType":"keystrokeModifiers","modifierMask":33},{"keyActionType":"keystrokeWithM...
|
||||
NoneAction.fromJsObject: {"keyActionType":"none"} => <NoneAction>
|
||||
KeystrokeAction.fromJsObject: {"keyActionType":"keystroke","scancode":110} => <KeystrokeAction scancode="110">
|
||||
KeystrokeModifiersAction.fromJsObject: {"keyActionType":"keystrokeModifiers","modifierMask":33} => <KeystrokeModifiersAction modifierMask="33">
|
||||
KeystrokeWithModifiersAction.fromJsObject: {"keyActionType":"keystrokeWithModifiers","scancode":120,"modifierMask":16} => <KeystrokeWithModifiersAction scancode="120" modifierMask="16">
|
||||
SwitchLayerAction.fromJsObject: {"keyActionType":"switchLayer","layer":"fn","toggle":false} => <SwitchLayerAction layer="1" toggle="false">
|
||||
DualRoleKeystrokeAction.fromJsObject: {"keyActionType":"dualRoleKeystroke","scancode":111,"longPressAction":"mod"} => <DualRoleKeystrokeAction scancode="111" longPressAction="8">
|
||||
MouseAction.fromJsObject: {"keyActionType":"mouse","mouseAction":"scrollDown"} => <MouseAction mouseAction="8">
|
||||
PlayMacroAction.fromJsObject: {"keyActionType":"playMacro","macroId":0} => <PlayMacroAction macroId="0">
|
||||
SwitchKeymapAction.fromJsObject: {"keyActionType":"switchKeymap","keymapId":1} => <SwitchKeymapAction keymapId="1">
|
||||
KeyActions.toBinary: <KeyActions length="9"> => ['u8(9)]
|
||||
NoneAction.toBinary: <NoneAction> => ['u8(0)]
|
||||
KeystrokeAction.toBinary: <KeystrokeAction scancode="110"> => ['u8(1), u8(110)]
|
||||
KeystrokeModifiersAction.toBinary: <KeystrokeModifiersAction modifierMask="33"> => ['u8(2), u8(33)]
|
||||
KeystrokeWithModifiersAction.toBinary: <KeystrokeWithModifiersAction scancode="120" modifierMask="16"> => ['u8(3), u8(120), u8(16)]
|
||||
SwitchLayerAction.toBinary: <SwitchLayerAction layer="1" toggle="false"> => ['u8(5), u8(1)]
|
||||
DualRoleKeystrokeAction.toBinary: <DualRoleKeystrokeAction scancode="111" longPressAction="8"> => ['u8(4), u8(111), u8(8)]
|
||||
MouseAction.toBinary: <MouseAction mouseAction="8"> => ['u8(7), u8(8)]
|
||||
PlayMacroAction.toBinary: <PlayMacroAction macroId="0"> => ['u8(8), u8(0)]
|
||||
SwitchKeymapAction.toBinary: <SwitchKeymapAction keymapId="1"> => ['u8(6), u8(1)]
|
||||
KeyActions.fromBinary: [u8(9)]
|
||||
NoneAction.fromBinary: [u8(0)] => <NoneAction>
|
||||
KeystrokeAction.fromBinary: [u8(1), u8(110)] => <KeystrokeAction scancode="110">
|
||||
KeystrokeModifiersAction.fromBinary: [u8(2), u8(33)] => <KeystrokeModifiersAction modifierMask="33">
|
||||
KeystrokeWithModifiersAction.fromBinary: [u8(3), u8(120), u8(16)] => <KeystrokeWithModifiersAction scancode="120" modifierMask="16">
|
||||
SwitchLayerAction.fromBinary: [u8(5), u8(1)] => <SwitchLayerAction layer="1" toggle="false">
|
||||
DualRoleKeystrokeAction.fromBinary: [u8(4), u8(111), u8(8)] => <DualRoleKeystrokeAction scancode="111" longPressAction="8">
|
||||
MouseAction.fromBinary: [u8(7), u8(8)] => <MouseAction mouseAction="8">
|
||||
PlayMacroAction.fromBinary: [u8(8), u8(0)] => <PlayMacroAction macroId="0">
|
||||
SwitchKeymapAction.fromBinary: [u8(6), u8(1)] => <SwitchKeymapAction keymapId="1">
|
||||
KeyActions.toJsObject: <KeyActions length="9">
|
||||
NoneAction.toJsObject: <NoneAction> => {"keyActionType":"none"}
|
||||
KeystrokeAction.toJsObject: <KeystrokeAction scancode="110"> => {"keyActionType":"keystroke","scancode":110}
|
||||
KeystrokeModifiersAction.toJsObject: <KeystrokeModifiersAction modifierMask="33"> => {"keyActionType":"keystrokeModifiers","modifierMask":33}
|
||||
KeystrokeWithModifiersAction.toJsObject: <KeystrokeWithModifiersAction scancode="120" modifierMask="16"> => {"keyActionType":"keystrokeWithModifiers","scancode":120,"modifierMask":16}
|
||||
SwitchLayerAction.toJsObject: <SwitchLayerAction layer="1" toggle="false"> => {"keyActionType":"switchLayer","layer":"fn","toggle":false}
|
||||
DualRoleKeystrokeAction.toJsObject: <DualRoleKeystrokeAction scancode="111" longPressAction="8"> => {"keyActionType":"dualRoleKeystroke","scancode":111,"longPressAction":"mod"}
|
||||
MouseAction.toJsObject: <MouseAction mouseAction="8"> => {"keyActionType":"mouse","mouseAction":"scrollDown"}
|
||||
PlayMacroAction.toJsObject: <PlayMacroAction macroId="0"> => {"keyActionType":"playMacro","macroId":0}
|
||||
SwitchKeymapAction.toJsObject: <SwitchKeymapAction keymapId="1"> => {"keyActionType":"switchKeymap","keymapId":1}
|
||||
```
|
||||
|
||||
## Testing the serializer
|
||||
|
||||
[test-serializer.ts](test-serializer.ts) is designed to test the serializer by taking [user-config.json](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.
|
||||
```
|
||||
@@ -1,78 +0,0 @@
|
||||
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
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
import { assertUInt8, assertUInt32 } from '../assert';
|
||||
import { UhkBuffer } from '../uhk-buffer';
|
||||
|
||||
export class HardwareConfiguration {
|
||||
|
||||
signature: string;
|
||||
|
||||
@assertUInt8
|
||||
dataModelVersion: number;
|
||||
|
||||
@assertUInt8
|
||||
hardwareId: number;
|
||||
|
||||
@assertUInt8
|
||||
brandId: number;
|
||||
|
||||
@assertUInt32
|
||||
uuid: number;
|
||||
|
||||
isIso: boolean;
|
||||
|
||||
hasBacklighting: boolean;
|
||||
|
||||
fromJsonObject(jsonObject: any): HardwareConfiguration {
|
||||
this.signature = jsonObject.signature;
|
||||
this.dataModelVersion = jsonObject.dataModelVersion;
|
||||
this.hardwareId = jsonObject.hardwareId;
|
||||
this.brandId = jsonObject.brandId;
|
||||
this.uuid = jsonObject.uuid;
|
||||
this.isIso = jsonObject.isIso;
|
||||
this.hasBacklighting = jsonObject.hasBacklighting;
|
||||
return this;
|
||||
}
|
||||
|
||||
fromBinary(buffer: UhkBuffer): HardwareConfiguration {
|
||||
this.signature = buffer.readString();
|
||||
this.dataModelVersion = buffer.readUInt16();
|
||||
this.hardwareId = buffer.readUInt8();
|
||||
this.uuid = buffer.readUInt32();
|
||||
this.brandId = buffer.readUInt8();
|
||||
this.isIso = buffer.readBoolean();
|
||||
this.hasBacklighting = buffer.readBoolean();
|
||||
return this;
|
||||
}
|
||||
|
||||
toJsonObject(): any {
|
||||
return {
|
||||
signature: this.signature,
|
||||
dataModelVersion: this.dataModelVersion,
|
||||
hardwareId: this.hardwareId,
|
||||
brandId: this.brandId,
|
||||
uuid: this.uuid,
|
||||
isIso: this.isIso,
|
||||
hasBacklighting: this.hasBacklighting
|
||||
};
|
||||
}
|
||||
|
||||
toBinary(buffer: UhkBuffer): void {
|
||||
buffer.writeString(this.signature);
|
||||
buffer.writeUInt16(this.dataModelVersion);
|
||||
buffer.writeUInt8(this.hardwareId);
|
||||
buffer.writeUInt8(this.brandId);
|
||||
buffer.writeUInt32(this.uuid);
|
||||
buffer.writeBoolean(this.isIso);
|
||||
buffer.writeBoolean(this.hasBacklighting);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<HardwareConfiguration signature="${this.signature}">`;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
import { UhkBuffer } from '../../uhk-buffer';
|
||||
|
||||
import { Macro } from '../macro';
|
||||
import { KeyAction, KeyActionId, keyActionType } from './key-action';
|
||||
import { KeystrokeAction } from './keystroke-action';
|
||||
import { SwitchLayerAction } from './switch-layer-action';
|
||||
import { SwitchKeymapAction, UnresolvedSwitchKeymapAction } from './switch-keymap-action';
|
||||
import { MouseAction } from './mouse-action';
|
||||
import { PlayMacroAction } from './play-macro-action';
|
||||
|
||||
export class Helper {
|
||||
|
||||
static createKeyAction(source: KeyAction | UhkBuffer | any, macros?: Macro[]): KeyAction {
|
||||
if (source instanceof KeyAction) {
|
||||
return Helper.fromKeyAction(source);
|
||||
} else if (source instanceof UhkBuffer) {
|
||||
return Helper.fromUhkBuffer(source, macros);
|
||||
} else {
|
||||
return Helper.fromJSONObject(source, macros);
|
||||
}
|
||||
}
|
||||
|
||||
private static fromUhkBuffer(buffer: UhkBuffer, macros: Macro[]): KeyAction {
|
||||
const keyActionFirstByte = buffer.readUInt8();
|
||||
buffer.backtrack();
|
||||
|
||||
if (keyActionFirstByte >= KeyActionId.KeystrokeAction && keyActionFirstByte < KeyActionId.LastKeystrokeAction) {
|
||||
return new KeystrokeAction().fromBinary(buffer);
|
||||
}
|
||||
|
||||
switch (keyActionFirstByte) {
|
||||
case KeyActionId.NoneAction:
|
||||
buffer.readUInt8(); // Read type just to skip it
|
||||
return undefined;
|
||||
case KeyActionId.SwitchLayerAction:
|
||||
return new SwitchLayerAction().fromBinary(buffer);
|
||||
case KeyActionId.SwitchKeymapAction:
|
||||
return new UnresolvedSwitchKeymapAction().fromBinary(buffer);
|
||||
case KeyActionId.MouseAction:
|
||||
return new MouseAction().fromBinary(buffer);
|
||||
case KeyActionId.PlayMacroAction:
|
||||
return new PlayMacroAction().fromBinary(buffer, macros);
|
||||
default:
|
||||
throw `Invalid KeyAction first byte: ${keyActionFirstByte}`;
|
||||
}
|
||||
}
|
||||
|
||||
private static fromKeyAction(keyAction: KeyAction): KeyAction {
|
||||
let newKeyAction: KeyAction;
|
||||
if (keyAction instanceof KeystrokeAction) {
|
||||
newKeyAction = new KeystrokeAction(keyAction);
|
||||
} else if (keyAction instanceof SwitchLayerAction) {
|
||||
newKeyAction = new SwitchLayerAction(keyAction);
|
||||
} else if (keyAction instanceof SwitchKeymapAction) {
|
||||
newKeyAction = new SwitchKeymapAction(keyAction);
|
||||
} else if (keyAction instanceof MouseAction) {
|
||||
newKeyAction = new MouseAction(keyAction);
|
||||
} else if (keyAction instanceof PlayMacroAction) {
|
||||
newKeyAction = new PlayMacroAction(keyAction);
|
||||
}
|
||||
return newKeyAction;
|
||||
}
|
||||
|
||||
private static fromJSONObject(keyAction: any, macros: Macro[]): KeyAction {
|
||||
if (!keyAction) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (keyAction.keyActionType) {
|
||||
case keyActionType.KeystrokeAction:
|
||||
return new KeystrokeAction().fromJsonObject(keyAction);
|
||||
case keyActionType.SwitchLayerAction:
|
||||
return new SwitchLayerAction().fromJsonObject(keyAction);
|
||||
case keyActionType.SwitchKeymapAction:
|
||||
return new SwitchKeymapAction().fromJsonObject(keyAction);
|
||||
case keyActionType.MouseAction:
|
||||
return new MouseAction().fromJsonObject(keyAction);
|
||||
case keyActionType.PlayMacroAction:
|
||||
return new PlayMacroAction().fromJsonObject(keyAction, macros);
|
||||
default:
|
||||
throw `Invalid KeyAction.keyActionType: "${keyAction.keyActionType}"`;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
export * from './key-action';
|
||||
export * from './keystroke-action';
|
||||
export * from './mouse-action';
|
||||
export * from './none-action';
|
||||
export * from './play-macro-action';
|
||||
export * from './switch-keymap-action';
|
||||
export * from './switch-layer-action';
|
||||
export * from './helper';
|
||||
@@ -1,65 +0,0 @@
|
||||
import { Macro } from '../macro';
|
||||
import { UhkBuffer } from '../../uhk-buffer';
|
||||
import { UserConfiguration } from '../user-configuration';
|
||||
|
||||
export enum KeyActionId {
|
||||
NoneAction = 0,
|
||||
KeystrokeAction = 1,
|
||||
/*
|
||||
1 - 31 are reserved for KeystrokeAction
|
||||
5 bits:
|
||||
1: Do we have scancode?
|
||||
2: Do we have modifiers?
|
||||
3: Do we have longpress?
|
||||
4-5: What kind of keystroke? (basic, short/long media, system)
|
||||
*/
|
||||
LastKeystrokeAction = 31, // TODO: remove this after refactoring the keyActionId check
|
||||
SwitchLayerAction = 32,
|
||||
SwitchKeymapAction = 33,
|
||||
MouseAction = 34,
|
||||
PlayMacroAction = 35
|
||||
}
|
||||
|
||||
export let keyActionType = {
|
||||
NoneAction : 'none',
|
||||
KeystrokeAction : 'keystroke',
|
||||
SwitchLayerAction : 'switchLayer',
|
||||
SwitchKeymapAction : 'switchKeymap',
|
||||
MouseAction : 'mouse',
|
||||
PlayMacroAction : 'playMacro'
|
||||
};
|
||||
|
||||
export abstract class KeyAction {
|
||||
|
||||
assertKeyActionType(jsObject: any): void {
|
||||
const keyActionClassname: string = this.getName();
|
||||
const keyActionTypeString: string = keyActionType[keyActionClassname];
|
||||
if (jsObject.keyActionType !== keyActionTypeString) {
|
||||
throw `Invalid ${keyActionClassname}.keyActionType: ${jsObject.keyActionType}`;
|
||||
}
|
||||
}
|
||||
|
||||
readAndAssertKeyActionId(buffer: UhkBuffer): KeyActionId {
|
||||
const classname: string = this.getName();
|
||||
const readKeyActionId: number = buffer.readUInt8();
|
||||
const keyActionId: number = KeyActionId[classname];
|
||||
if (keyActionId === KeyActionId.KeystrokeAction) {
|
||||
if (readKeyActionId < KeyActionId.KeystrokeAction || readKeyActionId > KeyActionId.LastKeystrokeAction) {
|
||||
throw `Invalid ${classname} first byte: ${readKeyActionId}`;
|
||||
}
|
||||
} else if (readKeyActionId !== keyActionId) {
|
||||
throw `Invalid ${classname} first byte: ${readKeyActionId}`;
|
||||
}
|
||||
return readKeyActionId;
|
||||
}
|
||||
|
||||
abstract toJsonObject(macros?: Macro[]): any;
|
||||
|
||||
abstract toBinary(buffer: UhkBuffer, userConfiguration?: UserConfiguration): void;
|
||||
|
||||
abstract getName(): string;
|
||||
|
||||
renameKeymap(oldAbbr: string, newAbbr: string): KeyAction {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -1,215 +0,0 @@
|
||||
import { assertEnum, assertUInt8 } from '../../assert';
|
||||
import { UhkBuffer } from '../../uhk-buffer';
|
||||
import { KeyModifiers } from '../key-modifiers';
|
||||
import { LongPressAction } from '../long-press-action';
|
||||
import { KeyAction, KeyActionId, keyActionType } from './key-action';
|
||||
import { KeystrokeType } from './keystroke-type';
|
||||
|
||||
export enum KeystrokeActionFlag {
|
||||
scancode = 1 << 0,
|
||||
modifierMask = 1 << 1,
|
||||
longPressAction = 1 << 2
|
||||
}
|
||||
|
||||
const KEYSTROKE_ACTION_FLAG_LENGTH = 3;
|
||||
|
||||
interface JsonObjectKeystrokeAction {
|
||||
keyActionType: string;
|
||||
scancode?: number;
|
||||
modifierMask?: number;
|
||||
longPressAction?: string;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
const MODIFIERS = ['LCtrl', 'LShift', 'LAlt', 'LSuper', 'RCtrl', 'RShift', 'RAlt', 'RSuper'];
|
||||
|
||||
export class KeystrokeAction extends KeyAction {
|
||||
|
||||
set scancode(scancode: number) {
|
||||
this._scancode = scancode;
|
||||
if (this.type !== KeystrokeType.shortMedia && this.type !== KeystrokeType.longMedia) {
|
||||
return;
|
||||
}
|
||||
this.type = scancode < 256 ? KeystrokeType.shortMedia : KeystrokeType.longMedia;
|
||||
}
|
||||
|
||||
get scancode() {
|
||||
return this._scancode;
|
||||
}
|
||||
|
||||
@assertUInt8
|
||||
modifierMask: number;
|
||||
|
||||
@assertEnum(LongPressAction)
|
||||
longPressAction: LongPressAction;
|
||||
|
||||
set type(type: KeystrokeType) {
|
||||
if (type === KeystrokeType.shortMedia || type === KeystrokeType.longMedia) {
|
||||
type = this.scancode < 256 ? KeystrokeType.shortMedia : KeystrokeType.longMedia;
|
||||
}
|
||||
this._type = type;
|
||||
}
|
||||
|
||||
get type() {
|
||||
return this._type;
|
||||
}
|
||||
|
||||
private _scancode: number;
|
||||
|
||||
@assertEnum(KeystrokeType)
|
||||
private _type: KeystrokeType;
|
||||
|
||||
constructor(other?: KeystrokeAction) {
|
||||
super();
|
||||
if (!other) {
|
||||
return;
|
||||
}
|
||||
this.type = other.type;
|
||||
this._scancode = other._scancode;
|
||||
this.modifierMask = other.modifierMask;
|
||||
this.longPressAction = other.longPressAction;
|
||||
}
|
||||
|
||||
fromJsonObject(jsonObject: JsonObjectKeystrokeAction): KeystrokeAction {
|
||||
this.assertKeyActionType(jsonObject);
|
||||
if (jsonObject.type === 'media') {
|
||||
this.type = jsonObject.scancode < 256 ? KeystrokeType.shortMedia : KeystrokeType.longMedia;
|
||||
} else {
|
||||
this.type = KeystrokeType[jsonObject.type];
|
||||
}
|
||||
this._scancode = jsonObject.scancode;
|
||||
this.modifierMask = jsonObject.modifierMask;
|
||||
this.longPressAction = LongPressAction[jsonObject.longPressAction];
|
||||
return this;
|
||||
}
|
||||
|
||||
fromBinary(buffer: UhkBuffer): KeystrokeAction {
|
||||
const keyActionId: KeyActionId = this.readAndAssertKeyActionId(buffer);
|
||||
const flags: number = keyActionId - KeyActionId.NoneAction; // NoneAction is the same as an empty KeystrokeAction.
|
||||
this.type = (flags >> 3) & 0b11;
|
||||
if (flags & KeystrokeActionFlag.scancode) {
|
||||
this._scancode = this.type === KeystrokeType.longMedia ? buffer.readUInt16() : buffer.readUInt8();
|
||||
}
|
||||
if (flags & KeystrokeActionFlag.modifierMask) {
|
||||
this.modifierMask = buffer.readUInt8();
|
||||
}
|
||||
if (flags & KeystrokeActionFlag.longPressAction) {
|
||||
this.longPressAction = buffer.readUInt8();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
toJsonObject(): JsonObjectKeystrokeAction {
|
||||
const jsonObject: JsonObjectKeystrokeAction = {
|
||||
keyActionType: keyActionType.KeystrokeAction
|
||||
};
|
||||
|
||||
if (this.type === KeystrokeType.shortMedia || this.type === KeystrokeType.longMedia) {
|
||||
jsonObject.type = 'media';
|
||||
} else {
|
||||
jsonObject.type = KeystrokeType[this.type];
|
||||
}
|
||||
|
||||
if (this.hasScancode()) {
|
||||
jsonObject.scancode = this._scancode;
|
||||
}
|
||||
|
||||
if (this.hasActiveModifier()) {
|
||||
jsonObject.modifierMask = this.modifierMask;
|
||||
}
|
||||
|
||||
if (this.hasLongPressAction()) {
|
||||
jsonObject.longPressAction = LongPressAction[this.longPressAction];
|
||||
}
|
||||
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
toBinary(buffer: UhkBuffer) {
|
||||
let flags = 0;
|
||||
const toWrite: {
|
||||
data: number,
|
||||
long: boolean
|
||||
}[] = [];
|
||||
|
||||
if (this.hasScancode()) {
|
||||
flags |= KeystrokeActionFlag.scancode;
|
||||
toWrite.push({ data: this._scancode, long: this.type === KeystrokeType.longMedia });
|
||||
}
|
||||
|
||||
if (this.hasActiveModifier()) {
|
||||
flags |= KeystrokeActionFlag.modifierMask;
|
||||
toWrite.push({ data: this.modifierMask, long: false });
|
||||
}
|
||||
|
||||
if (this.hasLongPressAction()) {
|
||||
flags |= KeystrokeActionFlag.longPressAction;
|
||||
toWrite.push({ data: this.longPressAction, long: false });
|
||||
}
|
||||
|
||||
const TYPE_OFFSET = flags + (this.type << KEYSTROKE_ACTION_FLAG_LENGTH);
|
||||
|
||||
buffer.writeUInt8(KeyActionId.NoneAction + TYPE_OFFSET); // NoneAction is the same as an empty KeystrokeAction.
|
||||
|
||||
for (let i = 0; i < toWrite.length; ++i) {
|
||||
if (toWrite[i].long) {
|
||||
buffer.writeUInt16(toWrite[i].data);
|
||||
} else {
|
||||
buffer.writeUInt8(toWrite[i].data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
const properties: string[] = [];
|
||||
properties.push(`type="${KeystrokeType[this.type]}"`);
|
||||
|
||||
if (this.hasScancode()) {
|
||||
properties.push(`scancode="${this._scancode}"`);
|
||||
}
|
||||
if (this.hasActiveModifier()) {
|
||||
properties.push(`modifierMask="${this.modifierMask}"`);
|
||||
}
|
||||
if (this.hasLongPressAction()) {
|
||||
properties.push(`longPressAction="${this.longPressAction}"`);
|
||||
}
|
||||
|
||||
return `<KeystrokeAction ${properties.join(' ')}>`;
|
||||
}
|
||||
|
||||
isActive(modifier: KeyModifiers): boolean {
|
||||
return (this.modifierMask & modifier) > 0;
|
||||
}
|
||||
|
||||
hasActiveModifier(): boolean {
|
||||
return this.modifierMask > 0;
|
||||
}
|
||||
|
||||
hasLongPressAction(): boolean {
|
||||
return this.longPressAction !== undefined;
|
||||
}
|
||||
|
||||
hasScancode(): boolean {
|
||||
return !!this._scancode;
|
||||
}
|
||||
|
||||
hasOnlyOneActiveModifier(): boolean {
|
||||
return this.modifierMask !== 0 && !(this.modifierMask & this.modifierMask - 1);
|
||||
}
|
||||
|
||||
getModifierList(): string[] {
|
||||
const modifierList: string[] = [];
|
||||
let modifierMask = this.modifierMask;
|
||||
for (let i = 0; modifierMask !== 0; ++i, modifierMask >>= 1) {
|
||||
if (modifierMask & 1) {
|
||||
modifierList.push(MODIFIERS[i]);
|
||||
}
|
||||
}
|
||||
return modifierList;
|
||||
}
|
||||
|
||||
public getName(): string {
|
||||
return 'KeystrokeAction';
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
export enum KeystrokeType {
|
||||
basic,
|
||||
shortMedia,
|
||||
longMedia,
|
||||
system
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
import { assertEnum } from '../../assert';
|
||||
import { UhkBuffer } from '../../uhk-buffer';
|
||||
import { KeyAction, KeyActionId, keyActionType } from './key-action';
|
||||
|
||||
export enum MouseActionParam {
|
||||
leftClick,
|
||||
middleClick,
|
||||
rightClick,
|
||||
moveUp,
|
||||
moveDown,
|
||||
moveLeft,
|
||||
moveRight,
|
||||
scrollUp,
|
||||
scrollDown,
|
||||
scrollLeft,
|
||||
scrollRight,
|
||||
accelerate,
|
||||
decelerate
|
||||
}
|
||||
|
||||
export class MouseAction extends KeyAction {
|
||||
|
||||
@assertEnum(MouseActionParam)
|
||||
mouseAction: MouseActionParam;
|
||||
|
||||
constructor(other?: MouseAction) {
|
||||
super();
|
||||
if (!other) {
|
||||
return;
|
||||
}
|
||||
this.mouseAction = other.mouseAction;
|
||||
}
|
||||
|
||||
fromJsonObject(jsObject: any): MouseAction {
|
||||
this.assertKeyActionType(jsObject);
|
||||
this.mouseAction = MouseActionParam[<string>jsObject.mouseAction];
|
||||
return this;
|
||||
}
|
||||
|
||||
fromBinary(buffer: UhkBuffer): MouseAction {
|
||||
this.readAndAssertKeyActionId(buffer);
|
||||
this.mouseAction = buffer.readUInt8();
|
||||
return this;
|
||||
}
|
||||
|
||||
toJsonObject(): any {
|
||||
return {
|
||||
keyActionType: keyActionType.MouseAction,
|
||||
mouseAction: MouseActionParam[this.mouseAction]
|
||||
};
|
||||
}
|
||||
|
||||
toBinary(buffer: UhkBuffer) {
|
||||
buffer.writeUInt8(KeyActionId.MouseAction);
|
||||
buffer.writeUInt8(this.mouseAction);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<MouseAction mouseAction="${this.mouseAction}">`;
|
||||
}
|
||||
|
||||
public getName(): string {
|
||||
return 'MouseAction';
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
import { UhkBuffer } from '../../uhk-buffer';
|
||||
import { KeyAction, KeyActionId, keyActionType } from './key-action';
|
||||
|
||||
/**
|
||||
* NoneAction is only intended for binary serialization of undefined key actions
|
||||
* DO NOT use it as a real KeyAction
|
||||
*
|
||||
*/
|
||||
|
||||
export class NoneAction extends KeyAction {
|
||||
|
||||
fromJsonObject(jsonObject: any): NoneAction {
|
||||
this.assertKeyActionType(jsonObject);
|
||||
return this;
|
||||
}
|
||||
|
||||
fromBinary(buffer: UhkBuffer): NoneAction {
|
||||
this.readAndAssertKeyActionId(buffer);
|
||||
return this;
|
||||
}
|
||||
|
||||
toJsonObject(): any {
|
||||
return {
|
||||
keyActionType: keyActionType.NoneAction
|
||||
};
|
||||
}
|
||||
|
||||
toBinary(buffer: UhkBuffer) {
|
||||
buffer.writeUInt8(KeyActionId.NoneAction);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return '<NoneAction>';
|
||||
}
|
||||
|
||||
public getName(): string {
|
||||
return 'NoneAction';
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
import { assertUInt8 } from '../../assert';
|
||||
import { UhkBuffer } from '../../uhk-buffer';
|
||||
import { Macro } from '../macro';
|
||||
import { KeyAction, KeyActionId, keyActionType } from './key-action';
|
||||
import { UserConfiguration } from '../user-configuration';
|
||||
|
||||
export class PlayMacroAction extends KeyAction {
|
||||
|
||||
@assertUInt8
|
||||
macroId: number;
|
||||
|
||||
constructor(parameter?: PlayMacroAction | Macro) {
|
||||
super();
|
||||
if (!parameter) {
|
||||
return;
|
||||
}
|
||||
if (parameter instanceof PlayMacroAction) {
|
||||
this.macroId = parameter.macroId;
|
||||
} else {
|
||||
this.macroId = parameter.id;
|
||||
}
|
||||
}
|
||||
|
||||
fromJsonObject(jsonObject: any, macros: Macro[]): PlayMacroAction {
|
||||
this.assertKeyActionType(jsonObject);
|
||||
this.macroId = macros[jsonObject.macroIndex].id;
|
||||
return this;
|
||||
}
|
||||
|
||||
fromBinary(buffer: UhkBuffer, macros: Macro[]): PlayMacroAction {
|
||||
this.readAndAssertKeyActionId(buffer);
|
||||
const macroIndex = buffer.readUInt8();
|
||||
this.macroId = macros[macroIndex].id;
|
||||
return this;
|
||||
}
|
||||
|
||||
toJsonObject(macros: Macro[]): any {
|
||||
return {
|
||||
keyActionType: keyActionType.PlayMacroAction,
|
||||
macroIndex: macros.findIndex(macro => macro.id === this.macroId)
|
||||
};
|
||||
}
|
||||
|
||||
toBinary(buffer: UhkBuffer, userConfiguration: UserConfiguration) {
|
||||
buffer.writeUInt8(KeyActionId.PlayMacroAction);
|
||||
buffer.writeUInt8(userConfiguration.macros.findIndex(macro => macro.id === this.macroId));
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<PlayMacroAction macroId="${this.macroId}">`;
|
||||
}
|
||||
|
||||
public getName(): string {
|
||||
return 'PlayMacroAction';
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
import { assertUInt8 } from '../../assert';
|
||||
import { UhkBuffer } from '../../uhk-buffer';
|
||||
import { Keymap } from '../keymap';
|
||||
import { KeyAction, KeyActionId, keyActionType } from './key-action';
|
||||
import { UserConfiguration } from '../user-configuration';
|
||||
|
||||
export class SwitchKeymapAction extends KeyAction {
|
||||
|
||||
keymapAbbreviation: string;
|
||||
|
||||
constructor(parameter?: SwitchKeymapAction | Keymap | string) {
|
||||
super();
|
||||
if (!parameter) {
|
||||
return;
|
||||
}
|
||||
if (parameter instanceof SwitchKeymapAction) {
|
||||
this.keymapAbbreviation = parameter.keymapAbbreviation;
|
||||
} else if (parameter instanceof Keymap) {
|
||||
this.keymapAbbreviation = parameter.abbreviation;
|
||||
} else {
|
||||
this.keymapAbbreviation = parameter;
|
||||
}
|
||||
}
|
||||
|
||||
fromJsonObject(jsonObject: any): SwitchKeymapAction {
|
||||
this.assertKeyActionType(jsonObject);
|
||||
this.keymapAbbreviation = jsonObject.keymapAbbreviation;
|
||||
return this;
|
||||
}
|
||||
|
||||
toJsonObject(): any {
|
||||
return {
|
||||
keyActionType: keyActionType.SwitchKeymapAction,
|
||||
keymapAbbreviation: this.keymapAbbreviation
|
||||
};
|
||||
}
|
||||
|
||||
toBinary(buffer: UhkBuffer, userConfiguration: UserConfiguration): void {
|
||||
const keymapIndex = userConfiguration.keymaps.findIndex(keymap => keymap.abbreviation === this.keymapAbbreviation);
|
||||
buffer.writeUInt8(KeyActionId.SwitchKeymapAction);
|
||||
buffer.writeUInt8(keymapIndex);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<SwitchKeymapAction keymapAbbreviation="${this.keymapAbbreviation}">`;
|
||||
}
|
||||
|
||||
renameKeymap(oldAbbr: string, newAbbr: string): KeyAction {
|
||||
if (this.keymapAbbreviation !== oldAbbr) {
|
||||
return this;
|
||||
}
|
||||
return new SwitchKeymapAction(newAbbr);
|
||||
}
|
||||
|
||||
public getName(): string {
|
||||
return 'SwitchKeymapAction';
|
||||
}
|
||||
}
|
||||
|
||||
export class UnresolvedSwitchKeymapAction extends KeyAction {
|
||||
|
||||
@assertUInt8
|
||||
keymapIndex: number;
|
||||
|
||||
constructor(keymapIndex?: number) {
|
||||
super();
|
||||
this.keymapIndex = keymapIndex;
|
||||
}
|
||||
|
||||
fromBinary(buffer: UhkBuffer): UnresolvedSwitchKeymapAction {
|
||||
buffer.readUInt8(); // Skip key action id
|
||||
this.keymapIndex = buffer.readUInt8();
|
||||
return this;
|
||||
}
|
||||
|
||||
toBinary(buffer: UhkBuffer) {
|
||||
buffer.writeUInt8(KeyActionId.SwitchKeymapAction);
|
||||
buffer.writeUInt8(this.keymapIndex);
|
||||
}
|
||||
|
||||
toJsonObject(): any {
|
||||
throw new Error('UnresolvedSwitchKeymapAction cannot be serialized directly. Convert it to SwitchKeymapAction first.');
|
||||
}
|
||||
|
||||
resolve(keymaps: Keymap[]): SwitchKeymapAction {
|
||||
return new SwitchKeymapAction(keymaps[this.keymapIndex]);
|
||||
}
|
||||
|
||||
public getName(): string {
|
||||
return 'UnresolvedSwitchKeymapAction';
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
import { assertEnum } from '../../assert';
|
||||
import { UhkBuffer } from '../../uhk-buffer';
|
||||
import { KeyAction, KeyActionId, keyActionType } from './key-action';
|
||||
|
||||
export enum LayerName {
|
||||
mod,
|
||||
fn,
|
||||
mouse
|
||||
}
|
||||
|
||||
export class SwitchLayerAction extends KeyAction {
|
||||
|
||||
isLayerToggleable: boolean;
|
||||
|
||||
@assertEnum(LayerName)
|
||||
layer: LayerName;
|
||||
|
||||
constructor(other?: SwitchLayerAction) {
|
||||
super();
|
||||
if (!other) {
|
||||
return;
|
||||
}
|
||||
this.isLayerToggleable = other.isLayerToggleable;
|
||||
this.layer = other.layer;
|
||||
}
|
||||
|
||||
fromJsonObject(jsonObject: any): SwitchLayerAction {
|
||||
this.assertKeyActionType(jsonObject);
|
||||
this.layer = LayerName[<string>jsonObject.layer];
|
||||
this.isLayerToggleable = jsonObject.toggle;
|
||||
return this;
|
||||
}
|
||||
|
||||
fromBinary(buffer: UhkBuffer): SwitchLayerAction {
|
||||
this.readAndAssertKeyActionId(buffer);
|
||||
this.layer = buffer.readUInt8();
|
||||
this.isLayerToggleable = buffer.readBoolean();
|
||||
return this;
|
||||
}
|
||||
|
||||
toJsonObject(): any {
|
||||
return {
|
||||
keyActionType: keyActionType.SwitchLayerAction,
|
||||
layer: LayerName[this.layer],
|
||||
toggle: this.isLayerToggleable
|
||||
};
|
||||
}
|
||||
|
||||
toBinary(buffer: UhkBuffer) {
|
||||
buffer.writeUInt8(KeyActionId.SwitchLayerAction);
|
||||
buffer.writeUInt8(this.layer);
|
||||
buffer.writeBoolean(this.isLayerToggleable);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<SwitchLayerAction layer="${this.layer}" toggle="${this.isLayerToggleable}">`;
|
||||
}
|
||||
|
||||
public getName(): string {
|
||||
return 'SwitchLayerAction';
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
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
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
import { UhkBuffer } from '../uhk-buffer';
|
||||
import { Layer } from './layer';
|
||||
import { Macro } from './macro';
|
||||
import { SwitchLayerAction } from './key-action/switch-layer-action';
|
||||
import { KeyAction } from './key-action/key-action';
|
||||
import { ConfigSerializer } from '../config-serializer';
|
||||
import { UserConfiguration } from './user-configuration';
|
||||
|
||||
export class Keymap {
|
||||
|
||||
name: string;
|
||||
|
||||
description: string;
|
||||
|
||||
abbreviation: string;
|
||||
|
||||
isDefault: boolean;
|
||||
|
||||
layers: Layer[];
|
||||
|
||||
constructor(keymap?: Keymap) {
|
||||
if (!keymap) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.name = keymap.name;
|
||||
this.description = keymap.description;
|
||||
this.abbreviation = keymap.abbreviation;
|
||||
this.isDefault = keymap.isDefault;
|
||||
this.layers = keymap.layers.map(layer => new Layer(layer));
|
||||
}
|
||||
|
||||
fromJsonObject(jsonObject: any, macros?: Macro[]): Keymap {
|
||||
this.isDefault = jsonObject.isDefault;
|
||||
this.abbreviation = jsonObject.abbreviation;
|
||||
this.name = jsonObject.name;
|
||||
this.description = jsonObject.description;
|
||||
this.layers = jsonObject.layers.map((layer: any) => new Layer().fromJsonObject(layer, macros));
|
||||
this.normalize();
|
||||
return this;
|
||||
}
|
||||
|
||||
fromBinary(buffer: UhkBuffer, macros?: Macro[]): Keymap {
|
||||
this.abbreviation = buffer.readString();
|
||||
this.isDefault = buffer.readBoolean();
|
||||
this.name = buffer.readString();
|
||||
this.description = buffer.readString();
|
||||
this.layers = buffer.readArray<Layer>(uhkBuffer => {
|
||||
return new Layer().fromBinary(uhkBuffer, macros);
|
||||
});
|
||||
this.normalize();
|
||||
return this;
|
||||
}
|
||||
|
||||
toJsonObject(macros?: Macro[]): any {
|
||||
return {
|
||||
isDefault: this.isDefault,
|
||||
abbreviation: this.abbreviation,
|
||||
name: this.name,
|
||||
description: this.description,
|
||||
layers: this.layers.map(layer => layer.toJsonObject(macros))
|
||||
};
|
||||
}
|
||||
|
||||
toBinary(buffer: UhkBuffer, userConfiguration: UserConfiguration): void {
|
||||
buffer.writeString(this.abbreviation);
|
||||
buffer.writeBoolean(this.isDefault);
|
||||
buffer.writeString(this.name);
|
||||
buffer.writeString(this.description);
|
||||
buffer.writeArray(this.layers, (uhkBuffer: UhkBuffer, layer: Layer) => {
|
||||
layer.toBinary(uhkBuffer, userConfiguration);
|
||||
});
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<Keymap abbreviation="${this.abbreviation}" name="${this.name}">`;
|
||||
}
|
||||
|
||||
renameKeymap(oldAbbr: string, newAbbr: string): Keymap {
|
||||
let layers: Layer[];
|
||||
let layerModified = false;
|
||||
this.layers.forEach((layer, index) => {
|
||||
const newLayer = layer.renameKeymap(oldAbbr, newAbbr);
|
||||
if (newLayer !== layer) {
|
||||
if (!layerModified) {
|
||||
layers = this.layers.slice();
|
||||
layerModified = true;
|
||||
}
|
||||
layers[index] = newLayer;
|
||||
}
|
||||
});
|
||||
if (layerModified) {
|
||||
const newKeymap = Object.assign(new Keymap(), this);
|
||||
newKeymap.layers = layers;
|
||||
return newKeymap;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private normalize() {
|
||||
// Removes all the SwitchLayerActions from any non base layer
|
||||
for (let i = 1; i < this.layers.length; ++i) {
|
||||
for (const module of this.layers[i].modules) {
|
||||
module.keyActions = module.keyActions.map(keyAction => {
|
||||
if (keyAction instanceof SwitchLayerAction) {
|
||||
return undefined;
|
||||
}
|
||||
return keyAction;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Adds the SwitchLayerActions from the base layer to any none base layer
|
||||
const baseLayerModules = this.layers[0].modules;
|
||||
for (let i = 0; i < baseLayerModules.length; ++i) {
|
||||
baseLayerModules[i].keyActions.forEach((keyAction: KeyAction, keyActionIndex: number) => {
|
||||
if (keyAction instanceof SwitchLayerAction) {
|
||||
for (let j = 1; j < this.layers.length; ++j) {
|
||||
this.layers[j].modules[i].keyActions[keyActionIndex] = new SwitchLayerAction(keyAction);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
import { UhkBuffer } from '../uhk-buffer';
|
||||
import { Macro } from './macro';
|
||||
import { Module } from './module';
|
||||
import { UserConfiguration } from './user-configuration';
|
||||
import { ConfigSerializer } from '../config-serializer';
|
||||
|
||||
export class Layer {
|
||||
|
||||
modules: Module[];
|
||||
|
||||
constructor(layers?: Layer) {
|
||||
if (!layers) {
|
||||
return;
|
||||
}
|
||||
this.modules = layers.modules.map(module => new Module(module));
|
||||
}
|
||||
|
||||
fromJsonObject(jsonObject: any, macros?: Macro[]): Layer {
|
||||
this.modules = jsonObject.modules.map((module: any) => new Module().fromJsonObject(module, macros));
|
||||
return this;
|
||||
}
|
||||
|
||||
fromBinary(buffer: UhkBuffer, macros?: Macro[]): Layer {
|
||||
this.modules = buffer.readArray<Module>(uhkBuffer => {
|
||||
return new Module().fromBinary(uhkBuffer, macros);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
toJsonObject(macros?: Macro[]): any {
|
||||
return {
|
||||
modules: this.modules.map(module => module.toJsonObject(macros))
|
||||
};
|
||||
}
|
||||
|
||||
toBinary(buffer: UhkBuffer, userConfiguration: UserConfiguration): void {
|
||||
buffer.writeArray(this.modules, (uhkBuffer: UhkBuffer, module: Module) => {
|
||||
module.toBinary(uhkBuffer, userConfiguration);
|
||||
});
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<Layer>`;
|
||||
}
|
||||
|
||||
renameKeymap(oldAbbr: string, newAbbr: string): Layer {
|
||||
let modules: Module[];
|
||||
let moduleModified = false;
|
||||
this.modules.forEach((module, index) => {
|
||||
const newModule = module.renameKeymap(oldAbbr, newAbbr);
|
||||
if (newModule !== module) {
|
||||
if (!moduleModified) {
|
||||
modules = this.modules.slice();
|
||||
moduleModified = true;
|
||||
}
|
||||
modules[index] = newModule;
|
||||
}
|
||||
});
|
||||
if (moduleModified) {
|
||||
const newLayer = Object.assign(new Layer(), this);
|
||||
newLayer.modules = modules;
|
||||
return newLayer;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
export enum LongPressAction {
|
||||
leftCtrl,
|
||||
leftShift,
|
||||
leftAlt,
|
||||
leftSuper,
|
||||
rightCtrl,
|
||||
rightShift,
|
||||
rightAlt,
|
||||
rightSuper,
|
||||
mod,
|
||||
fn,
|
||||
mouse
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
import { assertUInt16 } from '../../assert';
|
||||
import { UhkBuffer } from '../../uhk-buffer';
|
||||
import { MacroAction, MacroActionId, macroActionType } from './macro-action';
|
||||
|
||||
export class DelayMacroAction extends MacroAction {
|
||||
|
||||
@assertUInt16
|
||||
delay: number;
|
||||
|
||||
constructor(other?: DelayMacroAction) {
|
||||
super();
|
||||
if (!other) {
|
||||
return;
|
||||
}
|
||||
this.delay = other.delay;
|
||||
}
|
||||
|
||||
fromJsonObject(jsObject: any): DelayMacroAction {
|
||||
this.assertMacroActionType(jsObject);
|
||||
this.delay = jsObject.delay;
|
||||
return this;
|
||||
}
|
||||
|
||||
fromBinary(buffer: UhkBuffer): DelayMacroAction {
|
||||
this.readAndAssertMacroActionId(buffer);
|
||||
this.delay = buffer.readUInt16();
|
||||
return this;
|
||||
}
|
||||
|
||||
toJsonObject(): any {
|
||||
return {
|
||||
macroActionType: macroActionType.DelayMacroAction,
|
||||
delay: this.delay
|
||||
};
|
||||
}
|
||||
|
||||
toBinary(buffer: UhkBuffer) {
|
||||
buffer.writeUInt8(MacroActionId.DelayMacroAction);
|
||||
buffer.writeUInt16(this.delay);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<DelayMacroAction delay="${this.delay}">`;
|
||||
}
|
||||
|
||||
public getName(): string {
|
||||
return 'DelayMacroAction';
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
import { UhkBuffer } from '../../uhk-buffer';
|
||||
import { MacroAction, MacroActionId, macroActionType } from './macro-action';
|
||||
import { KeyMacroAction } from './key-macro-action';
|
||||
import { MouseButtonMacroAction } from './mouse-button-macro-action';
|
||||
import { MoveMouseMacroAction } from './move-mouse-macro-action';
|
||||
import { ScrollMouseMacroAction } from './scroll-mouse-macro-action';
|
||||
import { DelayMacroAction } from './delay-macro-action';
|
||||
import { TextMacroAction } from './text-macro-action';
|
||||
|
||||
export class Helper {
|
||||
|
||||
static createMacroAction(source: MacroAction | UhkBuffer | any): MacroAction {
|
||||
if (source instanceof MacroAction) {
|
||||
return Helper.fromMacroAction(source);
|
||||
} else if (source instanceof UhkBuffer) {
|
||||
return Helper.fromUhkBuffer(source);
|
||||
} else {
|
||||
return Helper.fromJSONObject(source);
|
||||
}
|
||||
}
|
||||
|
||||
private static fromUhkBuffer(buffer: UhkBuffer): MacroAction {
|
||||
const macroActionFirstByte = buffer.readUInt8();
|
||||
buffer.backtrack();
|
||||
|
||||
if (macroActionFirstByte >= MacroActionId.KeyMacroAction && macroActionFirstByte <= MacroActionId.LastKeyMacroAction) {
|
||||
return new KeyMacroAction().fromBinary(buffer);
|
||||
} else if (
|
||||
macroActionFirstByte >= MacroActionId.MouseButtonMacroAction &&
|
||||
macroActionFirstByte <= MacroActionId.LastMouseButtonMacroAction
|
||||
) {
|
||||
return new MouseButtonMacroAction().fromBinary(buffer);
|
||||
}
|
||||
switch (macroActionFirstByte) {
|
||||
case MacroActionId.MoveMouseMacroAction:
|
||||
return new MoveMouseMacroAction().fromBinary(buffer);
|
||||
case MacroActionId.ScrollMouseMacroAction:
|
||||
return new ScrollMouseMacroAction().fromBinary(buffer);
|
||||
case MacroActionId.DelayMacroAction:
|
||||
return new DelayMacroAction().fromBinary(buffer);
|
||||
case MacroActionId.TextMacroAction:
|
||||
return new TextMacroAction().fromBinary(buffer);
|
||||
default:
|
||||
throw `Invalid MacroAction first byte: ${macroActionFirstByte}`;
|
||||
}
|
||||
}
|
||||
|
||||
private static fromMacroAction(macroAction: MacroAction): MacroAction {
|
||||
let newMacroAction: MacroAction;
|
||||
if (macroAction instanceof KeyMacroAction) {
|
||||
newMacroAction = new KeyMacroAction(macroAction);
|
||||
} else if (macroAction instanceof MouseButtonMacroAction) {
|
||||
newMacroAction = new MouseButtonMacroAction(macroAction);
|
||||
} else if (macroAction instanceof MoveMouseMacroAction) {
|
||||
newMacroAction = new MoveMouseMacroAction(macroAction);
|
||||
} else if (macroAction instanceof ScrollMouseMacroAction) {
|
||||
newMacroAction = new ScrollMouseMacroAction(macroAction);
|
||||
} else if (macroAction instanceof DelayMacroAction) {
|
||||
newMacroAction = new DelayMacroAction(macroAction);
|
||||
} else if (macroAction instanceof TextMacroAction) {
|
||||
newMacroAction = new TextMacroAction(macroAction);
|
||||
}
|
||||
return newMacroAction;
|
||||
}
|
||||
|
||||
private static fromJSONObject(macroAction: any): MacroAction {
|
||||
switch (macroAction.macroActionType) {
|
||||
case macroActionType.KeyMacroAction:
|
||||
return new KeyMacroAction().fromJsonObject(macroAction);
|
||||
case macroActionType.MouseButtonMacroAction:
|
||||
return new MouseButtonMacroAction().fromJsonObject(macroAction);
|
||||
case macroActionType.MoveMouseMacroAction:
|
||||
return new MoveMouseMacroAction().fromJsonObject(macroAction);
|
||||
case macroActionType.ScrollMouseMacroAction:
|
||||
return new ScrollMouseMacroAction().fromJsonObject(macroAction);
|
||||
case macroActionType.DelayMacroAction:
|
||||
return new DelayMacroAction().fromJsonObject(macroAction);
|
||||
case macroActionType.TextMacroAction:
|
||||
return new TextMacroAction().fromJsonObject(macroAction);
|
||||
default:
|
||||
throw `Invalid MacroAction.macroActionType: "${macroAction.macroActionType}"`;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
export * from './delay-macro-action';
|
||||
export * from './key-macro-action';
|
||||
export * from './macro-action';
|
||||
export * from './move-mouse-macro-action';
|
||||
export * from './mouse-button-macro-action';
|
||||
export * from './scroll-mouse-macro-action';
|
||||
export * from './text-macro-action';
|
||||
export * from './helper';
|
||||
@@ -1,139 +0,0 @@
|
||||
import { assertEnum, assertUInt8 } from '../../assert';
|
||||
import { UhkBuffer } from '../../uhk-buffer';
|
||||
import { KeyModifiers } from '../key-modifiers';
|
||||
import { MacroAction, MacroActionId, MacroSubAction, macroActionType } from './macro-action';
|
||||
import { KeystrokeType } from '../key-action/keystroke-type';
|
||||
|
||||
interface JsObjectKeyMacroAction {
|
||||
macroActionType: string;
|
||||
action: string;
|
||||
type?: string;
|
||||
scancode?: number;
|
||||
modifierMask?: number;
|
||||
}
|
||||
|
||||
export class KeyMacroAction extends MacroAction {
|
||||
|
||||
@assertEnum(MacroSubAction)
|
||||
action: MacroSubAction;
|
||||
|
||||
@assertEnum(KeystrokeType)
|
||||
type: KeystrokeType;
|
||||
|
||||
@assertUInt8
|
||||
scancode: number;
|
||||
|
||||
@assertUInt8
|
||||
modifierMask: number;
|
||||
|
||||
constructor(other?: KeyMacroAction) {
|
||||
super();
|
||||
if (!other) {
|
||||
return;
|
||||
}
|
||||
this.action = other.action;
|
||||
this.type = other.type;
|
||||
this.scancode = other.scancode;
|
||||
this.modifierMask = other.modifierMask;
|
||||
}
|
||||
|
||||
fromJsonObject(jsObject: JsObjectKeyMacroAction): KeyMacroAction {
|
||||
this.assertMacroActionType(jsObject);
|
||||
this.action = MacroSubAction[jsObject.action];
|
||||
if (jsObject.type === 'media') {
|
||||
this.type = jsObject.scancode < 256 ? KeystrokeType.shortMedia : KeystrokeType.longMedia;
|
||||
} else {
|
||||
this.type = KeystrokeType[jsObject.type];
|
||||
}
|
||||
this.scancode = jsObject.scancode;
|
||||
this.modifierMask = jsObject.modifierMask;
|
||||
return this;
|
||||
}
|
||||
|
||||
fromBinary(buffer: UhkBuffer): KeyMacroAction {
|
||||
const macroActionId: MacroActionId = this.readAndAssertMacroActionId(buffer);
|
||||
let keyMacroType: number = macroActionId - MacroActionId.KeyMacroAction;
|
||||
this.action = keyMacroType & 0b11;
|
||||
keyMacroType >>= 2;
|
||||
this.type = keyMacroType & 0b11;
|
||||
keyMacroType >>= 2;
|
||||
if (keyMacroType & 0b10) {
|
||||
this.scancode = buffer.readUInt8();
|
||||
}
|
||||
if (keyMacroType & 0b01) {
|
||||
this.modifierMask = buffer.readUInt8();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
toJsonObject(): any {
|
||||
const jsObject: JsObjectKeyMacroAction = {
|
||||
macroActionType: macroActionType.KeyMacroAction,
|
||||
action: MacroSubAction[this.action]
|
||||
};
|
||||
|
||||
if (this.hasScancode()) {
|
||||
if (this.type === KeystrokeType.shortMedia || this.type === KeystrokeType.longMedia) {
|
||||
jsObject.type = 'media';
|
||||
} else {
|
||||
jsObject.type = KeystrokeType[this.type];
|
||||
}
|
||||
jsObject.scancode = this.scancode;
|
||||
}
|
||||
|
||||
if (this.hasModifiers()) {
|
||||
jsObject.modifierMask = this.modifierMask;
|
||||
}
|
||||
|
||||
return jsObject;
|
||||
}
|
||||
|
||||
toBinary(buffer: UhkBuffer) {
|
||||
let TYPE_OFFSET = 0;
|
||||
TYPE_OFFSET |= this.action;
|
||||
TYPE_OFFSET |= this.type << 2;
|
||||
TYPE_OFFSET |= ((this.hasScancode() ? 2 : 0) + (this.hasModifiers() ? 1 : 0)) << 4;
|
||||
|
||||
const keyMacroType: number = MacroActionId.KeyMacroAction + TYPE_OFFSET;
|
||||
|
||||
buffer.writeUInt8(keyMacroType);
|
||||
if (this.hasScancode()) {
|
||||
buffer.writeUInt8(this.scancode);
|
||||
}
|
||||
if (this.hasModifiers()) {
|
||||
buffer.writeUInt8(this.modifierMask);
|
||||
}
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<KeyMacroAction action="${this.action}" scancode="${this.scancode}" modifierMask="${this.modifierMask}">`;
|
||||
}
|
||||
|
||||
isModifierActive(modifier: KeyModifiers): boolean {
|
||||
return (this.modifierMask & modifier) > 0;
|
||||
}
|
||||
|
||||
hasScancode(): boolean {
|
||||
return !!this.scancode;
|
||||
}
|
||||
|
||||
hasModifiers(): boolean {
|
||||
return !!this.modifierMask;
|
||||
}
|
||||
|
||||
isHoldAction(): boolean {
|
||||
return this.action === MacroSubAction.hold;
|
||||
}
|
||||
|
||||
isPressAction(): boolean {
|
||||
return this.action === MacroSubAction.press;
|
||||
}
|
||||
|
||||
isReleaseAction(): boolean {
|
||||
return this.action === MacroSubAction.release;
|
||||
}
|
||||
|
||||
public getName(): string {
|
||||
return 'KeyMacroAction';
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
import { UhkBuffer } from '../../uhk-buffer';
|
||||
|
||||
export enum MacroActionId {
|
||||
KeyMacroAction = 0,
|
||||
/*
|
||||
0 - 63 are reserved for KeyMacroAction
|
||||
2 bits for: PressKeyMacroAction / HoldKeyMacroAction / ReleaseKeyMacroAction / undefined
|
||||
2 bits for: with only scancode / only modifiers / both scancode and modifiers / undefined
|
||||
2 bits for: scancode type basic, short media, long media, system. It should be only used if scancode does exist.
|
||||
*/
|
||||
LastKeyMacroAction = 63,
|
||||
MouseButtonMacroAction = 64,
|
||||
/*
|
||||
64 - 66 are reserved for MouseButtonMacroAction
|
||||
PressMouseButtonsMacroAction = 64,
|
||||
HoldMouseButtonsMacroAction = 65,
|
||||
ReleaseMouseButtonsMacroAction = 66,
|
||||
*/
|
||||
LastMouseButtonMacroAction = 66,
|
||||
MoveMouseMacroAction = 67,
|
||||
ScrollMouseMacroAction = 68,
|
||||
DelayMacroAction = 69,
|
||||
TextMacroAction = 70
|
||||
}
|
||||
|
||||
export enum MacroSubAction {
|
||||
press = 0,
|
||||
hold = 1,
|
||||
release = 2
|
||||
}
|
||||
|
||||
export let macroActionType = {
|
||||
KeyMacroAction : 'key',
|
||||
MouseButtonMacroAction : 'mouseButton',
|
||||
MoveMouseMacroAction : 'moveMouse',
|
||||
ScrollMouseMacroAction : 'scrollMouse',
|
||||
DelayMacroAction : 'delay',
|
||||
TextMacroAction : 'text'
|
||||
};
|
||||
|
||||
export abstract class MacroAction {
|
||||
assertMacroActionType(jsObject: any) {
|
||||
const macroActionClassname = this.getName();
|
||||
const macroActionTypeString = macroActionType[macroActionClassname];
|
||||
if (jsObject.macroActionType !== macroActionTypeString) {
|
||||
throw `Invalid ${macroActionClassname}.macroActionType: ${jsObject.macroActionType}`;
|
||||
}
|
||||
}
|
||||
|
||||
readAndAssertMacroActionId(buffer: UhkBuffer): MacroActionId {
|
||||
const classname: string = this.getName();
|
||||
const readMacroActionId: MacroActionId = buffer.readUInt8();
|
||||
const macroActionId: MacroActionId = MacroActionId[classname];
|
||||
if (macroActionId === MacroActionId.KeyMacroAction) {
|
||||
if (readMacroActionId < MacroActionId.KeyMacroAction || readMacroActionId > MacroActionId.LastKeyMacroAction) {
|
||||
throw `Invalid ${classname} first byte: ${readMacroActionId}`;
|
||||
}
|
||||
} else if (macroActionId === MacroActionId.MouseButtonMacroAction) {
|
||||
if (readMacroActionId < MacroActionId.MouseButtonMacroAction ||
|
||||
readMacroActionId > MacroActionId.LastMouseButtonMacroAction) {
|
||||
throw `Invalid ${classname} first byte: ${readMacroActionId}`;
|
||||
}
|
||||
} else if (readMacroActionId !== macroActionId) {
|
||||
throw `Invalid ${classname} first byte: ${readMacroActionId}`;
|
||||
}
|
||||
return readMacroActionId;
|
||||
}
|
||||
|
||||
abstract toJsonObject(): any;
|
||||
|
||||
abstract toBinary(buffer: UhkBuffer): void;
|
||||
|
||||
abstract getName(): string;
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
import { assertEnum, assertUInt8 } from '../../assert';
|
||||
import { UhkBuffer } from '../../uhk-buffer';
|
||||
import { MacroAction, MacroActionId, MacroSubAction, macroActionType } from './macro-action';
|
||||
|
||||
export enum MouseButtons {
|
||||
Left = 1 << 0,
|
||||
Middle = 1 << 1,
|
||||
Right = 1 << 2
|
||||
}
|
||||
|
||||
interface JsObjectMouseButtonMacroAction {
|
||||
macroActionType: string;
|
||||
action: string;
|
||||
mouseButtonsMask?: number;
|
||||
}
|
||||
|
||||
export class MouseButtonMacroAction extends MacroAction {
|
||||
@assertEnum(MacroSubAction)
|
||||
action: MacroSubAction;
|
||||
|
||||
@assertUInt8
|
||||
mouseButtonsMask: number;
|
||||
|
||||
constructor(other?: MouseButtonMacroAction) {
|
||||
super();
|
||||
if (!other) {
|
||||
return;
|
||||
}
|
||||
this.action = other.action;
|
||||
this.mouseButtonsMask = other.mouseButtonsMask;
|
||||
}
|
||||
|
||||
fromJsonObject(jsObject: JsObjectMouseButtonMacroAction): MouseButtonMacroAction {
|
||||
this.assertMacroActionType(jsObject);
|
||||
this.action = MacroSubAction[jsObject.action];
|
||||
this.mouseButtonsMask = jsObject.mouseButtonsMask;
|
||||
return this;
|
||||
}
|
||||
|
||||
fromBinary(buffer: UhkBuffer): MouseButtonMacroAction {
|
||||
const macroActionId: MacroActionId = this.readAndAssertMacroActionId(buffer);
|
||||
this.action = macroActionId - MacroActionId.MouseButtonMacroAction;
|
||||
this.mouseButtonsMask = buffer.readUInt8();
|
||||
return this;
|
||||
}
|
||||
|
||||
toJsonObject(): any {
|
||||
return {
|
||||
macroActionType: macroActionType.MouseButtonMacroAction,
|
||||
action: MacroSubAction[this.action],
|
||||
mouseButtonsMask: this.mouseButtonsMask
|
||||
};
|
||||
}
|
||||
|
||||
toBinary(buffer: UhkBuffer): void {
|
||||
buffer.writeUInt8(MacroActionId.MouseButtonMacroAction + this.action);
|
||||
buffer.writeUInt8(this.mouseButtonsMask);
|
||||
}
|
||||
|
||||
setMouseButtons(buttonStates: boolean[]): void {
|
||||
let bitmask = 0;
|
||||
for (let i = 0; i < buttonStates.length; i++) {
|
||||
bitmask |= Number(buttonStates[i]) << i;
|
||||
}
|
||||
this.mouseButtonsMask = bitmask;
|
||||
}
|
||||
|
||||
getMouseButtons(): boolean[] {
|
||||
const enabledMouseButtons: boolean[] = [];
|
||||
for (let bitmask = this.mouseButtonsMask; bitmask; bitmask >>>= 1) {
|
||||
enabledMouseButtons.push(Boolean(bitmask & 1));
|
||||
}
|
||||
return enabledMouseButtons;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<MouseButtonMacroAction mouseButtonsMask="${this.mouseButtonsMask}">`;
|
||||
}
|
||||
|
||||
hasButtons(): boolean {
|
||||
return this.mouseButtonsMask !== 0;
|
||||
}
|
||||
|
||||
isOnlyHoldAction(): boolean {
|
||||
return this.action === MacroSubAction.hold;
|
||||
}
|
||||
|
||||
isOnlyPressAction(): boolean {
|
||||
return this.action === MacroSubAction.press;
|
||||
}
|
||||
|
||||
isOnlyReleaseAction(): boolean {
|
||||
return this.action === MacroSubAction.release;
|
||||
}
|
||||
|
||||
public getName(): string {
|
||||
return 'MouseButtonMacroAction';
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
import { assertInt16 } from '../../assert';
|
||||
import { UhkBuffer } from '../../uhk-buffer';
|
||||
import { MacroAction, MacroActionId, macroActionType } from './macro-action';
|
||||
|
||||
export class MoveMouseMacroAction extends MacroAction {
|
||||
|
||||
@assertInt16
|
||||
x: number;
|
||||
|
||||
@assertInt16
|
||||
y: number;
|
||||
|
||||
constructor(other?: MoveMouseMacroAction) {
|
||||
super();
|
||||
if (!other) {
|
||||
return;
|
||||
}
|
||||
this.x = other.x;
|
||||
this.y = other.y;
|
||||
}
|
||||
|
||||
fromJsonObject(jsObject: any): MoveMouseMacroAction {
|
||||
this.assertMacroActionType(jsObject);
|
||||
this.x = jsObject.x;
|
||||
this.y = jsObject.y;
|
||||
return this;
|
||||
}
|
||||
|
||||
fromBinary(buffer: UhkBuffer): MoveMouseMacroAction {
|
||||
this.readAndAssertMacroActionId(buffer);
|
||||
this.x = buffer.readInt16();
|
||||
this.y = buffer.readInt16();
|
||||
return this;
|
||||
}
|
||||
|
||||
toJsonObject(): any {
|
||||
return {
|
||||
macroActionType: macroActionType.MoveMouseMacroAction,
|
||||
x: this.x,
|
||||
y: this.y
|
||||
};
|
||||
}
|
||||
|
||||
toBinary(buffer: UhkBuffer) {
|
||||
buffer.writeUInt8(MacroActionId.MoveMouseMacroAction);
|
||||
buffer.writeInt16(this.x);
|
||||
buffer.writeInt16(this.y);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<MoveMouseMacroAction pos="(${this.x},${this.y})">`;
|
||||
}
|
||||
|
||||
public getName(): string {
|
||||
return 'MoveMouseMacroAction';
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
import { assertInt16 } from '../../assert';
|
||||
import { UhkBuffer } from '../../uhk-buffer';
|
||||
import { MacroAction, MacroActionId, macroActionType } from './macro-action';
|
||||
|
||||
export class ScrollMouseMacroAction extends MacroAction {
|
||||
|
||||
@assertInt16
|
||||
x: number;
|
||||
|
||||
@assertInt16
|
||||
y: number;
|
||||
|
||||
constructor(other?: ScrollMouseMacroAction) {
|
||||
super();
|
||||
if (!other) {
|
||||
return;
|
||||
}
|
||||
this.x = other.x;
|
||||
this.y = other.y;
|
||||
}
|
||||
|
||||
fromJsonObject(jsObject: any): ScrollMouseMacroAction {
|
||||
this.assertMacroActionType(jsObject);
|
||||
this.x = jsObject.x;
|
||||
this.y = jsObject.y;
|
||||
return this;
|
||||
}
|
||||
|
||||
fromBinary(buffer: UhkBuffer): ScrollMouseMacroAction {
|
||||
this.readAndAssertMacroActionId(buffer);
|
||||
this.x = buffer.readInt16();
|
||||
this.y = buffer.readInt16();
|
||||
return this;
|
||||
}
|
||||
|
||||
toJsonObject(): any {
|
||||
return {
|
||||
macroActionType: macroActionType.ScrollMouseMacroAction,
|
||||
x: this.x,
|
||||
y: this.y
|
||||
};
|
||||
}
|
||||
|
||||
toBinary(buffer: UhkBuffer) {
|
||||
buffer.writeUInt8(MacroActionId.ScrollMouseMacroAction);
|
||||
buffer.writeInt16(this.x);
|
||||
buffer.writeInt16(this.y);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<ScrollMouseMacroAction pos="(${this.x},${this.y})">`;
|
||||
}
|
||||
|
||||
public getName(): string {
|
||||
return 'ScrollMouseMacroAction';
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
import { UhkBuffer } from '../../uhk-buffer';
|
||||
import { MacroAction, MacroActionId, macroActionType } from './macro-action';
|
||||
|
||||
export class TextMacroAction extends MacroAction {
|
||||
|
||||
text: string;
|
||||
|
||||
constructor(other?: TextMacroAction) {
|
||||
super();
|
||||
if (!other) {
|
||||
return;
|
||||
}
|
||||
this.text = other.text;
|
||||
}
|
||||
|
||||
fromJsonObject(jsObject: any): TextMacroAction {
|
||||
this.assertMacroActionType(jsObject);
|
||||
this.text = jsObject.text;
|
||||
return this;
|
||||
}
|
||||
|
||||
fromBinary(buffer: UhkBuffer): TextMacroAction {
|
||||
this.readAndAssertMacroActionId(buffer);
|
||||
this.text = buffer.readString();
|
||||
return this;
|
||||
}
|
||||
|
||||
toJsonObject(): any {
|
||||
return {
|
||||
macroActionType: macroActionType.TextMacroAction,
|
||||
text: this.text
|
||||
};
|
||||
}
|
||||
|
||||
toBinary(buffer: UhkBuffer) {
|
||||
buffer.writeUInt8(MacroActionId.TextMacroAction);
|
||||
buffer.writeString(this.text);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<TextMacroAction text="${this.text}">`;
|
||||
}
|
||||
|
||||
public getName(): string {
|
||||
return 'TextMacroAction';
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
import { assertUInt8 } from '../assert';
|
||||
import { UhkBuffer } from '../uhk-buffer';
|
||||
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();
|
||||
const macroActionsLength: number = buffer.readCompactLength();
|
||||
this.macroActions = [];
|
||||
for (let i = 0; i < macroActionsLength; ++i) {
|
||||
this.macroActions.push(MacroActionHelper.createMacroAction(buffer));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
toJsonObject(): any {
|
||||
return {
|
||||
isLooped: this.isLooped,
|
||||
isPrivate: this.isPrivate,
|
||||
name: this.name,
|
||||
macroActions: this.macroActions.map(macroAction => macroAction.toJsonObject())
|
||||
};
|
||||
}
|
||||
|
||||
toBinary(buffer: UhkBuffer): void {
|
||||
buffer.writeBoolean(this.isLooped);
|
||||
buffer.writeBoolean(this.isPrivate);
|
||||
buffer.writeString(this.name);
|
||||
buffer.writeArray(this.macroActions);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<Macro id="${this.id}" name="${this.name}">`;
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
import { assertUInt8 } from '../assert';
|
||||
import { UhkBuffer } from '../uhk-buffer';
|
||||
|
||||
export class ModuleConfiguration {
|
||||
|
||||
/*
|
||||
* module id enumeration is a separate story
|
||||
*/
|
||||
|
||||
@assertUInt8
|
||||
id: number;
|
||||
|
||||
@assertUInt8
|
||||
initialPointerSpeed: number;
|
||||
|
||||
@assertUInt8
|
||||
pointerAcceleration: number;
|
||||
|
||||
@assertUInt8
|
||||
maxPointerSpeed: number;
|
||||
|
||||
fromJsonObject(jsonObject: any): ModuleConfiguration {
|
||||
this.id = jsonObject.id;
|
||||
this.initialPointerSpeed = jsonObject.initialPointerSpeed;
|
||||
this.pointerAcceleration = jsonObject.pointerAcceleration;
|
||||
this.maxPointerSpeed = jsonObject.maxPointerSpeed;
|
||||
return this;
|
||||
}
|
||||
|
||||
fromBinary(buffer: UhkBuffer): ModuleConfiguration {
|
||||
this.id = buffer.readUInt8();
|
||||
this.initialPointerSpeed = buffer.readUInt8();
|
||||
this.pointerAcceleration = buffer.readUInt8();
|
||||
this.maxPointerSpeed = buffer.readUInt8();
|
||||
return this;
|
||||
}
|
||||
|
||||
toJsonObject(): any {
|
||||
return {
|
||||
id: this.id,
|
||||
initialPointerSpeed: this.initialPointerSpeed,
|
||||
pointerAcceleration: this.pointerAcceleration,
|
||||
maxPointerSpeed: this.maxPointerSpeed
|
||||
};
|
||||
}
|
||||
|
||||
toBinary(buffer: UhkBuffer): void {
|
||||
buffer.writeUInt8(this.id);
|
||||
buffer.writeUInt8(this.initialPointerSpeed);
|
||||
buffer.writeUInt8(this.pointerAcceleration);
|
||||
buffer.writeUInt8(this.maxPointerSpeed);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<ModuleConfiguration id="${this.id}" >`;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
import { assertEnum, assertUInt8 } from '../assert';
|
||||
import { UhkBuffer } from '../uhk-buffer';
|
||||
import { Helper as KeyActionHelper, KeyAction, NoneAction, PlayMacroAction, SwitchKeymapAction } from './key-action';
|
||||
import { Macro } from './macro';
|
||||
import { UserConfiguration } from './user-configuration';
|
||||
|
||||
enum PointerRole {
|
||||
none,
|
||||
move,
|
||||
scroll
|
||||
}
|
||||
|
||||
export class Module {
|
||||
|
||||
@assertUInt8
|
||||
id: number;
|
||||
|
||||
keyActions: KeyAction[];
|
||||
|
||||
@assertEnum(PointerRole)
|
||||
pointerRole: PointerRole;
|
||||
|
||||
constructor(other?: Module) {
|
||||
if (!other) {
|
||||
return;
|
||||
}
|
||||
this.id = other.id;
|
||||
this.keyActions = other.keyActions.map(keyAction => KeyActionHelper.createKeyAction(keyAction));
|
||||
this.pointerRole = other.pointerRole;
|
||||
}
|
||||
|
||||
fromJsonObject(jsonObject: any, macros?: Macro[]): Module {
|
||||
this.id = jsonObject.id;
|
||||
this.pointerRole = PointerRole[<string>jsonObject.pointerRole];
|
||||
this.keyActions = jsonObject.keyActions.map((keyAction: any) => {
|
||||
return KeyActionHelper.createKeyAction(keyAction, macros);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
fromBinary(buffer: UhkBuffer, macros?: Macro[]): Module {
|
||||
this.id = buffer.readUInt8();
|
||||
this.pointerRole = buffer.readUInt8();
|
||||
const keyActionsLength: number = buffer.readCompactLength();
|
||||
this.keyActions = [];
|
||||
for (let i = 0; i < keyActionsLength; ++i) {
|
||||
this.keyActions.push(KeyActionHelper.createKeyAction(buffer, macros));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
toJsonObject(macros?: Macro[]): any {
|
||||
return {
|
||||
id: this.id,
|
||||
pointerRole: PointerRole[this.pointerRole],
|
||||
keyActions: this.keyActions.map(keyAction => {
|
||||
if (keyAction && (macros || !(keyAction instanceof PlayMacroAction || keyAction instanceof SwitchKeymapAction))) {
|
||||
return keyAction.toJsonObject(macros);
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
toBinary(buffer: UhkBuffer, userConfiguration: UserConfiguration): void {
|
||||
buffer.writeUInt8(this.id);
|
||||
buffer.writeUInt8(this.pointerRole);
|
||||
|
||||
const noneAction = new NoneAction();
|
||||
|
||||
const keyActions: KeyAction[] = this.keyActions.map(keyAction => {
|
||||
if (keyAction) {
|
||||
return keyAction;
|
||||
}
|
||||
return noneAction;
|
||||
});
|
||||
|
||||
buffer.writeArray(keyActions, (uhkBuffer: UhkBuffer, keyAction: KeyAction) => {
|
||||
keyAction.toBinary(uhkBuffer, userConfiguration);
|
||||
});
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<Module id="${this.id}" pointerRole="${this.pointerRole}">`;
|
||||
}
|
||||
|
||||
renameKeymap(oldAbbr: string, newAbbr: string): Module {
|
||||
let keyActions: KeyAction[];
|
||||
let keyActionModified = false;
|
||||
this.keyActions.forEach((keyAction, index) => {
|
||||
if (!keyAction) { return; }
|
||||
const newKeyAction = keyAction.renameKeymap(oldAbbr, newAbbr);
|
||||
if (newKeyAction !== keyAction) {
|
||||
if (!keyActionModified) {
|
||||
keyActions = this.keyActions.slice();
|
||||
keyActionModified = true;
|
||||
}
|
||||
keyActions[index] = newKeyAction;
|
||||
}
|
||||
});
|
||||
if (keyActionModified) {
|
||||
const newModule = Object.assign(new Module(), this);
|
||||
newModule.keyActions = keyActions;
|
||||
return newModule;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
import { assertUInt16 } from '../assert';
|
||||
import { UhkBuffer } from '../uhk-buffer';
|
||||
import { Keymap } from './keymap';
|
||||
import { Macro } from './macro';
|
||||
import { ModuleConfiguration } from './module-configuration';
|
||||
import { ConfigSerializer } from '../config-serializer';
|
||||
|
||||
export class UserConfiguration {
|
||||
|
||||
@assertUInt16
|
||||
dataModelVersion: number;
|
||||
|
||||
moduleConfigurations: ModuleConfiguration[] = [];
|
||||
|
||||
keymaps: Keymap[] = [];
|
||||
|
||||
macros: Macro[] = [];
|
||||
|
||||
fromJsonObject(jsonObject: any): UserConfiguration {
|
||||
this.dataModelVersion = jsonObject.dataModelVersion;
|
||||
this.moduleConfigurations = jsonObject.moduleConfigurations.map((moduleConfiguration: any) => {
|
||||
return new ModuleConfiguration().fromJsonObject(moduleConfiguration);
|
||||
});
|
||||
this.macros = jsonObject.macros.map((macroJsonObject: any, index: number) => {
|
||||
const macro = new Macro().fromJsonObject(macroJsonObject);
|
||||
macro.id = index;
|
||||
return macro;
|
||||
});
|
||||
this.keymaps = jsonObject.keymaps.map((keymap: any) => new Keymap().fromJsonObject(keymap, this.macros));
|
||||
return this;
|
||||
}
|
||||
|
||||
fromBinary(buffer: UhkBuffer): UserConfiguration {
|
||||
this.dataModelVersion = buffer.readUInt16();
|
||||
this.moduleConfigurations = buffer.readArray<ModuleConfiguration>(uhkBuffer => {
|
||||
return new ModuleConfiguration().fromBinary(uhkBuffer);
|
||||
});
|
||||
this.macros = buffer.readArray<Macro>((uhkBuffer, index) => {
|
||||
const macro = new Macro().fromBinary(uhkBuffer);
|
||||
macro.id = index;
|
||||
return macro;
|
||||
});
|
||||
this.keymaps = buffer.readArray<Keymap>(uhkBuffer => new Keymap().fromBinary(uhkBuffer, this.macros));
|
||||
ConfigSerializer.resolveSwitchKeymapActions(this.keymaps);
|
||||
return this;
|
||||
}
|
||||
|
||||
toJsonObject(): any {
|
||||
return {
|
||||
dataModelVersion: this.dataModelVersion,
|
||||
moduleConfigurations: this.moduleConfigurations.map(moduleConfiguration => moduleConfiguration.toJsonObject()),
|
||||
keymaps: this.keymaps.map(keymap => keymap.toJsonObject(this.macros)),
|
||||
macros: this.macros.map(macro => macro.toJsonObject())
|
||||
};
|
||||
}
|
||||
|
||||
toBinary(buffer: UhkBuffer): void {
|
||||
buffer.writeUInt16(this.dataModelVersion);
|
||||
buffer.writeArray(this.moduleConfigurations);
|
||||
buffer.writeArray(this.macros);
|
||||
buffer.writeArray(this.keymaps, (uhkBuffer: UhkBuffer, keymap: Keymap) => {
|
||||
keymap.toBinary(uhkBuffer, this);
|
||||
});
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<UserConfiguration dataModelVersion="${this.dataModelVersion}">`;
|
||||
}
|
||||
|
||||
getKeymap(keymapAbbreviation: string): Keymap {
|
||||
return this.keymaps.find(keymap => keymapAbbreviation === keymap.abbreviation);
|
||||
}
|
||||
|
||||
getMacro(macroId: number): Macro {
|
||||
return this.macros.find(macro => macroId === macro.id);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import { Keymap } from './config-items/keymap';
|
||||
import { UnresolvedSwitchKeymapAction } from './config-items/key-action';
|
||||
|
||||
export namespace ConfigSerializer {
|
||||
|
||||
export function resolveSwitchKeymapActions(keymaps: Keymap[]) {
|
||||
for (const keymap of keymaps) {
|
||||
for (const layer of keymap.layers) {
|
||||
for (const module of layer.modules) {
|
||||
for (let i = 0; i < module.keyActions.length; ++i) {
|
||||
const keyAction = module.keyActions[i];
|
||||
if (keyAction instanceof UnresolvedSwitchKeymapAction) {
|
||||
module.keyActions[i] = keyAction.resolve(keymaps);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,214 +0,0 @@
|
||||
export class UhkBuffer {
|
||||
|
||||
static simpleElementWriter<T>(buffer: UhkBuffer, element: T): void {
|
||||
(<any>element).toBinary(buffer); // TODO: Remove any
|
||||
}
|
||||
|
||||
private static eepromSize = 32 * 1024;
|
||||
private static maxCompactLength = 0xFFFF;
|
||||
private static longCompactLengthPrefix = 0xFF;
|
||||
private static stringEncoding = 'utf8';
|
||||
private static isFirstElementToDump = false;
|
||||
|
||||
offset: number;
|
||||
private _enableDump = false;
|
||||
|
||||
private buffer: Buffer;
|
||||
private bytesToBacktrack: number;
|
||||
|
||||
constructor() {
|
||||
this.offset = 0;
|
||||
this.bytesToBacktrack = 0;
|
||||
this.buffer = new Buffer(UhkBuffer.eepromSize);
|
||||
this.buffer.fill(0);
|
||||
}
|
||||
|
||||
readInt8(): number {
|
||||
const value = this.buffer.readInt8(this.offset);
|
||||
this.dump(`i8(${value})`);
|
||||
this.bytesToBacktrack = 1;
|
||||
this.offset += this.bytesToBacktrack;
|
||||
return value;
|
||||
}
|
||||
|
||||
writeInt8(value: number): void {
|
||||
this.dump(`i8(${value})`);
|
||||
this.buffer.writeInt8(value, this.offset);
|
||||
this.offset += 1;
|
||||
}
|
||||
|
||||
readUInt8(): number {
|
||||
const value = this.buffer.readUInt8(this.offset);
|
||||
this.dump(`u8(${value})`);
|
||||
this.bytesToBacktrack = 1;
|
||||
this.offset += this.bytesToBacktrack;
|
||||
return value;
|
||||
}
|
||||
|
||||
writeUInt8(value: number): void {
|
||||
this.dump(`u8(${value})`);
|
||||
this.buffer.writeUInt8(value, this.offset);
|
||||
this.offset += 1;
|
||||
}
|
||||
|
||||
readInt16(): number {
|
||||
const value = this.buffer.readInt16LE(this.offset);
|
||||
this.dump(`i16(${value})`);
|
||||
this.bytesToBacktrack = 2;
|
||||
this.offset += this.bytesToBacktrack;
|
||||
return value;
|
||||
}
|
||||
|
||||
writeInt16(value: number): void {
|
||||
this.dump(`i16(${value})`);
|
||||
this.buffer.writeInt16LE(value, this.offset);
|
||||
this.offset += 2;
|
||||
}
|
||||
|
||||
readUInt16(): number {
|
||||
const value = this.buffer.readUInt16LE(this.offset);
|
||||
this.dump(`u16(${value})`);
|
||||
this.bytesToBacktrack = 2;
|
||||
this.offset += this.bytesToBacktrack;
|
||||
return value;
|
||||
}
|
||||
|
||||
writeUInt16(value: number): void {
|
||||
this.dump(`u16(${value})`);
|
||||
this.buffer.writeUInt16LE(value, this.offset);
|
||||
this.offset += 2;
|
||||
}
|
||||
|
||||
readInt32(): number {
|
||||
const value = this.buffer.readInt32LE(this.offset);
|
||||
this.dump(`i32(${value})`);
|
||||
this.bytesToBacktrack = 4;
|
||||
this.offset += this.bytesToBacktrack;
|
||||
return value;
|
||||
}
|
||||
|
||||
writeInt32(value: number): void {
|
||||
this.dump(`i32(${value})`);
|
||||
this.buffer.writeInt32LE(value, this.offset);
|
||||
this.offset += 4;
|
||||
}
|
||||
|
||||
readUInt32(): number {
|
||||
const value = this.buffer.readUInt32LE(this.offset);
|
||||
this.dump(`u32(${value})`);
|
||||
this.bytesToBacktrack = 4;
|
||||
this.offset += this.bytesToBacktrack;
|
||||
return value;
|
||||
}
|
||||
|
||||
writeUInt32(value: number): void {
|
||||
this.dump(`u32(${value})`);
|
||||
this.buffer.writeUInt32LE(value, this.offset);
|
||||
this.offset += 4;
|
||||
}
|
||||
|
||||
readCompactLength(): number {
|
||||
let length = this.readUInt8();
|
||||
if (length === UhkBuffer.longCompactLengthPrefix) {
|
||||
length = this.readUInt16();
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
writeCompactLength(length: number) {
|
||||
if (length >= UhkBuffer.longCompactLengthPrefix) {
|
||||
this.writeUInt8(UhkBuffer.longCompactLengthPrefix);
|
||||
this.writeUInt16(length);
|
||||
} else {
|
||||
this.writeUInt8(length);
|
||||
}
|
||||
}
|
||||
|
||||
readString(): string {
|
||||
const stringByteLength = this.readCompactLength();
|
||||
const str = this.buffer.toString(UhkBuffer.stringEncoding, this.offset, this.offset + stringByteLength);
|
||||
this.dump(`${UhkBuffer.stringEncoding}(${str})`);
|
||||
this.bytesToBacktrack = stringByteLength;
|
||||
this.offset += stringByteLength;
|
||||
return str;
|
||||
}
|
||||
|
||||
writeString(str: string): void {
|
||||
const stringByteLength = Buffer.byteLength(str, UhkBuffer.stringEncoding);
|
||||
|
||||
if (stringByteLength > UhkBuffer.maxCompactLength) {
|
||||
throw `Cannot serialize string: ${stringByteLength} bytes is larger
|
||||
than the maximum allowed length of ${UhkBuffer.maxCompactLength} bytes`;
|
||||
}
|
||||
|
||||
this.writeCompactLength(stringByteLength);
|
||||
this.dump(`${UhkBuffer.stringEncoding}(${str})`);
|
||||
this.buffer.write(str, this.offset, stringByteLength, UhkBuffer.stringEncoding);
|
||||
this.offset += stringByteLength;
|
||||
}
|
||||
|
||||
readBoolean(): boolean {
|
||||
return this.readUInt8() !== 0;
|
||||
}
|
||||
|
||||
writeBoolean(bool: boolean) {
|
||||
this.writeUInt8(bool ? 1 : 0);
|
||||
}
|
||||
|
||||
readArray<T>(elementReader: (buffer: UhkBuffer, index?: number) => T): T[] {
|
||||
const array: T[] = [];
|
||||
const length = this.readCompactLength();
|
||||
for (let i = 0; i < length; ++i) {
|
||||
array.push(elementReader(this, i));
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
writeArray<T>(
|
||||
array: T[],
|
||||
elementWriter: (buffer: UhkBuffer, element: T, index?: number) => void = UhkBuffer.simpleElementWriter
|
||||
): void {
|
||||
const length = array.length;
|
||||
this.writeCompactLength(length);
|
||||
for (let i = 0; i < length; ++i) {
|
||||
elementWriter(this, array[i], i);
|
||||
}
|
||||
}
|
||||
|
||||
backtrack(): void {
|
||||
this.offset -= this.bytesToBacktrack;
|
||||
this.bytesToBacktrack = 0;
|
||||
}
|
||||
|
||||
getBufferContent(): Buffer {
|
||||
return this.buffer.slice(0, this.offset);
|
||||
}
|
||||
|
||||
get enableDump() {
|
||||
return this._enableDump;
|
||||
}
|
||||
|
||||
set enableDump(value) {
|
||||
if (value) {
|
||||
UhkBuffer.isFirstElementToDump = true;
|
||||
}
|
||||
this._enableDump = value;
|
||||
}
|
||||
|
||||
dump(value: any) {
|
||||
if (!this.enableDump) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!UhkBuffer.isFirstElementToDump) {
|
||||
process.stdout.write(', ');
|
||||
}
|
||||
|
||||
process.stdout.write(value);
|
||||
|
||||
if (UhkBuffer.isFirstElementToDump) {
|
||||
UhkBuffer.isFirstElementToDump = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { UserConfiguration } from 'uhk-common';
|
||||
|
||||
import { UserConfiguration } from '../config-serializer/config-items/user-configuration';
|
||||
import { AutoUpdateSettings } from '../models/auto-update-settings';
|
||||
|
||||
@Injectable()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { UserConfiguration } from '../config-serializer/config-items/user-configuration';
|
||||
import { UserConfiguration } from 'uhk-common';
|
||||
|
||||
@Injectable()
|
||||
export class DefaultUserConfigurationService {
|
||||
@@ -7,7 +7,7 @@ export class DefaultUserConfigurationService {
|
||||
|
||||
constructor() {
|
||||
this._defaultConfig = new UserConfiguration()
|
||||
.fromJsonObject(require('../config-serializer/user-config.json'));
|
||||
.fromJsonObject(require('./user-config.json'));
|
||||
}
|
||||
|
||||
getDefault(): UserConfiguration {
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
SaveConfigurationReplyAction,
|
||||
SetPrivilegeOnLinuxReplyAction
|
||||
} from '../store/actions/device';
|
||||
import { LoadUserConfigFromDeviceReplyAction } from '../store/actions/user-config';
|
||||
import { LoadConfigFromDeviceReplyAction } from '../store/actions/user-config';
|
||||
|
||||
@Injectable()
|
||||
export class DeviceRendererService {
|
||||
@@ -29,8 +29,8 @@ export class DeviceRendererService {
|
||||
this.ipcRenderer.send(IpcEvents.device.saveUserConfiguration, JSON.stringify(buffer));
|
||||
}
|
||||
|
||||
loadUserConfiguration(): void {
|
||||
this.ipcRenderer.send(IpcEvents.device.loadUserConfiguration);
|
||||
loadConfigurationFromKeyboard(): void {
|
||||
this.ipcRenderer.send(IpcEvents.device.loadConfigurations);
|
||||
}
|
||||
|
||||
private registerEvents(): void {
|
||||
@@ -46,8 +46,8 @@ export class DeviceRendererService {
|
||||
this.dispachStoreAction(new SaveConfigurationReplyAction(response));
|
||||
});
|
||||
|
||||
this.ipcRenderer.on(IpcEvents.device.loadUserConfigurationReply, (event: string, response: string) => {
|
||||
this.dispachStoreAction(new LoadUserConfigFromDeviceReplyAction(JSON.parse(response)));
|
||||
this.ipcRenderer.on(IpcEvents.device.loadConfigurationReply, (event: string, response: string) => {
|
||||
this.dispachStoreAction(new LoadConfigFromDeviceReplyAction(JSON.parse(response)));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { KeystrokeType } from '../config-serializer/config-items/key-action/keystroke-type';
|
||||
import { KeystrokeType } from 'uhk-common';
|
||||
|
||||
@Injectable()
|
||||
export class MapperService {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,7 @@
|
||||
import { Action } from '@ngrx/store';
|
||||
|
||||
import { type } from 'uhk-common';
|
||||
import { Notification, CommandLineArgs } from 'uhk-common';
|
||||
import { AppStartInfo } from '../../../../../uhk-common/src/models/app-start-info';
|
||||
import { AppStartInfo, HardwareConfiguration, Notification } from 'uhk-common';
|
||||
|
||||
const PREFIX = '[app] ';
|
||||
|
||||
@@ -15,7 +14,8 @@ export const ActionTypes = {
|
||||
APP_PROCESS_START_INFO: type(PREFIX + 'process start info'),
|
||||
UNDO_LAST: type(PREFIX + 'undo last action'),
|
||||
UNDO_LAST_SUCCESS: type(PREFIX + 'undo last action success'),
|
||||
DISMISS_UNDO_NOTIFICATION: type(PREFIX + 'dismiss notification action')
|
||||
DISMISS_UNDO_NOTIFICATION: type(PREFIX + 'dismiss notification action'),
|
||||
LOAD_HARDWARE_CONFIGURATION_SUCCESS: type(PREFIX + 'load hardware configuration success')
|
||||
};
|
||||
|
||||
export class AppBootsrappedAction implements Action {
|
||||
@@ -58,6 +58,12 @@ export class DismissUndoNotificationAction implements Action {
|
||||
type = ActionTypes.DISMISS_UNDO_NOTIFICATION;
|
||||
}
|
||||
|
||||
export class LoadHardwareConfigurationSuccessAction implements Action {
|
||||
type = ActionTypes.LOAD_HARDWARE_CONFIGURATION_SUCCESS;
|
||||
|
||||
constructor(public payload: HardwareConfiguration) {}
|
||||
}
|
||||
|
||||
export type Actions
|
||||
= AppStartedAction
|
||||
| AppBootsrappedAction
|
||||
@@ -66,4 +72,6 @@ export type Actions
|
||||
| ProcessAppStartInfoAction
|
||||
| UndoLastAction
|
||||
| UndoLastSuccessAction
|
||||
| DismissUndoNotificationAction;
|
||||
| DismissUndoNotificationAction
|
||||
| LoadHardwareConfigurationSuccessAction
|
||||
;
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import { Action } from '@ngrx/store';
|
||||
|
||||
import { KeyAction } from '../../config-serializer/config-items/key-action';
|
||||
import { Keymap } from '../../config-serializer/config-items/keymap';
|
||||
import { Macro } from '../../config-serializer/config-items/macro';
|
||||
import { KeyAction, Keymap, Macro } from 'uhk-common';
|
||||
|
||||
export namespace KeymapActions {
|
||||
export const PREFIX = '[Keymap] ';
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { Action } from '@ngrx/store';
|
||||
|
||||
import { Macro } from '../../config-serializer/config-items/macro';
|
||||
import { MacroAction } from '../../config-serializer/config-items/macro-action';
|
||||
import { Macro, MacroAction } from 'uhk-common';
|
||||
|
||||
export namespace MacroActions {
|
||||
export const PREFIX = '[Macro] ';
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
import { Action } from '@ngrx/store';
|
||||
|
||||
import { type } from 'uhk-common';
|
||||
import { UserConfiguration } from '../../config-serializer/config-items/user-configuration';
|
||||
import { type, UserConfiguration, ConfigurationReply } from 'uhk-common';
|
||||
|
||||
const PREFIX = '[user-config] ';
|
||||
|
||||
// tslint:disable-next-line:variable-name
|
||||
export const ActionTypes = {
|
||||
LOAD_USER_CONFIG: type(PREFIX + 'Load User Config'),
|
||||
LOAD_USER_CONFIG_FROM_DEVICE: type(PREFIX + 'Load User Config from Device'),
|
||||
LOAD_USER_CONFIG_FROM_DEVICE_REPLY: type(PREFIX + 'Load User Config from Device reply'),
|
||||
LOAD_CONFIG_FROM_DEVICE: type(PREFIX + 'Load User Config from Device'),
|
||||
LOAD_CONFIG_FROM_DEVICE_REPLY: type(PREFIX + 'Load User Config from Device reply'),
|
||||
LOAD_USER_CONFIG_SUCCESS: type(PREFIX + 'Load User Config Success'),
|
||||
SAVE_USER_CONFIG_SUCCESS: type(PREFIX + 'Save User Config Success')
|
||||
};
|
||||
@@ -18,14 +16,14 @@ export class LoadUserConfigAction implements Action {
|
||||
type = ActionTypes.LOAD_USER_CONFIG;
|
||||
}
|
||||
|
||||
export class LoadUserConfigFromDeviceAction implements Action {
|
||||
type = ActionTypes.LOAD_USER_CONFIG_FROM_DEVICE;
|
||||
export class LoadConfigFromDeviceAction implements Action {
|
||||
type = ActionTypes.LOAD_CONFIG_FROM_DEVICE;
|
||||
}
|
||||
|
||||
export class LoadUserConfigFromDeviceReplyAction implements Action {
|
||||
type = ActionTypes.LOAD_USER_CONFIG_FROM_DEVICE_REPLY;
|
||||
export class LoadConfigFromDeviceReplyAction implements Action {
|
||||
type = ActionTypes.LOAD_CONFIG_FROM_DEVICE_REPLY;
|
||||
|
||||
constructor(public payload: Array<number>) { }
|
||||
constructor(public payload: ConfigurationReply) { }
|
||||
}
|
||||
|
||||
export class LoadUserConfigSuccessAction implements Action {
|
||||
@@ -43,4 +41,7 @@ export class SaveUserConfigSuccessAction implements Action {
|
||||
export type Actions
|
||||
= LoadUserConfigAction
|
||||
| LoadUserConfigSuccessAction
|
||||
| SaveUserConfigSuccessAction;
|
||||
| SaveUserConfigSuccessAction
|
||||
| LoadConfigFromDeviceAction
|
||||
| LoadConfigFromDeviceReplyAction
|
||||
;
|
||||
|
||||
@@ -12,7 +12,7 @@ import 'rxjs/add/operator/map';
|
||||
import 'rxjs/add/operator/mergeMap';
|
||||
import 'rxjs/add/operator/withLatestFrom';
|
||||
|
||||
import { NotificationType, IpcResponse } from 'uhk-common';
|
||||
import { NotificationType, IpcResponse, UhkBuffer, UserConfiguration } from 'uhk-common';
|
||||
import {
|
||||
ActionTypes,
|
||||
ConnectionStateChangedAction,
|
||||
@@ -24,9 +24,7 @@ import {
|
||||
import { DeviceRendererService } from '../../services/device-renderer.service';
|
||||
import { ShowNotificationAction } from '../actions/app';
|
||||
import { AppState } from '../index';
|
||||
import { UserConfiguration } from '../../config-serializer/config-items/user-configuration';
|
||||
import { UhkBuffer } from '../../config-serializer/uhk-buffer';
|
||||
import { LoadUserConfigFromDeviceAction } from '../actions/user-config';
|
||||
import { LoadConfigFromDeviceAction } from '../actions/user-config';
|
||||
|
||||
@Injectable()
|
||||
export class DeviceEffects {
|
||||
@@ -44,7 +42,7 @@ export class DeviceEffects {
|
||||
})
|
||||
.switchMap((connected: boolean) => {
|
||||
if (connected) {
|
||||
return Observable.of(new LoadUserConfigFromDeviceAction());
|
||||
return Observable.of(new LoadConfigFromDeviceAction());
|
||||
}
|
||||
|
||||
return Observable.empty();
|
||||
|
||||
@@ -12,11 +12,10 @@ import 'rxjs/add/operator/switchMap';
|
||||
import 'rxjs/add/operator/withLatestFrom';
|
||||
import 'rxjs/add/observable/of';
|
||||
|
||||
import { Keymap } from 'uhk-common';
|
||||
import { KeymapActions } from '../actions';
|
||||
import { AppState } from '../index';
|
||||
|
||||
import { Keymap } from '../../config-serializer/config-items/keymap';
|
||||
|
||||
@Injectable()
|
||||
export class KeymapEffects {
|
||||
|
||||
|
||||
@@ -11,7 +11,14 @@ import 'rxjs/add/operator/withLatestFrom';
|
||||
import 'rxjs/add/operator/mergeMap';
|
||||
import 'rxjs/add/observable/of';
|
||||
|
||||
import { LogService, NotificationType } from 'uhk-common';
|
||||
import {
|
||||
ConfigurationReply,
|
||||
HardwareConfiguration,
|
||||
LogService,
|
||||
NotificationType,
|
||||
UhkBuffer,
|
||||
UserConfiguration
|
||||
} from 'uhk-common';
|
||||
|
||||
import {
|
||||
ActionTypes,
|
||||
@@ -20,21 +27,42 @@ import {
|
||||
SaveUserConfigSuccessAction
|
||||
} from '../actions/user-config';
|
||||
|
||||
import { UserConfiguration } from '../../config-serializer/config-items/user-configuration';
|
||||
import { DataStorageRepositoryService } from '../../services/datastorage-repository.service';
|
||||
import { DefaultUserConfigurationService } from '../../services/default-user-configuration.service';
|
||||
import { AppState, getPrevUserConfiguration, getUserConfiguration } from '../index';
|
||||
import { KeymapActions } from '../actions/keymap';
|
||||
import { MacroActions } from '../actions/macro';
|
||||
import { UndoUserConfigData } from '../../models/undo-user-config-data';
|
||||
import { ShowNotificationAction, DismissUndoNotificationAction } from '../actions/app';
|
||||
import { ShowNotificationAction, DismissUndoNotificationAction, LoadHardwareConfigurationSuccessAction } from '../actions/app';
|
||||
import { ShowSaveToKeyboardButtonAction } from '../actions/device';
|
||||
import { DeviceRendererService } from '../../services/device-renderer.service';
|
||||
import { UhkBuffer } from '../../config-serializer/uhk-buffer';
|
||||
|
||||
@Injectable()
|
||||
export class UserConfigEffects {
|
||||
|
||||
private static getUserConfigFromDeviceResponse(json: string): UserConfiguration {
|
||||
const data = JSON.parse(json);
|
||||
const userConfig = new UserConfiguration();
|
||||
userConfig.fromBinary(UhkBuffer.fromArray(data));
|
||||
|
||||
if (userConfig.dataModelVersion > 0) {
|
||||
return userConfig;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static getHardwareConfigFromDeviceResponse(json: string): HardwareConfiguration {
|
||||
const data = JSON.parse(json);
|
||||
const hardwareConfig = new HardwareConfiguration();
|
||||
hardwareConfig.fromBinary(UhkBuffer.fromArray(data));
|
||||
|
||||
if (hardwareConfig.uuid > 0) {
|
||||
return hardwareConfig;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Effect() loadUserConfig$: Observable<Action> = this.actions$
|
||||
.ofType(ActionTypes.LOAD_USER_CONFIG)
|
||||
.startWith(new LoadUserConfigAction())
|
||||
@@ -88,38 +116,36 @@ export class UserConfigEffects {
|
||||
return [new LoadUserConfigSuccessAction(config), go(payload.path)];
|
||||
});
|
||||
|
||||
@Effect({dispatch: false}) loadUserConfigFromDevice$ = this.actions$
|
||||
.ofType(ActionTypes.LOAD_USER_CONFIG_FROM_DEVICE)
|
||||
.do(() => this.deviceRendererService.loadUserConfiguration());
|
||||
@Effect({dispatch: false}) loadConfigFromDevice$ = this.actions$
|
||||
.ofType(ActionTypes.LOAD_CONFIG_FROM_DEVICE)
|
||||
.do(() => this.deviceRendererService.loadConfigurationFromKeyboard());
|
||||
|
||||
@Effect() loadUserConfigFromDeviceReply$ = this.actions$
|
||||
.ofType(ActionTypes.LOAD_USER_CONFIG_FROM_DEVICE_REPLY)
|
||||
.map(action => action.payload)
|
||||
.switchMap((data: Array<number>) => {
|
||||
try {
|
||||
let userConfig;
|
||||
if (data.length > 0) {
|
||||
const uhkBuffer = new UhkBuffer();
|
||||
let hasNonZeroValue = false;
|
||||
for (const num of data) {
|
||||
if (num > 0) {
|
||||
hasNonZeroValue = true;
|
||||
}
|
||||
uhkBuffer.writeUInt8(num);
|
||||
}
|
||||
uhkBuffer.offset = 0;
|
||||
userConfig = new UserConfiguration();
|
||||
userConfig.fromBinary(uhkBuffer);
|
||||
|
||||
if (hasNonZeroValue) {
|
||||
return Observable.of(new LoadUserConfigSuccessAction(userConfig));
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
this.logService.error('Eeprom parse error:', err);
|
||||
@Effect() loadConfigFromDeviceReply$ = this.actions$
|
||||
.ofType(ActionTypes.LOAD_CONFIG_FROM_DEVICE_REPLY)
|
||||
.map(toPayload)
|
||||
.mergeMap((data: ConfigurationReply): any => {
|
||||
if (!data.success) {
|
||||
return [new ShowNotificationAction({
|
||||
type: NotificationType.Error,
|
||||
message: data.error
|
||||
})];
|
||||
}
|
||||
|
||||
return Observable.empty();
|
||||
try {
|
||||
const userConfig = UserConfigEffects.getUserConfigFromDeviceResponse(data.userConfiguration);
|
||||
const hardwareConfig = UserConfigEffects.getHardwareConfigFromDeviceResponse(data.hardwareConfiguration);
|
||||
|
||||
return [
|
||||
new LoadUserConfigSuccessAction(userConfig),
|
||||
new LoadHardwareConfigurationSuccessAction(hardwareConfig)
|
||||
];
|
||||
} catch (err) {
|
||||
this.logService.error('Eeprom parse error:', err);
|
||||
return [new ShowNotificationAction({
|
||||
type: NotificationType.Error,
|
||||
message: err.message
|
||||
})];
|
||||
}
|
||||
});
|
||||
|
||||
constructor(private actions$: Actions,
|
||||
@@ -147,4 +173,5 @@ export class UserConfigEffects {
|
||||
return config;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,11 +3,10 @@ import { compose } from '@ngrx/core/compose';
|
||||
import { ActionReducer, combineReducers } from '@ngrx/store';
|
||||
import { RouterState, routerReducer } from '@ngrx/router-store';
|
||||
import { storeFreeze } from 'ngrx-store-freeze';
|
||||
import { Keymap, UserConfiguration } from 'uhk-common';
|
||||
|
||||
import userConfigurationReducer from './reducers/user-configuration';
|
||||
import presetReducer from './reducers/preset';
|
||||
import { Keymap } from '../config-serializer/config-items/keymap';
|
||||
import { UserConfiguration } from '../config-serializer/config-items/user-configuration';
|
||||
import * as fromAppUpdate from './reducers/app-update.reducer';
|
||||
import * as autoUpdateSettings from './reducers/auto-update-settings';
|
||||
import * as fromApp from './reducers/app.reducer';
|
||||
@@ -53,6 +52,8 @@ export const showAddonMenu = createSelector(appState, fromApp.showAddonMenu);
|
||||
export const getUndoableNotification = createSelector(appState, fromApp.getUndoableNotification);
|
||||
export const getPrevUserConfiguration = createSelector(appState, fromApp.getPrevUserConfiguration);
|
||||
export const runningInElectron = createSelector(appState, fromApp.runningInElectron);
|
||||
export const getHardwareConfiguration = createSelector(appState, fromApp.getHardwareConfiguration);
|
||||
export const getKeyboardLayout = createSelector(appState, fromApp.getKeyboardLayout);
|
||||
|
||||
export const appUpdateState = (state: AppState) => state.appUpdate;
|
||||
export const getShowAppUpdateAvailable = createSelector(appUpdateState, fromAppUpdate.getShowAppUpdateAvailable);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { routerActions } from '@ngrx/router-store';
|
||||
import { Action } from '@ngrx/store';
|
||||
|
||||
import { runInElectron, Notification, NotificationType } from 'uhk-common';
|
||||
import { HardwareConfiguration, runInElectron, Notification, NotificationType, UserConfiguration } from 'uhk-common';
|
||||
import { ActionTypes, ShowNotificationAction } from '../actions/app';
|
||||
import { ActionTypes as UserConfigActionTypes } from '../actions/user-config';
|
||||
import { UserConfiguration } from '../../config-serializer/config-items/user-configuration';
|
||||
import { KeyboardLayout } from '../../keyboard/keyboard-layout.enum';
|
||||
|
||||
export interface State {
|
||||
started: boolean;
|
||||
@@ -13,7 +13,8 @@ export interface State {
|
||||
navigationCountAfterNotification: number;
|
||||
prevUserConfig?: UserConfiguration;
|
||||
runningInElectron: boolean;
|
||||
userConfigLoading: boolean;
|
||||
configLoading: boolean;
|
||||
hardwareConfig?: HardwareConfiguration;
|
||||
}
|
||||
|
||||
const initialState: State = {
|
||||
@@ -21,7 +22,7 @@ const initialState: State = {
|
||||
showAddonMenu: false,
|
||||
navigationCountAfterNotification: 0,
|
||||
runningInElectron: runInElectron(),
|
||||
userConfigLoading: true
|
||||
configLoading: true
|
||||
};
|
||||
|
||||
export function reducer(state = initialState, action: Action) {
|
||||
@@ -56,7 +57,7 @@ export function reducer(state = initialState, action: Action) {
|
||||
// When deleted a keymap or macro the app automaticaly navigate to other keymap, or macro, so
|
||||
// so we have to count the navigations and when reach the 2nd then remove the dialog.
|
||||
case routerActions.UPDATE_LOCATION: {
|
||||
const newState = { ...state };
|
||||
const newState = {...state};
|
||||
newState.navigationCountAfterNotification++;
|
||||
|
||||
if (newState.navigationCountAfterNotification > 1) {
|
||||
@@ -79,18 +80,24 @@ export function reducer(state = initialState, action: Action) {
|
||||
return {
|
||||
...state,
|
||||
prevUserConfig: action.payload,
|
||||
userConfigLoading: false
|
||||
configLoading: false
|
||||
};
|
||||
}
|
||||
|
||||
case UserConfigActionTypes.LOAD_USER_CONFIG_FROM_DEVICE:
|
||||
case UserConfigActionTypes.LOAD_CONFIG_FROM_DEVICE:
|
||||
case UserConfigActionTypes.LOAD_USER_CONFIG: {
|
||||
return {
|
||||
...state,
|
||||
userConfigLoading: true
|
||||
configLoading: true
|
||||
};
|
||||
}
|
||||
|
||||
case ActionTypes.LOAD_HARDWARE_CONFIGURATION_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
hardwareConfig: action.payload
|
||||
};
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
@@ -100,3 +107,11 @@ export const showAddonMenu = (state: State) => state.showAddonMenu;
|
||||
export const getUndoableNotification = (state: State) => state.undoableNotification;
|
||||
export const getPrevUserConfiguration = (state: State) => state.prevUserConfig;
|
||||
export const runningInElectron = (state: State) => state.runningInElectron;
|
||||
export const getHardwareConfiguration = (state: State) => state.hardwareConfig;
|
||||
export const getKeyboardLayout = (state: State): KeyboardLayout => {
|
||||
if (state.hardwareConfig && state.hardwareConfig.isIso) {
|
||||
return KeyboardLayout.ISO;
|
||||
}
|
||||
|
||||
return KeyboardLayout.ANSI;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Action } from '@ngrx/store';
|
||||
import { Keymap } from 'uhk-common';
|
||||
|
||||
import { Keymap } from '../../config-serializer/config-items/keymap';
|
||||
import { KeymapActions } from '../actions/keymap';
|
||||
|
||||
const initialState: Keymap[] = [];
|
||||
|
||||
@@ -5,12 +5,7 @@ import { Observable } from 'rxjs/Observable';
|
||||
import 'rxjs/add/observable/of';
|
||||
import 'rxjs/add/operator/map';
|
||||
|
||||
import { Helper as KeyActionHelper } from '../../config-serializer/config-items/key-action';
|
||||
import { Keymap } from '../../config-serializer/config-items/keymap';
|
||||
import { Macro } from '../../config-serializer/config-items/macro';
|
||||
import { UserConfiguration } from '../../config-serializer/config-items/user-configuration';
|
||||
import { Layer } from '../../config-serializer/config-items/layer';
|
||||
import { Module } from '../../config-serializer/config-items/module';
|
||||
import { Keymap, KeyActionHelper, Layer, Macro, Module, UserConfiguration } from 'uhk-common';
|
||||
import { KeymapActions, MacroActions } from '../actions';
|
||||
import { AppState } from '../index';
|
||||
import { ActionTypes } from '../actions/user-config';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as storage from 'electron-settings';
|
||||
|
||||
import { UserConfiguration } from '../../app/config-serializer/config-items/user-configuration';
|
||||
import { UserConfiguration } from 'uhk-common';
|
||||
import { DataStorageRepositoryService } from '../../app/services/datastorage-repository.service';
|
||||
import { AutoUpdateSettings } from '../../app/models/auto-update-settings';
|
||||
|
||||
|
||||
@@ -1,25 +1,19 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import * as log from 'electron-log';
|
||||
import * as util from 'util';
|
||||
|
||||
import { LogService } from 'uhk-common';
|
||||
|
||||
const transferRegExp = /USB\[T]:/;
|
||||
const writeRegExp = /USB\[W]:/;
|
||||
const readRegExp = /USB\[R]: 00/;
|
||||
const errorRegExp = /(?:(USB\[R]: ([^0]|0[^0])))/;
|
||||
import { LogService, LogRegExps } from 'uhk-common';
|
||||
|
||||
// https://github.com/megahertz/electron-log/issues/44
|
||||
// console.debug starting with Chromium 58 this method is a no-op on Chromium browsers.
|
||||
if (console.debug) {
|
||||
console.debug = (...args: any[]): void => {
|
||||
if (writeRegExp.test(args[0])) {
|
||||
if (LogRegExps.writeRegExp.test(args[0])) {
|
||||
console.log('%c' + args[0], 'color:blue');
|
||||
} else if (readRegExp.test(args[0])) {
|
||||
} else if (LogRegExps.readRegExp.test(args[0])) {
|
||||
console.log('%c' + args[0], 'color:green');
|
||||
} else if (errorRegExp.test(args[0])) {
|
||||
} else if (LogRegExps.errorRegExp.test(args[0])) {
|
||||
console.log('%c' + args[0], 'color:red');
|
||||
}else if (transferRegExp.test(args[0])) {
|
||||
}else if (LogRegExps.transferRegExp.test(args[0])) {
|
||||
console.log('%c' + args[0], 'color:orange');
|
||||
} else {
|
||||
console.log(...args);
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
import { LogService } from 'uhk-common';
|
||||
import { UhkDeviceService } from './uhk-device.service';
|
||||
import { UhkHidApiService } from './uhk-hid-api.service';
|
||||
|
||||
export function uhkDeviceFactory(logService: LogService): UhkDeviceService {
|
||||
// HID API officially support MAC, WIN and linux x64 platform
|
||||
// https://github.com/node-hid/node-hid#platform-support
|
||||
if (process.platform === 'darwin' ||
|
||||
process.platform === 'win32' ||
|
||||
(process.platform === 'linux' && process.arch === 'x64')) {
|
||||
return new UhkHidApiService(logService);
|
||||
}
|
||||
|
||||
// On other platform use libUsb, but we try to test on all platform
|
||||
// return new UhkLibUsbApiService(logService);
|
||||
return new UhkHidApiService(logService);
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
import { OnDestroy } from '@angular/core';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { Subject } from 'rxjs/Subject';
|
||||
import { Observer } from 'rxjs/Observer';
|
||||
import { Subscriber } from 'rxjs/Subscriber';
|
||||
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
|
||||
import { Constants, LogService } from 'uhk-common';
|
||||
import { SenderMessage } from '../models/sender-message';
|
||||
|
||||
enum Command {
|
||||
UploadConfig = 8,
|
||||
ApplyConfig = 9
|
||||
}
|
||||
|
||||
export abstract class UhkDeviceService implements OnDestroy {
|
||||
protected connected$: BehaviorSubject<boolean>;
|
||||
protected initialized$: BehaviorSubject<boolean>;
|
||||
protected deviceOpened$: BehaviorSubject<boolean>;
|
||||
protected outSubscription: Subscription;
|
||||
|
||||
protected messageIn$: Observable<Buffer>;
|
||||
protected messageOut$: Subject<SenderMessage>;
|
||||
|
||||
constructor(protected logService: LogService) {
|
||||
this.messageOut$ = new Subject<SenderMessage>();
|
||||
this.initialized$ = new BehaviorSubject(false);
|
||||
this.connected$ = new BehaviorSubject(false);
|
||||
this.deviceOpened$ = new BehaviorSubject(false);
|
||||
this.outSubscription = Subscription.EMPTY;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.disconnect();
|
||||
this.initialized$.unsubscribe();
|
||||
this.connected$.unsubscribe();
|
||||
this.deviceOpened$.unsubscribe();
|
||||
}
|
||||
|
||||
sendConfig(configBuffer: Buffer): Observable<Buffer> {
|
||||
return Observable.create((subscriber: Subscriber<Buffer>) => {
|
||||
this.logService.info('Sending...', configBuffer);
|
||||
const fragments: Buffer[] = [];
|
||||
const MAX_SENDING_PAYLOAD_SIZE = Constants.MAX_PAYLOAD_SIZE - 4;
|
||||
for (let offset = 0; offset < configBuffer.length; offset += MAX_SENDING_PAYLOAD_SIZE) {
|
||||
const length = offset + MAX_SENDING_PAYLOAD_SIZE < configBuffer.length
|
||||
? MAX_SENDING_PAYLOAD_SIZE
|
||||
: configBuffer.length - offset;
|
||||
const header = new Buffer([Command.UploadConfig, length, offset & 0xFF, offset >> 8]);
|
||||
fragments.push(Buffer.concat([header, configBuffer.slice(offset, offset + length)]));
|
||||
}
|
||||
|
||||
const buffers: Buffer[] = [];
|
||||
const observer: Observer<Buffer> = {
|
||||
next: (buffer: Buffer) => buffers.push(buffer),
|
||||
error: error => subscriber.error(error),
|
||||
complete: () => {
|
||||
if (buffers.length === fragments.length) {
|
||||
subscriber.next(Buffer.concat(buffers));
|
||||
subscriber.complete();
|
||||
this.logService.info('Sending finished');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fragments
|
||||
.map<SenderMessage>(fragment => ({ buffer: fragment, observer }))
|
||||
.forEach(senderPackage => this.messageOut$.next(senderPackage));
|
||||
});
|
||||
}
|
||||
|
||||
applyConfig(): Observable<Buffer> {
|
||||
return Observable.create((subscriber: Subscriber<Buffer>) => {
|
||||
this.logService.info('Applying configuration');
|
||||
this.messageOut$.next({
|
||||
buffer: new Buffer([Command.ApplyConfig]),
|
||||
observer: subscriber
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
isInitialized(): Observable<boolean> {
|
||||
return this.initialized$.asObservable();
|
||||
}
|
||||
|
||||
isConnected(): Observable<boolean> {
|
||||
return this.connected$.asObservable();
|
||||
}
|
||||
|
||||
isOpened(): Observable<boolean> {
|
||||
return this.deviceOpened$.asObservable();
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
this.outSubscription.unsubscribe();
|
||||
this.messageIn$ = undefined;
|
||||
this.initialized$.next(false);
|
||||
this.deviceOpened$.next(false);
|
||||
this.connected$.next(false);
|
||||
}
|
||||
|
||||
abstract initialize(): void;
|
||||
|
||||
abstract hasPermissions(): Observable<boolean>;
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
import { Injectable, OnDestroy } from '@angular/core';
|
||||
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { Subscriber } from 'rxjs/Subscriber';
|
||||
import { Device, devices, HID } from 'node-hid';
|
||||
|
||||
import 'rxjs/add/observable/empty';
|
||||
import 'rxjs/add/observable/interval';
|
||||
import 'rxjs/add/operator/catch';
|
||||
import 'rxjs/add/operator/concat';
|
||||
import 'rxjs/add/operator/combineLatest';
|
||||
import 'rxjs/add/operator/concatMap';
|
||||
import 'rxjs/add/operator/publish';
|
||||
import 'rxjs/add/operator/do';
|
||||
import 'rxjs/add/operator/startWith';
|
||||
import 'rxjs/add/operator/map';
|
||||
|
||||
import { Constants, LogService } from 'uhk-common';
|
||||
import { UhkDeviceService } from './uhk-device.service';
|
||||
|
||||
@Injectable()
|
||||
export class UhkHidApiService extends UhkDeviceService implements OnDestroy {
|
||||
private device: HID;
|
||||
|
||||
constructor(protected logService: LogService) {
|
||||
super(logService);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
super.ngOnDestroy();
|
||||
}
|
||||
|
||||
initialize(): void {
|
||||
if (this.initialized$.getValue()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.device = this.getDevice();
|
||||
if (!this.device) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.deviceOpened$.next(true);
|
||||
|
||||
this.messageIn$ = Observable.create((subscriber: Subscriber<Buffer>) => {
|
||||
this.logService.info('Try to read');
|
||||
this.device.read((error: any, data: any = []) => {
|
||||
if (error) {
|
||||
this.logService.error('reading error', error);
|
||||
subscriber.error(error);
|
||||
} else {
|
||||
this.logService.info('read data', data);
|
||||
subscriber.next(data);
|
||||
subscriber.complete();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const outSending = this.messageOut$.concatMap(senderPackage => {
|
||||
return (<Observable<void>>Observable.create((subscriber: Subscriber<void>) => {
|
||||
this.logService.info('transfering', senderPackage.buffer);
|
||||
const data = Array.prototype.slice.call(senderPackage.buffer, 0);
|
||||
// if data start with 0 need to add additional leading zero because HID API remove it.
|
||||
// https://github.com/node-hid/node-hid/issues/187
|
||||
if (data.length > 0 && data[0] === 0) {
|
||||
data.unshift(0);
|
||||
}
|
||||
|
||||
// From HID API documentation:
|
||||
// http://www.signal11.us/oss/hidapi/hidapi/doxygen/html/group__API.html#gad14ea48e440cf5066df87cc6488493af
|
||||
// The first byte of data[] must contain the Report ID.
|
||||
// For devices which only support a single report, this must be set to 0x0.
|
||||
data.unshift(0);
|
||||
|
||||
try {
|
||||
this.device.write(data);
|
||||
this.logService.info('transfering finished');
|
||||
subscriber.complete();
|
||||
}
|
||||
catch (error) {
|
||||
this.logService.error('transfering errored', error);
|
||||
subscriber.error(error);
|
||||
}
|
||||
})).concat(this.messageIn$)
|
||||
.do(buffer => senderPackage.observer.next(buffer) && senderPackage.observer.complete())
|
||||
.catch((error: string) => {
|
||||
senderPackage.observer.error(error);
|
||||
return Observable.empty<void>();
|
||||
});
|
||||
}).publish();
|
||||
this.outSubscription = outSending.connect();
|
||||
|
||||
this.initialized$.next(true);
|
||||
}
|
||||
|
||||
hasPermissions(): Observable<boolean> {
|
||||
return this.isConnected()
|
||||
.combineLatest(this.deviceOpened$)
|
||||
.map((latest: boolean[]) => {
|
||||
const connected = latest[0];
|
||||
const opened = latest[1];
|
||||
if (!connected) {
|
||||
return false;
|
||||
} else if (opened) {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the 0 interface of the keyboard.
|
||||
* @returns {HID}
|
||||
*/
|
||||
getDevice(): HID {
|
||||
try {
|
||||
const devs = devices();
|
||||
this.logService.info('Available devices:', devs);
|
||||
|
||||
const dev = devs.find((x: Device) =>
|
||||
x.vendorId === Constants.VENDOR_ID &&
|
||||
x.productId === Constants.PRODUCT_ID &&
|
||||
((x.usagePage === 128 && x.usage === 129) || x.interface === 0));
|
||||
|
||||
const device = new HID(dev.path);
|
||||
this.logService.info('Used device:', dev);
|
||||
return device;
|
||||
}
|
||||
catch (err) {
|
||||
this.logService.error('Can not create device:', err);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user