diff --git a/package.json b/package.json index 91228f8e..c06e2f68 100644 --- a/package.json +++ b/package.json @@ -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": { diff --git a/packages/uhk-agent/src/electron-main.ts b/packages/uhk-agent/src/electron-main.ts index a628f526..921e8030 100644 --- a/packages/uhk-agent/src/electron-main.ts +++ b/packages/uhk-agent/src/electron-main.ts @@ -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); diff --git a/packages/uhk-agent/src/services/app.service.ts b/packages/uhk-agent/src/services/app.service.ts index 850df131..9fbfb154 100644 --- a/packages/uhk-agent/src/services/app.service.ts +++ b/packages/uhk-agent/src/services/app.service.ts @@ -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, diff --git a/packages/uhk-common/src/config-serializer/config-items/key-action/switch-layer-action.spec.ts b/packages/uhk-common/src/config-serializer/config-items/key-action/switch-layer-action.spec.ts index 8483cafd..28668f98 100644 --- a/packages/uhk-common/src/config-serializer/config-items/key-action/switch-layer-action.spec.ts +++ b/packages/uhk-common/src/config-serializer/config-items/key-action/switch-layer-action.spec.ts @@ -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({layer: 0, isLayerToggleable: false}); + const action = new SwitchLayerAction({layer: 0, switchLayerMode: SwitchLayerMode.hold}); it('should be instantiate', () => { expect(new SwitchLayerAction()).toBeTruthy(); }); describe('toString', () => { - it('should return ', () => { - expect(action.toString()).toEqual(''); + it('should return ', () => { + expect(action.toString()).toEqual(''); }); }); @@ -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); + }); + }); }); diff --git a/packages/uhk-common/src/config-serializer/config-items/key-action/switch-layer-action.ts b/packages/uhk-common/src/config-serializer/config-items/key-action/switch-layer-action.ts index 01b3ba30..b46c6ea7 100644 --- a/packages/uhk-common/src/config-serializer/config-items/key-action/switch-layer-action.ts +++ b/packages/uhk-common/src/config-serializer/config-items/key-action/switch-layer-action.ts @@ -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[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 ``; + return ``; } 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`); + } +}; diff --git a/packages/uhk-common/src/config-serializer/config-items/keymap.ts b/packages/uhk-common/src/config-serializer/config-items/keymap.ts index db8e71c1..b72364fe 100644 --- a/packages/uhk-common/src/config-serializer/config-items/keymap.ts +++ b/packages/uhk-common/src/config-serializer/config-items/keymap.ts @@ -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 diff --git a/packages/uhk-common/src/config-serializer/config-items/macro-action/keymap.spec.ts b/packages/uhk-common/src/config-serializer/config-items/macro-action/keymap.spec.ts index b581acd9..bba96b13 100644 --- a/packages/uhk-common/src/config-serializer/config-items/macro-action/keymap.spec.ts +++ b/packages/uhk-common/src/config-serializer/config-items/macro-action/keymap.spec.ts @@ -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. will be override with '); + expect(console.warn).toHaveBeenCalledWith('QWERTY.layers[1]modules[0].keyActions[0] is not switch layer. will be override with '); }); 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. will be override with '); + expect(console.warn).toHaveBeenCalledWith('QWERTY.layers[1]modules[0].keyActions[0] is different switch layer. will be override with '); }); }); diff --git a/packages/uhk-common/src/models/command-line-args.ts b/packages/uhk-common/src/models/command-line-args.ts index 1e53fca3..7f70e550 100644 --- a/packages/uhk-common/src/models/command-line-args.ts +++ b/packages/uhk-common/src/models/command-line-args.ts @@ -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; } diff --git a/packages/uhk-web/src/app/components/keymap/edit/keymap-edit.component.html b/packages/uhk-web/src/app/components/keymap/edit/keymap-edit.component.html index 8a5487ae..79188b04 100644 --- a/packages/uhk-web/src/app/components/keymap/edit/keymap-edit.component.html +++ b/packages/uhk-web/src/app/components/keymap/edit/keymap-edit.component.html @@ -5,6 +5,7 @@ diff --git a/packages/uhk-web/src/app/components/keymap/edit/keymap-edit.component.ts b/packages/uhk-web/src/app/components/keymap/edit/keymap-edit.component.ts index e03d5858..7e2aaee9 100644 --- a/packages/uhk-web/src/app/components/keymap/edit/keymap-edit.component.ts +++ b/packages/uhk-web/src/app/components/keymap/edit/keymap-edit.component.ts @@ -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; keymap$: Observable; keyboardLayout$: Observable; + allowLayerDoubleTap$: Observable; constructor(protected store: Store, 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() { diff --git a/packages/uhk-web/src/app/components/popover/popover.component.html b/packages/uhk-web/src/app/components/popover/popover.component.html index 753a7552..68465e91 100644 --- a/packages/uhk-web/src/app/components/popover/popover.component.html +++ b/packages/uhk-web/src/app/components/popover/popover.component.html @@ -55,6 +55,7 @@ (); @Output() remap = new EventEmitter(); diff --git a/packages/uhk-web/src/app/components/popover/tab/layer/layer-tab.component.html b/packages/uhk-web/src/app/components/popover/tab/layer/layer-tab.component.html index 0dbb4521..f94f6957 100644 --- a/packages/uhk-web/src/app/components/popover/tab/layer/layer-tab.component.html +++ b/packages/uhk-web/src/app/components/popover/tab/layer/layer-tab.component.html @@ -1,20 +1,32 @@ - - the - - - layer by tapping this key. - layer by holding this key. - +
+
+ + the + + + layer by tapping this key. + layer by holding this key. + +
+
+
+ +
+
+
Layer switching is only possible from the base layer. - \ No newline at end of file + diff --git a/packages/uhk-web/src/app/components/popover/tab/layer/layer-tab.component.ts b/packages/uhk-web/src/app/components/popover/tab/layer/layer-tab.component.ts index 96e97b8a..9fab62ad 100644 --- a/packages/uhk-web/src/app/components/popover/tab/layer/layer-tab.component.ts +++ b/packages/uhk-web/src/app/components/popover/tab/layer/layer-tab.component.ts @@ -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 = 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) { diff --git a/packages/uhk-web/src/app/components/svg/keys/svg-keyboard-key/svg-keyboard-key.component.ts b/packages/uhk-web/src/app/components/svg/keys/svg-keyboard-key/svg-keyboard-key.component.ts index 74d0aa4b..d6e45ddc 100644 --- a/packages/uhk-web/src/app/components/svg/keys/svg-keyboard-key/svg-keyboard-key.component.ts +++ b/packages/uhk-web/src/app/components/svg/keys/svg-keyboard-key/svg-keyboard-key.component.ts @@ -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; diff --git a/packages/uhk-web/src/app/components/svg/wrap/svg-keyboard-wrap.component.html b/packages/uhk-web/src/app/components/svg/wrap/svg-keyboard-wrap.component.html index a04dcdb9..48327568 100644 --- a/packages/uhk-web/src/app/components/svg/wrap/svg-keyboard-wrap.component.html +++ b/packages/uhk-web/src/app/components/svg/wrap/svg-keyboard-wrap.component.html @@ -13,8 +13,18 @@ (capture)="onCapture($event.moduleId, $event.keyId, $event.captured)" (descriptionChanged)="onDescriptionChanged($event)" > - + + +
(); @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); diff --git a/packages/uhk-web/src/app/services/mapper.service.ts b/packages/uhk-web/src/app/services/mapper.service.ts index a93882f5..fb7c2f0d 100644 --- a/packages/uhk-web/src/app/services/mapper.service.ts +++ b/packages/uhk-web/src/app/services/mapper.service.ts @@ -262,6 +262,7 @@ export class MapperService { private initNameToFileNames(): void { this.nameToFileName = new Map(); 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'); diff --git a/packages/uhk-web/src/app/services/user-config.json b/packages/uhk-web/src/app/services/user-config.json index ac882cde..0bfa3dad 100644 --- a/packages/uhk-web/src/app/services/user-config.json +++ b/packages/uhk-web/src/app/services/user-config.json @@ -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, { @@ -6900,4 +6900,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/packages/uhk-web/src/app/store/index.ts b/packages/uhk-web/src/app/store/index.ts index 6a145236..1bb18be1 100644 --- a/packages/uhk-web/src/app/store/index.ts +++ b/packages/uhk-web/src/app/store/index.ts @@ -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); diff --git a/packages/uhk-web/src/app/store/reducers/app.reducer.ts b/packages/uhk-web/src/app/store/reducers/app.reducer.ts index 9fd1bc5a..3793dfe6 100644 --- a/packages/uhk-web/src/app/store/reducers/app.reducer.ts +++ b/packages/uhk-web/src/app/store/reducers/app.reducer.ts @@ -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; diff --git a/packages/uhk-web/src/app/store/reducers/user-configuration.spec.ts b/packages/uhk-web/src/app/store/reducers/user-configuration.spec.ts index 02d21d9f..98701810 100644 --- a/packages/uhk-web/src/app/store/reducers/user-configuration.spec.ts +++ b/packages/uhk-web/src/app/store/reducers/user-configuration.spec.ts @@ -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 } ] }, diff --git a/packages/uhk-web/src/assets/compiled_sprite.svg b/packages/uhk-web/src/assets/compiled_sprite.svg index ea1b83d7..1176393d 100644 --- a/packages/uhk-web/src/assets/compiled_sprite.svg +++ b/packages/uhk-web/src/assets/compiled_sprite.svg @@ -1 +1,974 @@ -~ `! 1@ 2# 3$ 4% 5^ 6 Tab Q W E R T Mouse A S D F G Shift Z X C V B Ctrl Super Alt Fn Mod Space & 7* 8( 9) 0_ -+ = Y U I O P { [} ]| \ H J K L : ;" ' Enter N M < ,> .? / Shift Space Fn Alt Super Ctrl Mod ~ `! 1@ 2# 3$ 4% 5^ 6TabQWERTMouseASDFGShiftZXCVBCtrlSuperAltFnModSpace& 7* 8( 9) 0_ -+ =YUIOP{ [} ]| \HJKL: ;" 'EnterNM< ,> .? /ShiftSpaceFnAltSuperCtrlMod \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ~ + ` + + + ! + 1 + + + @ + 2 + + + # + 3 + + + $ + 4 + + + % + 5 + + + ^ + 6 + + + Tab + + + Q + + + W + + + E + + + R + + + T + + + Mouse + + + A + + + S + + + D + + + F + + + G + + + Shift + + + Z + + + X + + + C + + + V + + + B + + + Ctrl + + + Super + + + Alt + + + Fn + + + Mod + + + Space + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + & + 7 + + + * + 8 + + + ( + 9 + + + ) + 0 + + + _ + - + + + + + = + + + + + + Y + + + U + + + I + + + O + + + P + + + { + [ + + + } + ] + + + | + \ + + + H + + + J + + + K + + + L + + + : + ; + + + " + ' + + + Enter + + + N + + + M + + + < + , + + + > + . + + + ? + / + + + Shift + + + Space + + + Fn + + + Alt + + + Super + + + Ctrl + + + Mod + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ~ + ` + + + ! + 1 + + + @ + 2 + + + # + 3 + + + $ + 4 + + + % + 5 + + + ^ + 6 + + + Tab + + + Q + + + W + + + E + + + R + + + T + + + Mouse + + + A + + + S + + + D + + + F + + + G + + + Shift + + + Z + + + X + + + C + + + V + + + B + + + Ctrl + + + Super + + + Alt + + + Fn + + + Mod + + + Space + + + + + & + 7 + + + * + 8 + + + ( + 9 + + + ) + 0 + + + _ + - + + + + + = + + + + + + Y + + + U + + + I + + + O + + + P + + + { + [ + + + } + ] + + + | + \ + + + H + + + J + + + K + + + L + + + : + ; + + + " + ' + + + Enter + + + N + + + M + + + < + , + + + > + . + + + ? + / + + + Shift + + + Space + + + Fn + + + Alt + + + Super + + + Ctrl + + + Mod + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/uhk-web/src/styles/uhk-icons/uhk-css.svg b/packages/uhk-web/src/styles/uhk-icons/uhk-css.svg index ab0fad11..d1aedc07 100644 --- a/packages/uhk-web/src/styles/uhk-icons/uhk-css.svg +++ b/packages/uhk-web/src/styles/uhk-icons/uhk-css.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/packages/uhk-web/src/svgs/keyboard/icons/kbd__fn--double-tap.svg b/packages/uhk-web/src/svgs/keyboard/icons/kbd__fn--double-tap.svg new file mode 100644 index 00000000..c7d3712c --- /dev/null +++ b/packages/uhk-web/src/svgs/keyboard/icons/kbd__fn--double-tap.svg @@ -0,0 +1,12 @@ + + + + + +