feat: make double tap to hold layer optional per key (#662)

* feat: make double tap to hold layer optional per key

* test: fix test serializer

* fix: remove "application start" text

* Add double-tap.svg

* Add closing dot at the end of the sentence.

* fead: add double-tap icon

* Bundle firmware version 8.3.0

* feat: 'layer-double-tap' feature flag

* feat: convert SwitchLayerMode to string enum
This commit is contained in:
Róbert Kiss
2018-06-07 22:11:41 +02:00
committed by László Monda
parent 81a83994ab
commit 4ae577f936
25 changed files with 1284 additions and 144 deletions

View File

@@ -4,9 +4,9 @@
"author": "Ultimate Gadget Laboratories",
"main": "electron/dist/electron-main.js",
"version": "1.2.2",
"firmwareVersion": "8.2.5",
"firmwareVersion": "8.3.0",
"deviceProtocolVersion": "4.3.1",
"userConfigVersion": "4.0.1",
"userConfigVersion": "4.1.0",
"hardwareConfigVersion": "1.0.0",
"description": "Agent is the configuration application of the Ultimate Hacking Keyboard.",
"repository": {

View File

@@ -21,7 +21,9 @@ import * as isDev from 'electron-is-dev';
const optionDefinitions = [
{name: 'addons', type: Boolean},
{name: 'spe', type: Boolean} // simulate privilege escalation error
{name: 'spe', type: Boolean}, // simulate privilege escalation error
// show 'Lock layer when double tapping this key' checkbox on 'Layer' tab of the config popover
{name: 'layer-double-tap', type: Boolean}
];
const options: CommandLineArgs = commandLineArgs(optionDefinitions);

View File

@@ -1,4 +1,4 @@
import { BrowserWindow, ipcMain, shell } from 'electron';
import { ipcMain, shell } from 'electron';
import { UhkHidDevice } from 'uhk-usb';
import { AppStartInfo, IpcEvents, LogService } from 'uhk-common';
@@ -25,7 +25,8 @@ export class AppService extends MainServiceBase {
const deviceConnectionState = this.uhkHidDeviceService.getDeviceConnectionState();
const response: AppStartInfo = {
commandLineArgs: {
addons: this.options.addons || false
addons: this.options.addons || false,
layerDoubleTap: this.options['layer-double-tap'] || false
},
deviceConnected: deviceConnectionState.connected,
hasPermission: deviceConnectionState.hasPermission,

View File

@@ -1,17 +1,18 @@
import { binaryDefaultHelper, jsonDefaultHelper } from '../../../../test/serializer-test-helper';
import { SwitchLayerAction } from './switch-layer-action';
import { SwitchLayerAction, SwitchLayerMode } from './switch-layer-action';
import { keyActionType } from './key-action';
// TODO: Add null, undefined, empty object, empty buffer test cases
describe('switch-layer-action', () => {
const action = new SwitchLayerAction(<SwitchLayerAction>{layer: 0, isLayerToggleable: false});
const action = new SwitchLayerAction(<SwitchLayerAction>{layer: 0, switchLayerMode: SwitchLayerMode.hold});
it('should be instantiate', () => {
expect(new SwitchLayerAction()).toBeTruthy();
});
describe('toString', () => {
it('should return <SwitchLayerAction layer="0" toggle="false">', () => {
expect(action.toString()).toEqual('<SwitchLayerAction layer="0" toggle="false">');
it('should return <SwitchLayerAction layer="0" switchLayerMode="hold">', () => {
expect(action.toString()).toEqual('<SwitchLayerAction layer="0" switchLayerMode="hold">');
});
});
@@ -30,4 +31,20 @@ describe('switch-layer-action', () => {
binaryDefaultHelper(action);
});
});
describe('backward compatibility of the "toggle" property ', () => {
it('should map toggle=false to SwitchLayerMode.holdAndDoubleTapToggle', () => {
const oldAction = new SwitchLayerAction();
oldAction.fromJsonObject({keyActionType: keyActionType.SwitchLayerAction, layer: 0, toggle: false});
expect(oldAction.switchLayerMode).toEqual(SwitchLayerMode.holdAndDoubleTapToggle);
});
it('should map toggle=true to SwitchLayerMode.toggle', () => {
const oldAction = new SwitchLayerAction();
oldAction.fromJsonObject({keyActionType: keyActionType.SwitchLayerAction, layer: 0, toggle: true});
expect(oldAction.switchLayerMode).toEqual(SwitchLayerMode.toggle);
});
});
});

View File

@@ -8,9 +8,16 @@ export enum LayerName {
mouse
}
export enum SwitchLayerMode {
holdAndDoubleTapToggle = 'holdAndDoubleTapToggle',
toggle = 'toggle',
hold = 'hold'
}
export class SwitchLayerAction extends KeyAction {
isLayerToggleable: boolean;
@assertEnum(SwitchLayerMode)
switchLayerMode: SwitchLayerMode;
@assertEnum(LayerName)
layer: LayerName;
@@ -20,21 +27,29 @@ export class SwitchLayerAction extends KeyAction {
if (!other) {
return;
}
this.isLayerToggleable = other.isLayerToggleable;
this.switchLayerMode = other.switchLayerMode;
this.layer = other.layer;
}
fromJsonObject(jsonObject: any): SwitchLayerAction {
this.assertKeyActionType(jsonObject);
this.layer = LayerName[<string>jsonObject.layer];
this.isLayerToggleable = jsonObject.toggle;
// Backward compatibility when "switchLayerMode" was a boolean type as "toggle"
if (typeof jsonObject.toggle === 'boolean') {
this.switchLayerMode = jsonObject.toggle ? SwitchLayerMode.toggle : SwitchLayerMode.holdAndDoubleTapToggle;
}
else {
this.switchLayerMode = jsonObject.switchLayerMode;
}
return this;
}
fromBinary(buffer: UhkBuffer): SwitchLayerAction {
this.readAndAssertKeyActionId(buffer);
this.layer = buffer.readUInt8();
this.isLayerToggleable = buffer.readBoolean();
this.switchLayerMode = mapNumberToSwitchLayerMode(buffer.readUInt8());
return this;
}
@@ -42,21 +57,53 @@ export class SwitchLayerAction extends KeyAction {
return {
keyActionType: keyActionType.SwitchLayerAction,
layer: LayerName[this.layer],
toggle: this.isLayerToggleable
switchLayerMode: this.switchLayerMode
};
}
toBinary(buffer: UhkBuffer) {
buffer.writeUInt8(KeyActionId.SwitchLayerAction);
buffer.writeUInt8(this.layer);
buffer.writeBoolean(this.isLayerToggleable);
buffer.writeUInt8(mapSwitchLayerModeToNumber(this.switchLayerMode));
}
toString(): string {
return `<SwitchLayerAction layer="${this.layer}" toggle="${this.isLayerToggleable}">`;
return `<SwitchLayerAction layer="${this.layer}" switchLayerMode="${this.switchLayerMode}">`;
}
public getName(): string {
return 'SwitchLayerAction';
}
}
export const mapSwitchLayerModeToNumber = (switchLayerMode: SwitchLayerMode): number => {
switch (switchLayerMode) {
case SwitchLayerMode.holdAndDoubleTapToggle:
return 0;
case SwitchLayerMode.toggle:
return 1;
case SwitchLayerMode.hold:
return 2;
default:
throw new Error(`Can not map ${switchLayerMode} to number`);
}
};
export const mapNumberToSwitchLayerMode = (value: number): SwitchLayerMode => {
switch (value) {
case 0:
return SwitchLayerMode.holdAndDoubleTapToggle;
case 1:
return SwitchLayerMode.toggle;
case 2:
return SwitchLayerMode.hold;
default:
throw new Error(`Can not map "${value}" to SwitchLayerMode`);
}
};

View File

@@ -127,7 +127,7 @@ export class Keymap {
if (currentLayerId - 1 === baseKeyAction.layer) {
if (currentKeyAction instanceof SwitchLayerAction) {
if (currentKeyAction.layer === baseKeyAction.layer &&
currentKeyAction.isLayerToggleable === baseKeyAction.isLayerToggleable) {
currentKeyAction.switchLayerMode === baseKeyAction.switchLayerMode) {
continue;
}
// tslint:disable-next-line: max-line-length

View File

@@ -109,7 +109,7 @@ describe('keymap', () => {
{
keyActionType: 'switchLayer',
layer: 'mod',
toggle: false
switchLayerMode: 'holdAndDoubleTapToggle'
}
]
}]
@@ -121,7 +121,7 @@ describe('keymap', () => {
{
keyActionType: 'switchLayer',
layer: 'mod',
toggle: false
switchLayerMode: 'holdAndDoubleTapToggle'
}
]
}]
@@ -151,7 +151,7 @@ describe('keymap', () => {
expect(inputUserConfig.toJsonObject()).toEqual(expectedJsonConfig);
// tslint:disable-next-line: max-line-length
expect(console.warn).toHaveBeenCalledWith('QWERTY.layers[1]modules[0].keyActions[0] is not switch layer. <KeystrokeAction type="basic" scancode="44"> will be override with <SwitchLayerAction layer="0" toggle="false">');
expect(console.warn).toHaveBeenCalledWith('QWERTY.layers[1]modules[0].keyActions[0] is not switch layer. <KeystrokeAction type="basic" scancode="44"> will be override with <SwitchLayerAction layer="0" switchLayerMode="holdAndDoubleTapToggle">');
});
it('should normalize SwitchLayerAction if non base layer action is other SwitchLayerAction', () => {
@@ -262,7 +262,7 @@ describe('keymap', () => {
{
keyActionType: 'switchLayer',
layer: 'mod',
toggle: false
switchLayerMode: 'holdAndDoubleTapToggle'
}
]
}]
@@ -274,7 +274,7 @@ describe('keymap', () => {
{
keyActionType: 'switchLayer',
layer: 'mod',
toggle: false
switchLayerMode: 'holdAndDoubleTapToggle'
}
]
}]
@@ -304,6 +304,6 @@ describe('keymap', () => {
expect(inputUserConfig.toJsonObject()).toEqual(expectedJsonConfig);
// tslint:disable-next-line: max-line-length
expect(console.warn).toHaveBeenCalledWith('QWERTY.layers[1]modules[0].keyActions[0] is different switch layer. <SwitchLayerAction layer="1" toggle="false"> will be override with <SwitchLayerAction layer="0" toggle="false">');
expect(console.warn).toHaveBeenCalledWith('QWERTY.layers[1]modules[0].keyActions[0] is different switch layer. <SwitchLayerAction layer="1" switchLayerMode="holdAndDoubleTapToggle"> will be override with <SwitchLayerAction layer="0" switchLayerMode="holdAndDoubleTapToggle">');
});
});

View File

@@ -7,4 +7,9 @@ export interface CommandLineArgs {
* simulate privilege escalation error
*/
spe?: boolean;
/**
* show 'Lock layer when double tapping this key' checkbox on 'Layer' tab of the config popover
* if it false the checkbox invisible and the value of the checkbox = true
*/
layerDoubleTap?: boolean;
}

View File

@@ -5,6 +5,7 @@
<svg-keyboard-wrap [keymap]="keymap$ | async"
[halvesSplit]="keyboardSplit"
[keyboardLayout]="keyboardLayout$ | async"
[allowLayerDoubleTap]="allowLayerDoubleTap$ | async"
(descriptionChanged)="descriptionChanged($event)"></svg-keyboard-wrap>
</ng-template>

View File

@@ -1,4 +1,4 @@
import { Component, HostListener, ViewChild } from '@angular/core';
import { Component, HostListener } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Store } from '@ngrx/store';
import { Keymap } from 'uhk-common';
@@ -14,9 +14,8 @@ import 'rxjs/add/operator/combineLatest';
import { saveAs } from 'file-saver';
import { AppState, getKeyboardLayout } from '../../../store';
import { allowLayerDoubleTap, AppState, getKeyboardLayout } from '../../../store';
import { getKeymap, getKeymaps, getUserConfiguration } from '../../../store/reducers/user-configuration';
import { SvgKeyboardWrapComponent } from '../../svg/wrap';
import { KeyboardLayout } from '../../../keyboard/keyboard-layout.enum';
import { KeymapActions } from '../../../store/actions';
import { ChangeKeymapDescription } from '../../../models/ChangeKeymapDescription';
@@ -31,13 +30,12 @@ import { ChangeKeymapDescription } from '../../../models/ChangeKeymapDescription
})
export class KeymapEditComponent {
@ViewChild(SvgKeyboardWrapComponent) wrap: SvgKeyboardWrapComponent;
keyboardSplit: boolean;
deletable$: Observable<boolean>;
keymap$: Observable<Keymap>;
keyboardLayout$: Observable<KeyboardLayout>;
allowLayerDoubleTap$: Observable<boolean>;
constructor(protected store: Store<AppState>,
route: ActivatedRoute) {
@@ -52,6 +50,7 @@ export class KeymapEditComponent {
.map((keymaps: Keymap[]) => keymaps.length > 1);
this.keyboardLayout$ = store.select(getKeyboardLayout);
this.allowLayerDoubleTap$ = store.select(allowLayerDoubleTap);
}
downloadKeymap() {

View File

@@ -55,6 +55,7 @@
<layer-tab #tab *ngSwitchCase="tabName.Layer" class="popover-content"
[defaultKeyAction]="defaultKeyAction"
[currentLayer]="currentLayer"
[allowLayerDoubleTap]="allowLayerDoubleTap"
(validAction)="keyActionValid=$event"
></layer-tab>
<mouse-tab #tab *ngSwitchCase="tabName.Mouse" class="popover-content"

View File

@@ -27,7 +27,7 @@ import {
SwitchLayerAction
} from 'uhk-common';
import { Tab } from './tab/tab';
import { Tab } from './tab';
import { AppState } from '../../store';
import { getKeymaps } from '../../store/reducers/user-configuration';
@@ -82,6 +82,7 @@ export class PopoverComponent implements OnChanges {
@Input() keyPosition: any;
@Input() wrapPosition: any;
@Input() visible: boolean;
@Input() allowLayerDoubleTap: boolean;
@Output() cancel = new EventEmitter<any>();
@Output() remap = new EventEmitter<KeyAction>();

View File

@@ -1,4 +1,6 @@
<ng-template [ngIf]="!isNotBase">
<div>
<div>
<select (change)="toggleChanged($event.target.value)">
<option *ngFor="let item of toggleData" [value]="item.id" [selected]="toggle === item.id">
{{ item.text }}
@@ -11,9 +13,19 @@
</option>
</select>
<span [ngSwitch]="toggle">
<ng-template [ngSwitchCase]="true">layer by tapping this key.</ng-template>
<ng-template [ngSwitchCase]="'toggle'">layer by tapping this key.</ng-template>
<ng-template ngSwitchDefault>layer by holding this key.</ng-template>
</span>
</div>
<div *ngIf="toggle === 'active' && allowLayerDoubleTap">
<div class="checkbox">
<label>
<input type="checkbox"
[(ngModel)]="lockLayerWhenDoubleTapping"> Lock layer when double tapping this key.
</label>
</div>
</div>
</div>
</ng-template>
<ng-template [ngIf]="isNotBase">
<span> Layer switching is only possible from the base layer. </span>

View File

@@ -1,8 +1,10 @@
import { Component, HostBinding, Input, OnChanges, SimpleChanges } from '@angular/core';
import { KeyAction, LayerName, SwitchLayerAction } from 'uhk-common';
import { KeyAction, LayerName, SwitchLayerAction, SwitchLayerMode } from 'uhk-common';
import { Tab } from '../tab';
export type toggleType = 'active' | 'toggle';
@Component({
selector: 'layer-tab',
templateUrl: './layer-tab.component.html',
@@ -11,16 +13,17 @@ import { Tab } from '../tab';
export class LayerTabComponent extends Tab implements OnChanges {
@Input() defaultKeyAction: KeyAction;
@Input() currentLayer: number;
@Input() allowLayerDoubleTap: boolean;
@HostBinding('class.no-base') isNotBase: boolean;
toggleData: { id: boolean, text: string }[] = [
toggleData: { id: toggleType, text: string }[] = [
{
id: false,
id: 'active',
text: 'Activate'
},
{
id: true,
id: 'toggle',
text: 'Toggle'
}
];
@@ -40,12 +43,13 @@ export class LayerTabComponent extends Tab implements OnChanges {
}
];
toggle: boolean;
toggle: toggleType;
layer: LayerName;
lockLayerWhenDoubleTapping: boolean;
constructor() {
super();
this.toggle = false;
this.toggle = 'active';
this.layer = LayerName.mod;
}
@@ -71,14 +75,39 @@ export class LayerTabComponent extends Tab implements OnChanges {
}
const switchLayerAction: SwitchLayerAction = <SwitchLayerAction>keyAction;
this.toggle = switchLayerAction.isLayerToggleable;
switch (switchLayerAction.switchLayerMode) {
case SwitchLayerMode.holdAndDoubleTapToggle: {
this.toggle = 'active';
this.lockLayerWhenDoubleTapping = true;
break;
}
case SwitchLayerMode.hold: {
this.toggle = 'active';
this.lockLayerWhenDoubleTapping = false;
break;
}
default: {
this.toggle = 'toggle';
this.lockLayerWhenDoubleTapping = false;
}
}
this.layer = switchLayerAction.layer;
return true;
}
toKeyAction(): SwitchLayerAction {
const keyAction = new SwitchLayerAction();
keyAction.isLayerToggleable = this.toggle;
if (this.toggle === 'toggle') {
keyAction.switchLayerMode = SwitchLayerMode.toggle;
} else if (!this.allowLayerDoubleTap || this.lockLayerWhenDoubleTapping) {
keyAction.switchLayerMode = SwitchLayerMode.holdAndDoubleTapToggle;
} else {
keyAction.switchLayerMode = SwitchLayerMode.hold;
}
keyAction.layer = this.layer;
if (!this.keyActionValid()) {
throw new Error('KeyAction is invalid!');
@@ -86,8 +115,8 @@ export class LayerTabComponent extends Tab implements OnChanges {
return keyAction;
}
toggleChanged(value: string) {
this.toggle = value === 'true';
toggleChanged(value: toggleType) {
this.toggle = value;
}
layerChanged(value: number) {

View File

@@ -17,13 +17,14 @@ import {
MouseAction,
PlayMacroAction,
SwitchKeymapAction,
SwitchLayerAction
SwitchLayerAction,
SwitchLayerMode
} from 'uhk-common';
import { CaptureService } from '../../../../services/capture.service';
import { MapperService } from '../../../../services/mapper.service';
import { AppState } from '../../../../store/index';
import { AppState } from '../../../../store';
import { getMacros } from '../../../../store/reducers/user-configuration';
enum LabelTypes {
@@ -288,12 +289,18 @@ export class SvgKeyboardKeyComponent implements OnInit, OnChanges, OnDestroy {
break;
}
if (keyAction.isLayerToggleable) {
if (keyAction.switchLayerMode === SwitchLayerMode.toggle) {
this.labelType = LabelTypes.TextIcon;
this.labelSource = {
text: newLabelSource,
icon: this.mapper.getIcon('toggle')
};
} else if (keyAction.switchLayerMode === SwitchLayerMode.holdAndDoubleTapToggle) {
this.labelType = LabelTypes.TextIcon;
this.labelSource = {
text: newLabelSource,
icon: this.mapper.getIcon('double-tap')
};
} else {
this.labelType = LabelTypes.OneLineText;
this.labelSource = newLabelSource;

View File

@@ -13,8 +13,18 @@
(capture)="onCapture($event.moduleId, $event.keyId, $event.captured)"
(descriptionChanged)="onDescriptionChanged($event)"
></keyboard-slider>
<popover tabindex="0" [visible]="popoverShown" [keyPosition]="keyPosition" [wrapPosition]="wrapPosition" [defaultKeyAction]="popoverInitKeyAction"
[currentKeymap]="keymap" [currentLayer]="currentLayer" (cancel)="hidePopover()" (remap)="onRemap($event)"></popover>
<popover tabindex="0"
[visible]="popoverShown"
[keyPosition]="keyPosition"
[wrapPosition]="wrapPosition"
[defaultKeyAction]="popoverInitKeyAction"
[currentKeymap]="keymap"
[currentLayer]="currentLayer"
[allowLayerDoubleTap]="allowLayerDoubleTap"
(cancel)="hidePopover()"
(remap)="onRemap($event)"></popover>
<div class="tooltip bottom"
[class.in]="tooltipData.show"
[style.top.px]="tooltipData.posTop"

View File

@@ -32,7 +32,8 @@ import {
PlayMacroAction,
SecondaryRoleAction,
SwitchKeymapAction,
SwitchLayerAction
SwitchLayerAction,
SwitchLayerMode
} from 'uhk-common';
import { MapperService } from '../../../services/mapper.service';
@@ -59,6 +60,8 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges {
@Input() tooltipEnabled: boolean = false;
@Input() halvesSplit: boolean;
@Input() keyboardLayout: KeyboardLayout.ANSI;
@Input() allowLayerDoubleTap: boolean;
@Output() descriptionChanged = new EventEmitter<ChangeKeymapDescription>();
@ViewChild(PopoverComponent, { read: ElementRef }) popover: ElementRef;
@@ -350,7 +353,7 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges {
},
{
name: 'Toogle',
value: switchLayerAction.isLayerToggleable ? 'On' : 'Off'
value: switchLayerAction.switchLayerMode === SwitchLayerMode.toggle ? 'On' : 'Off'
}
];
return Observable.of(content);

View File

@@ -262,6 +262,7 @@ export class MapperService {
private initNameToFileNames(): void {
this.nameToFileName = new Map<string, string>();
this.nameToFileName.set('toggle', 'icon-kbd__fn--toggle');
this.nameToFileName.set('double-tap', 'icon-kbd__fn--double-tap');
this.nameToFileName.set('switch-keymap', 'icon-kbd__mod--switch-keymap');
this.nameToFileName.set('macro', 'icon-icon__macro');
this.nameToFileName.set('shift', 'icon-kbd__default--modifier-shift');

View File

@@ -179,12 +179,12 @@
{
"keyActionType": "switchLayer",
"layer": "mod",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "switchLayer",
"layer": "fn",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "keystroke",
@@ -275,7 +275,7 @@
{
"keyActionType": "switchLayer",
"layer": "mouse",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "keystroke",
@@ -356,7 +356,7 @@
{
"keyActionType": "switchLayer",
"layer": "fn",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "keystroke",
@@ -366,7 +366,7 @@
{
"keyActionType": "switchLayer",
"layer": "mod",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null
]
@@ -507,7 +507,7 @@
{
"keyActionType": "switchLayer",
"layer": "mod",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null,
{
@@ -654,7 +654,7 @@
{
"keyActionType": "switchLayer",
"layer": "mod",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null
]
@@ -732,7 +732,7 @@
{
"keyActionType": "switchLayer",
"layer": "fn",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "keystroke",
@@ -819,7 +819,7 @@
{
"keyActionType": "switchLayer",
"layer": "fn",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null,
null,
@@ -941,7 +941,7 @@
{
"keyActionType": "switchLayer",
"layer": "mouse",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null,
{
@@ -1156,12 +1156,12 @@
{
"keyActionType": "switchLayer",
"layer": "mod",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "switchLayer",
"layer": "fn",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "keystroke",
@@ -1252,7 +1252,7 @@
{
"keyActionType": "switchLayer",
"layer": "mouse",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "keystroke",
@@ -1333,7 +1333,7 @@
{
"keyActionType": "switchLayer",
"layer": "fn",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "keystroke",
@@ -1343,7 +1343,7 @@
{
"keyActionType": "switchLayer",
"layer": "mod",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null
]
@@ -1484,7 +1484,7 @@
{
"keyActionType": "switchLayer",
"layer": "mod",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null,
{
@@ -1641,7 +1641,7 @@
{
"keyActionType": "switchLayer",
"layer": "mod",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null
]
@@ -1719,7 +1719,7 @@
{
"keyActionType": "switchLayer",
"layer": "fn",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "keystroke",
@@ -1806,7 +1806,7 @@
{
"keyActionType": "switchLayer",
"layer": "fn",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null,
null,
@@ -1928,7 +1928,7 @@
{
"keyActionType": "switchLayer",
"layer": "mouse",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null,
{
@@ -2143,12 +2143,12 @@
{
"keyActionType": "switchLayer",
"layer": "mod",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "switchLayer",
"layer": "fn",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "keystroke",
@@ -2239,7 +2239,7 @@
{
"keyActionType": "switchLayer",
"layer": "mouse",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "keystroke",
@@ -2320,7 +2320,7 @@
{
"keyActionType": "switchLayer",
"layer": "fn",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "keystroke",
@@ -2330,7 +2330,7 @@
{
"keyActionType": "switchLayer",
"layer": "mod",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null
]
@@ -2471,7 +2471,7 @@
{
"keyActionType": "switchLayer",
"layer": "mod",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null,
{
@@ -2618,7 +2618,7 @@
{
"keyActionType": "switchLayer",
"layer": "mod",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null
]
@@ -2696,7 +2696,7 @@
{
"keyActionType": "switchLayer",
"layer": "fn",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "keystroke",
@@ -2783,7 +2783,7 @@
{
"keyActionType": "switchLayer",
"layer": "fn",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null,
null,
@@ -2902,7 +2902,7 @@
{
"keyActionType": "switchLayer",
"layer": "mouse",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null,
{
@@ -3117,12 +3117,12 @@
{
"keyActionType": "switchLayer",
"layer": "mod",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "switchLayer",
"layer": "fn",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "keystroke",
@@ -3213,7 +3213,7 @@
{
"keyActionType": "switchLayer",
"layer": "mouse",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "keystroke",
@@ -3294,7 +3294,7 @@
{
"keyActionType": "switchLayer",
"layer": "fn",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "keystroke",
@@ -3304,7 +3304,7 @@
{
"keyActionType": "switchLayer",
"layer": "mod",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null
]
@@ -3445,7 +3445,7 @@
{
"keyActionType": "switchLayer",
"layer": "mod",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null,
{
@@ -3602,7 +3602,7 @@
{
"keyActionType": "switchLayer",
"layer": "mod",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null
]
@@ -3680,7 +3680,7 @@
{
"keyActionType": "switchLayer",
"layer": "fn",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "keystroke",
@@ -3767,7 +3767,7 @@
{
"keyActionType": "switchLayer",
"layer": "fn",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null,
null,
@@ -3886,7 +3886,7 @@
{
"keyActionType": "switchLayer",
"layer": "mouse",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null,
{
@@ -4101,12 +4101,12 @@
{
"keyActionType": "switchLayer",
"layer": "mod",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "switchLayer",
"layer": "fn",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "keystroke",
@@ -4197,7 +4197,7 @@
{
"keyActionType": "switchLayer",
"layer": "mouse",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "keystroke",
@@ -4278,7 +4278,7 @@
{
"keyActionType": "switchLayer",
"layer": "fn",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "keystroke",
@@ -4288,7 +4288,7 @@
{
"keyActionType": "switchLayer",
"layer": "mod",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null
]
@@ -4429,7 +4429,7 @@
{
"keyActionType": "switchLayer",
"layer": "mod",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null,
{
@@ -4576,7 +4576,7 @@
{
"keyActionType": "switchLayer",
"layer": "mod",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null
]
@@ -4654,7 +4654,7 @@
{
"keyActionType": "switchLayer",
"layer": "fn",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "keystroke",
@@ -4741,7 +4741,7 @@
{
"keyActionType": "switchLayer",
"layer": "fn",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null,
null,
@@ -4854,7 +4854,7 @@
{
"keyActionType": "switchLayer",
"layer": "mouse",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null,
{
@@ -5069,12 +5069,12 @@
{
"keyActionType": "switchLayer",
"layer": "mod",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "switchLayer",
"layer": "fn",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "keystroke",
@@ -5165,7 +5165,7 @@
{
"keyActionType": "switchLayer",
"layer": "mouse",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "keystroke",
@@ -5246,7 +5246,7 @@
{
"keyActionType": "switchLayer",
"layer": "fn",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "keystroke",
@@ -5256,7 +5256,7 @@
{
"keyActionType": "switchLayer",
"layer": "mod",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null
]
@@ -5397,7 +5397,7 @@
{
"keyActionType": "switchLayer",
"layer": "mod",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null,
{
@@ -5554,7 +5554,7 @@
{
"keyActionType": "switchLayer",
"layer": "mod",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null
]
@@ -5635,7 +5635,7 @@
{
"keyActionType": "switchLayer",
"layer": "fn",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
{
"keyActionType": "keystroke",
@@ -5722,7 +5722,7 @@
{
"keyActionType": "switchLayer",
"layer": "fn",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null,
null,
@@ -5835,7 +5835,7 @@
{
"keyActionType": "switchLayer",
"layer": "mouse",
"toggle": false
"switchLayerMode": "holdAndDoubleTapToggle"
},
null,
{

View File

@@ -44,6 +44,7 @@ export const getUserConfiguration = (state: AppState) => state.userConfiguration
export const appState = (state: AppState) => state.app;
export const showAddonMenu = createSelector(appState, fromApp.showAddonMenu);
export const allowLayerDoubleTap = createSelector(appState, fromApp.allowLayerDoubleTap);
export const getUndoableNotification = createSelector(appState, fromApp.getUndoableNotification);
export const getPrevUserConfiguration = createSelector(appState, fromApp.getPrevUserConfiguration);
export const runningInElectron = createSelector(appState, fromApp.runningInElectron);

View File

@@ -1,6 +1,7 @@
import { ROUTER_NAVIGATION } from '@ngrx/router-store';
import { Action } from '@ngrx/store';
import {
CommandLineArgs,
HardwareConfiguration,
Notification,
NotificationType,
@@ -18,7 +19,7 @@ import { PrivilagePageSate } from '../../models/privilage-page-sate';
export interface State {
started: boolean;
showAddonMenu: boolean;
commandLineArgs: CommandLineArgs;
undoableNotification?: Notification;
navigationCountAfterNotification: number;
prevUserConfig?: UserConfiguration;
@@ -32,7 +33,7 @@ export interface State {
export const initialState: State = {
started: false,
showAddonMenu: false,
commandLineArgs: {},
navigationCountAfterNotification: 0,
runningInElectron: runInElectron(),
configLoading: true,
@@ -52,7 +53,7 @@ export function reducer(state = initialState, action: Action & { payload: any })
case ActionTypes.APPLY_COMMAND_LINE_ARGS: {
return {
...state,
showAddonMenu: action.payload.addons
commandLineArgs: action.payload
};
}
@@ -148,7 +149,8 @@ export function reducer(state = initialState, action: Action & { payload: any })
}
}
export const showAddonMenu = (state: State) => state.showAddonMenu;
export const showAddonMenu = (state: State) => state.commandLineArgs.addons;
export const allowLayerDoubleTap = (state: State) => state.commandLineArgs.layerDoubleTap;
export const getUndoableNotification = (state: State) => state.undoableNotification;
export const getPrevUserConfiguration = (state: State) => state.prevUserConfig;
export const runningInElectron = (state: State) => state.runningInElectron;

View File

@@ -1,5 +1,13 @@
import { reducer, initialState } from './user-configuration';
import { KeystrokeAction, KeystrokeType, SwitchLayerAction, UserConfiguration, LayerName, Keymap } from 'uhk-common';
import {
KeystrokeAction,
KeystrokeType,
SwitchLayerAction,
UserConfiguration,
LayerName,
Keymap,
SwitchLayerMode
} from 'uhk-common';
import { getDefaultUserConfig } from '../../../../test/user-config-helper';
import { KeymapActions } from '../actions';
@@ -42,7 +50,11 @@ describe('user-configuration reducer', () => {
const defaultUserConfig = new UserConfiguration().fromJsonObject(getDefaultUserConfig());
const state = new UserConfiguration().fromJsonObject(getDefaultUserConfig());
const destinationLayerId = LayerName.mod;
const switchLayerAction = new SwitchLayerAction({isLayerToggleable: false, layer: destinationLayerId} as any);
const switchLayerAction = new SwitchLayerAction({
switchLayerMode: SwitchLayerMode.toggle,
layer: destinationLayerId
} as any);
const saveKeyAction: KeymapActions.SaveKeyAction = {
type: KeymapActions.SAVE_KEY,
payload: {
@@ -81,7 +93,7 @@ describe('user-configuration reducer', () => {
{
keyActionType: 'switchLayer',
layer: 'mod',
toggle: false
switchLayerMode: 1
},
{
keyActionType: 'keystroke',
@@ -89,9 +101,9 @@ describe('user-configuration reducer', () => {
scancode: 37
},
{
'keyActionType': 'switchLayer',
'layer': 'mod',
'toggle': false
keyActionType: 'switchLayer',
layer: 'mod',
switchLayerMode: 1
}
]
},
@@ -128,7 +140,7 @@ describe('user-configuration reducer', () => {
{
keyActionType: 'switchLayer',
layer: 'mod',
toggle: false
switchLayerMode: 1
},
{
keyActionType: 'keystroke',
@@ -136,9 +148,9 @@ describe('user-configuration reducer', () => {
scancode: 65
},
{
'keyActionType': 'switchLayer',
'layer': 'mod',
'toggle': false
keyActionType: 'switchLayer',
layer: 'mod',
switchLayerMode: 1
}
]
},
@@ -219,7 +231,11 @@ describe('user-configuration reducer', () => {
const defaultUserConfig = new UserConfiguration().fromJsonObject(getDefaultUserConfig());
const state = new UserConfiguration().fromJsonObject(getDefaultUserConfig());
const destinationLayerId = LayerName.fn;
const switchLayerAction = new SwitchLayerAction({isLayerToggleable: false, layer: destinationLayerId} as any);
const switchLayerAction = new SwitchLayerAction({
switchLayerMode: SwitchLayerMode.toggle,
layer: destinationLayerId
} as any);
const saveKeyAction: KeymapActions.SaveKeyAction = {
type: KeymapActions.SAVE_KEY,
payload: {
@@ -266,9 +282,9 @@ describe('user-configuration reducer', () => {
scancode: 37
},
{
'keyActionType': 'switchLayer',
'layer': 'fn',
'toggle': false
keyActionType: 'switchLayer',
layer: 'fn',
switchLayerMode: 1
}
]
},
@@ -345,7 +361,7 @@ describe('user-configuration reducer', () => {
{
keyActionType: 'switchLayer',
layer: 'fn',
toggle: false
switchLayerMode: 1
}
]
},

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 88 KiB

View File

@@ -1 +1 @@
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="31" height="16" viewBox="0 0 31 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><svg width="16" height="16" viewBox="0 0 16 16" id="icon-0401-usb-stick" xmlns="http://www.w3.org/2000/svg"><path d="M6.5 2a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 1 0v-1a.5.5 0 0 0-.5-.5zM8.5 2a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 1 0v-1a.5.5 0 0 0-.5-.5z"/><path d="M11.5 5H11V.5a.5.5 0 0 0-.5-.5h-6a.5.5 0 0 0-.5.5V5h-.5a.5.5 0 0 0-.5.5v9.375c1 1.5 8 1.5 9 0V5.5a.5.5 0 0 0-.5-.5zM5 13.5a.5.5 0 0 1-1 0v-6a.5.5 0 0 1 1 0v6zM10 5H5V1h5v4z"/></svg><svg width="15" height="15" viewBox="0 0 15 15" id="icon-agent-icon" x="16" xmlns="http://www.w3.org/2000/svg"><path fill="#333" d="M3 0C1.338 0 0 1.338 0 3v9c0 1.662 1.338 3 3 3h9c1.662 0 3-1.338 3-3V3c0-1.662-1.338-3-3-3H3zM1.375 3.75a.36.36 0 0 1 .125 0H6c.375 0 .75.375.75.375s.375.375.75.375.75-.375.75-.375.375-.375.75-.375h4.5c.75 0 .75.75.75.75V6c0 2.25-1.5 2.25-1.5 2.25H9c-.375 0-.75-1.125-.75-1.125S7.875 6 7.5 6s-.75 1.125-.75 1.125S6.375 8.25 6 8.25H2.25S.75 8.25.75 6V4.5c0-.562.414-.715.625-.75z"/></svg></svg>
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="31" height="16" viewBox="0 0 31 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><svg width="16" height="16" viewBox="0 0 16 16" id="icon-0401-usb-stick" xmlns="http://www.w3.org/2000/svg"><path d="M6.5 2a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 1 0v-1a.5.5 0 0 0-.5-.5zM8.5 2a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 1 0v-1a.5.5 0 0 0-.5-.5z"/><path d="M11.5 5H11V.5a.5.5 0 0 0-.5-.5h-6a.5.5 0 0 0-.5.5V5h-.5a.5.5 0 0 0-.5.5v9.375c1 1.5 8 1.5 9 0V5.5a.5.5 0 0 0-.5-.5zM5 13.5a.5.5 0 0 1-1 0v-6a.5.5 0 0 1 1 0v6zM10 5H5V1h5v4z"/></svg><svg width="15" height="15" viewBox="0 0 15 15" id="icon-agent-icon" x="16" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(12 0 0 -12 0 6)" id="abb"><stop offset="0" stop-color="#85878d"/><stop offset=".001" stop-color="#85878d"/><stop offset=".001" stop-color="#5d5f63"/><stop offset=".526" stop-color="#ccc"/><stop offset="1" stop-color="#5d5c62"/></linearGradient><linearGradient id="aba" gradientTransform="matrix(12 0 0 -12 0 6)" gradientUnits="userSpaceOnUse" x2="1"><stop offset="0" stop-color="#85878d"/><stop offset=".001" stop-color="#85878d"/><stop offset=".001" stop-color="#85878d"/><stop offset=".495" stop-color="#ccc"/><stop offset="1" stop-color="#5d5c62"/></linearGradient><clipPath id="abc"><path d="M2.398 12A2.393 2.393 0 0 1 0 9.602V2.398A2.393 2.393 0 0 1 2.398 0h7.203A2.394 2.394 0 0 1 12 2.398v7.204A2.394 2.394 0 0 1 9.601 12H2.398zM.602 7.199v1.199c0 .454.329.575.5.602.054.008.097 0 .097 0h3.602c.301 0 .597-.301.597-.301s.301-.301.602-.301.602.301.602.301.296.301.597.301h3.602c.597 0 .597-.602.597-.602V7.199c0-1.801-1.199-1.801-1.199-1.801h-3c-.301 0-.597.903-.597.903s-.301.898-.602.898-.602-.898-.602-.898-.296-.903-.597-.903h-3s-1.199 0-1.199 1.801"/></clipPath><linearGradient gradientUnits="userSpaceOnUse" x2="11.746" y1="11.542" x1=".915" id="abd" xlink:href="#aba"/><linearGradient y2="-.051" x2="12" y1="11.898" x1=".102" gradientUnits="userSpaceOnUse" id="abe" xlink:href="#abb"/></defs><g transform="matrix(1.25 0 0 -1.25 0 15)"><path d="M11.473 5.117H.416v4.266h11.057V5.117z" fill="#343434"/><g clip-path="url(#abc)" fill="url(#abd)"><path d="M2.398 12A2.393 2.393 0 0 1 0 9.602V2.398A2.393 2.393 0 0 1 2.398 0h7.203A2.394 2.394 0 0 1 12 2.398v7.204A2.394 2.394 0 0 1 9.601 12H2.398zM.602 7.199v1.199c0 .454.329.575.5.602.054.008.097 0 .097 0h3.602c.301 0 .597-.301.597-.301s.301-.301.602-.301.602.301.602.301.296.301.597.301h3.602c.597 0 .597-.602.597-.602V7.199c0-1.801-1.199-1.801-1.199-1.801h-3c-.301 0-.597.903-.597.903s-.301.898-.602.898-.602-.898-.602-.898-.296-.903-.597-.903h-3s-1.199 0-1.199 1.801" fill="url(#abe)"/></g></g></svg></svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 26 26"
version="1.1"
width="26"
height="26">
<g id="surface1">
<path style=" "
d="M 13 4 C 8.5625 4 4.667969 6.410156 2.59375 10 C 2.316406 10.484375 2.484375 11.097656 2.96875 11.375 C 3.453125 11.652344 4.066406 11.484375 4.34375 11 C 6.070313 8.011719 9.289063 6 13 6 C 16.710938 6 19.929688 8.007813 21.65625 11 C 21.933594 11.484375 22.546875 11.652344 23.03125 11.375 C 23.515625 11.097656 23.683594 10.484375 23.40625 10 C 21.332031 6.410156 17.4375 4 13 4 Z M 13 8 C 8.59375 8 5 11.59375 5 16 C 4.996094 16.359375 5.183594 16.695313 5.496094 16.878906 C 5.808594 17.058594 6.191406 17.058594 6.503906 16.878906 C 6.816406 16.695313 7.003906 16.359375 7 16 C 7 12.675781 9.675781 10 13 10 C 16.324219 10 19 12.675781 19 16 C 18.996094 16.359375 19.183594 16.695313 19.496094 16.878906 C 19.808594 17.058594 20.191406 17.058594 20.503906 16.878906 C 20.816406 16.695313 21.003906 16.359375 21 16 C 21 11.59375 17.40625 8 13 8 Z M 13 12 C 10.789063 12 9 13.789063 9 16 C 9 18.210938 10.789063 20 13 20 C 15.210938 20 17 18.210938 17 16 C 17 13.789063 15.210938 12 13 12 Z "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB