From 84f378a276a1e46074043fd62f602d29e218e258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=B3bert=20Kiss?= Date: Sun, 8 Jul 2018 14:31:48 +0200 Subject: [PATCH] feat: add save to keyboard and remap shortcut keys (#712) * feat: add save to keyboard and remap shortcut keys * feat: Alt and Shift keys set the remapOnAllKeymap and remapOnAllLayer * fix: control + enter trigger remap keymap --- packages/uhk-web/src/app/app.component.html | 4 +- packages/uhk-web/src/app/app.component.ts | 27 ++++++- .../slider/keyboard-slider.component.html | 1 + .../slider/keyboard-slider.component.ts | 11 ++- .../components/popover/popover.component.ts | 15 ++-- .../svg/keyboard/svg-keyboard.component.html | 4 +- .../svg/keyboard/svg-keyboard.component.ts | 26 ++++--- .../svg-keyboard-key.component.ts | 74 +++++++++++++++---- .../svg/module/svg-module.component.ts | 22 ++++-- .../svg/wrap/svg-keyboard-wrap.component.html | 8 +- .../svg/wrap/svg-keyboard-wrap.component.ts | 46 +++++++----- .../uhk-web/src/app/models/svg-key-events.ts | 42 +++++++++++ 12 files changed, 210 insertions(+), 70 deletions(-) create mode 100644 packages/uhk-web/src/app/models/svg-key-events.ts diff --git a/packages/uhk-web/src/app/app.component.html b/packages/uhk-web/src/app/app.component.html index c847097f..bbe29074 100644 --- a/packages/uhk-web/src/app/app.component.html +++ b/packages/uhk-web/src/app/app.component.html @@ -9,7 +9,7 @@ diff --git a/packages/uhk-web/src/app/app.component.ts b/packages/uhk-web/src/app/app.component.ts index 20368e60..564cedae 100644 --- a/packages/uhk-web/src/app/app.component.ts +++ b/packages/uhk-web/src/app/app.component.ts @@ -1,6 +1,7 @@ -import { Component, ViewEncapsulation } from '@angular/core'; +import { Component, HostListener, ViewEncapsulation, OnDestroy } from '@angular/core'; import { animate, style, transition, trigger } from '@angular/animations'; import { Observable } from 'rxjs/Observable'; +import { Subscription } from 'rxjs/Subscription'; import { Action, Store } from '@ngrx/store'; import 'rxjs/add/operator/last'; @@ -34,17 +35,35 @@ import { ProgressButtonState } from './store/reducers/progress-button-state'; ]) ] }) -export class MainAppComponent { +export class MainAppComponent implements OnDestroy { showUpdateAvailable$: Observable; deviceConfigurationLoaded$: Observable; runningInElectron$: Observable; - saveToKeyboardState$: Observable; + saveToKeyboardState: ProgressButtonState; + + private saveToKeyboardStateSubscription: Subscription; constructor(private store: Store) { this.showUpdateAvailable$ = store.select(getShowAppUpdateAvailable); this.deviceConfigurationLoaded$ = store.select(deviceConfigurationLoaded); this.runningInElectron$ = store.select(runningInElectron); - this.saveToKeyboardState$ = store.select(saveToKeyboardState); + this.saveToKeyboardStateSubscription = store.select(saveToKeyboardState) + .subscribe(data => this.saveToKeyboardState = data); + } + + ngOnDestroy(): void { + this.saveToKeyboardStateSubscription.unsubscribe(); + } + + @HostListener('document:keydown', ['$event']) + onKeyDown(event: KeyboardEvent) { + if (this.saveToKeyboardState.showButton && + event.ctrlKey && + event.key === 's' && + !event.defaultPrevented) { + this.clickedOnProgressButton(this.saveToKeyboardState.action); + event.preventDefault(); + } } updateApp() { diff --git a/packages/uhk-web/src/app/components/keyboard/slider/keyboard-slider.component.html b/packages/uhk-web/src/app/components/keyboard/slider/keyboard-slider.component.html index 544e08b3..c9f01e42 100644 --- a/packages/uhk-web/src/app/components/keyboard/slider/keyboard-slider.component.html +++ b/packages/uhk-web/src/app/components/keyboard/slider/keyboard-slider.component.html @@ -9,6 +9,7 @@ [keyboardLayout]="keyboardLayout" [description]="description" [showDescription]="true" + oncontextmenu="return false;" (keyClick)="keyClick.emit($event)" (keyHover)="keyHover.emit($event)" (capture)="capture.emit($event)" diff --git a/packages/uhk-web/src/app/components/keyboard/slider/keyboard-slider.component.ts b/packages/uhk-web/src/app/components/keyboard/slider/keyboard-slider.component.ts index ed590348..c452d080 100644 --- a/packages/uhk-web/src/app/components/keyboard/slider/keyboard-slider.component.ts +++ b/packages/uhk-web/src/app/components/keyboard/slider/keyboard-slider.component.ts @@ -3,6 +3,11 @@ import { animate, keyframes, state, style, transition, trigger } from '@angular/ import { Layer } from 'uhk-common'; import { KeyboardLayout } from '../../../keyboard/keyboard-layout.enum'; +import { + SvgKeyboardCaptureEvent, + SvgKeyboardKeyClickEvent, + SvgKeyHoverEvent +} from '../../../models/svg-key-events'; type AnimationKeyboard = 'init' | @@ -82,9 +87,9 @@ export class KeyboardSliderComponent implements OnChanges { @Input() selectedKey: { layerId: number, moduleId: number, keyId: number }; @Input() keyboardLayout = KeyboardLayout.ANSI; @Input() description: string; - @Output() keyClick = new EventEmitter(); - @Output() keyHover = new EventEmitter(); - @Output() capture = new EventEmitter(); + @Output() keyClick = new EventEmitter(); + @Output() keyHover = new EventEmitter(); + @Output() capture = new EventEmitter(); @Output() descriptionChanged = new EventEmitter(); layerAnimationState: AnimationKeyboard[]; diff --git a/packages/uhk-web/src/app/components/popover/popover.component.ts b/packages/uhk-web/src/app/components/popover/popover.component.ts index 0c2a7387..885ff0fb 100644 --- a/packages/uhk-web/src/app/components/popover/popover.component.ts +++ b/packages/uhk-web/src/app/components/popover/popover.component.ts @@ -84,6 +84,8 @@ export class PopoverComponent implements OnChanges { @Input() wrapPosition: any; @Input() visible: boolean; @Input() allowLayerDoubleTap: boolean; + @Input() remapOnAllKeymap: boolean; + @Input() remapOnAllLayer: boolean; @Output() cancel = new EventEmitter(); @Output() remap = new EventEmitter(); @@ -101,9 +103,6 @@ export class PopoverComponent implements OnChanges { leftPosition: number = 0; animationState: string; - remapOnAllKeymap: boolean; - remapOnAllLayer: boolean; - private readonly currentKeymap$ = new BehaviorSubject(undefined); constructor(store: Store) { @@ -143,8 +142,6 @@ export class PopoverComponent implements OnChanges { if (change['visible']) { if (change['visible'].currentValue) { this.animationState = 'opened'; - this.remapOnAllKeymap = false; - this.remapOnAllLayer = false; } else { this.animationState = 'closed'; } @@ -179,6 +176,14 @@ export class PopoverComponent implements OnChanges { this.cancel.emit(); } + @HostListener('document:keydown.control.enter', ['$event']) + onKeyDown(event: KeyboardEvent) { + if (this.visible) { + this.onRemapKey(); + event.preventDefault(); + } + } + selectTab(tab: TabName): void { this.activeTab = tab; } diff --git a/packages/uhk-web/src/app/components/svg/keyboard/svg-keyboard.component.html b/packages/uhk-web/src/app/components/svg/keyboard/svg-keyboard.component.html index b16e44be..9f02ef01 100644 --- a/packages/uhk-web/src/app/components/svg/keyboard/svg-keyboard.component.html +++ b/packages/uhk-web/src/app/components/svg/keyboard/svg-keyboard.component.html @@ -13,9 +13,9 @@ [selectedKey]="selectedKey" [@split]="moduleAnimationStates[i]" [selected]="selectedKey?.moduleId === i" - (keyClick)="onKeyClick(i, $event.index, $event.keyTarget)" + (keyClick)="onKeyClick(i, $event)" (keyHover)="onKeyHover($event.index, $event.event, $event.over, i)" - (capture)="onCapture(i, $event.index, $event.captured)" /> + (capture)="onCapture(i, $event)" /> (); + @Output() keyHover = new EventEmitter(); + @Output() capture = new EventEmitter(); @Output() descriptionChanged = new EventEmitter(); modules: SvgModule[]; @@ -79,19 +85,17 @@ export class SvgKeyboardComponent implements OnInit { } } - onKeyClick(moduleId: number, keyId: number, keyTarget: HTMLElement): void { + onKeyClick(moduleId: number, event: SvgModuleKeyClickEvent): void { this.keyClick.emit({ - moduleId, - keyId, - keyTarget + ...event, + moduleId }); } - onCapture(moduleId: number, keyId: number, captured: { code: number, left: boolean[], right: boolean[] }): void { + onCapture(moduleId: number, event: SvgKeyboardCaptureEvent): void { this.capture.emit({ - moduleId, - keyId, - captured + ...event, + moduleId }); } 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 d6e45ddc..704b89ae 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 @@ -26,6 +26,7 @@ import { MapperService } from '../../../../services/mapper.service'; import { AppState } from '../../../../store'; import { getMacros } from '../../../../store/reducers/user-configuration'; +import { SvgKeyCaptureEvent, SvgKeyClickEvent } from '../../../../models/svg-key-events'; enum LabelTypes { KeystrokeKey, @@ -82,8 +83,8 @@ export class SvgKeyboardKeyComponent implements OnInit, OnChanges, OnDestroy { @Input() capturingEnabled: boolean; @Input() active: boolean; - @Output() keyClick = new EventEmitter(); - @Output() capture = new EventEmitter(); + @Output() keyClick = new EventEmitter(); + @Output() capture = new EventEmitter(); enumLabelTypes = LabelTypes; @@ -96,6 +97,10 @@ export class SvgKeyboardKeyComponent implements OnInit, OnChanges, OnDestroy { macros: Macro[]; private subscription: Subscription; private scanCodePressed: boolean; + private pressedShiftLocation = -1; + private pressedAltLocation = -1; + private altPressed = false; + private shitPressed = false; constructor( private mapper: MapperService, @@ -115,12 +120,16 @@ export class SvgKeyboardKeyComponent implements OnInit, OnChanges, OnDestroy { @HostListener('click') onClick() { this.reset(); - this.keyClick.emit(this.element.nativeElement); + this.keyClick.emit({ + keyTarget: this.element.nativeElement, + shiftPressed: this.pressedShiftLocation > -1, + altPressed: this.pressedAltLocation > -1 + }); } @HostListener('mousedown', ['$event']) onMouseDown(e: MouseEvent) { - if ((e.which === 2 || e.button === 1) && this.capturingEnabled) { + if ((e.which === 2 || e.button === 2) && this.capturingEnabled) { e.preventDefault(); this.renderer.invokeElementMethod(this.element.nativeElement, 'focus'); @@ -129,13 +138,29 @@ export class SvgKeyboardKeyComponent implements OnInit, OnChanges, OnDestroy { } else { this.recording = true; this.recordAnimation = 'active'; + + if (this.pressedShiftLocation > -1) { + this.shitPressed = true; + } + + if (this.pressedAltLocation > -1) { + this.altPressed = true; + } } } } - @HostListener('keyup', ['$event']) + @HostListener('document:keyup', ['$event']) onKeyUp(e: KeyboardEvent) { - if (this.scanCodePressed) { + if (e.keyCode === 18 && this.pressedAltLocation > -1) { + this.pressedAltLocation = -1; + e.preventDefault(); + } + else if (e.keyCode === 16 && this.pressedShiftLocation > -1) { + this.pressedShiftLocation = -1; + e.preventDefault(); + } + else if (this.scanCodePressed) { e.preventDefault(); this.scanCodePressed = false; } else if (this.recording) { @@ -144,7 +169,7 @@ export class SvgKeyboardKeyComponent implements OnInit, OnChanges, OnDestroy { } } - @HostListener('keydown', ['$event']) + @HostListener('document:keydown', ['$event']) onKeyDown(e: KeyboardEvent) { const code: number = e.keyCode; @@ -152,11 +177,29 @@ export class SvgKeyboardKeyComponent implements OnInit, OnChanges, OnDestroy { e.preventDefault(); if (this.captureService.hasMap(code)) { + // If the Alt or Shift key not released after start the capturing + // then add them as a modifier + if (this.pressedShiftLocation > -1) { + this.captureService.setModifier((this.pressedShiftLocation === 1), 16); + } + + if (this.pressedAltLocation > -1) { + this.captureService.setModifier((this.pressedAltLocation === 1), 18); + } + this.saveScanCode(this.captureService.getMap(code)); this.scanCodePressed = true; } else { this.captureService.setModifier((e.location === 1), code); } + } else { + if (e.keyCode === 16) { + this.pressedShiftLocation = e.location; + } + + if (e.keyCode === 18) { + this.pressedAltLocation = e.location; + } } } @@ -198,22 +241,25 @@ export class SvgKeyboardKeyComponent implements OnInit, OnChanges, OnDestroy { this.recording = false; this.changeAnimation = 'inactive'; this.captureService.initModifiers(); + this.shitPressed = false; + this.altPressed = false; } private saveScanCode(code = 0) { - this.recording = false; - this.changeAnimation = 'inactive'; - const left: boolean[] = this.captureService.getModifiers(true); const right: boolean[] = this.captureService.getModifiers(false); this.capture.emit({ - code, - left, - right + captured: { + code, + left, + right + }, + shiftPressed: this.shitPressed, + altPressed: this.altPressed }); - this.captureService.initModifiers(); + this.reset(); } private setLabels(): void { diff --git a/packages/uhk-web/src/app/components/svg/module/svg-module.component.ts b/packages/uhk-web/src/app/components/svg/module/svg-module.component.ts index 22ce34f7..066f5b05 100644 --- a/packages/uhk-web/src/app/components/svg/module/svg-module.component.ts +++ b/packages/uhk-web/src/app/components/svg/module/svg-module.component.ts @@ -2,6 +2,12 @@ import { Component, EventEmitter, Input, Output, ChangeDetectionStrategy } from import { KeyAction } from 'uhk-common'; import { SvgKeyboardKey } from '../keys'; +import { + SvgKeyCaptureEvent, + SvgKeyClickEvent, + SvgModuleCaptureEvent, + SvgModuleKeyClickEvent +} from '../../../models/svg-key-events'; @Component({ selector: 'g[svg-module]', @@ -17,18 +23,18 @@ export class SvgModuleComponent { @Input() selected: boolean; @Input() keybindAnimationEnabled: boolean; @Input() capturingEnabled: boolean; - @Output() keyClick = new EventEmitter(); + @Output() keyClick = new EventEmitter(); @Output() keyHover = new EventEmitter(); - @Output() capture = new EventEmitter(); + @Output() capture = new EventEmitter(); constructor() { this.keyboardKeys = []; } - onKeyClick(index: number, keyTarget: HTMLElement): void { + onKeyClick(keyId: number, event: SvgKeyClickEvent): void { this.keyClick.emit({ - index, - keyTarget + ...event, + keyId }); } @@ -40,10 +46,10 @@ export class SvgModuleComponent { }); } - onCapture(index: number, captured: {code: number, left: boolean[], right: boolean[]}) { + onCapture(keyId: number, event: SvgKeyCaptureEvent) { this.capture.emit({ - index, - captured + ...event, + keyId }); } } 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 48327568..2e1d70d2 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 @@ -8,9 +8,9 @@ [halvesSplit]="halvesSplit" [keyboardLayout]="keyboardLayout" [description]="keymap.description" - (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)" + (keyClick)="onKeyClick($event)" + (keyHover)="onKeyHover($event)" + (capture)="onCapture($event)" (descriptionChanged)="onDescriptionChanged($event)" > @@ -22,6 +22,8 @@ [currentKeymap]="keymap" [currentLayer]="currentLayer" [allowLayerDoubleTap]="allowLayerDoubleTap" + [remapOnAllKeymap]="remapOnAllKeymap" + [remapOnAllLayer]="remapOnAllLayer" (cancel)="hidePopover()" (remap)="onRemap($event)"> diff --git a/packages/uhk-web/src/app/components/svg/wrap/svg-keyboard-wrap.component.ts b/packages/uhk-web/src/app/components/svg/wrap/svg-keyboard-wrap.component.ts index 7b020409..c735d2d4 100644 --- a/packages/uhk-web/src/app/components/svg/wrap/svg-keyboard-wrap.component.ts +++ b/packages/uhk-web/src/app/components/svg/wrap/svg-keyboard-wrap.component.ts @@ -43,6 +43,11 @@ import { PopoverComponent } from '../../popover'; import { KeyboardLayout } from '../../../keyboard/keyboard-layout.enum'; import { ChangeKeymapDescription } from '../../../models/ChangeKeymapDescription'; import { KeyActionRemap } from '../../../models/key-action-remap'; +import { + SvgKeyboardCaptureEvent, + SvgKeyboardKeyClickEvent, + SvgKeyHoverEvent +} from '../../../models/svg-key-events'; interface NameValuePair { name: string; @@ -65,7 +70,7 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges { @Output() descriptionChanged = new EventEmitter(); - @ViewChild(PopoverComponent, { read: ElementRef }) popover: ElementRef; + @ViewChild(PopoverComponent, {read: ElementRef}) popover: ElementRef; popoverShown: boolean; keyEditConfig: { moduleId: number, keyId: number }; @@ -82,6 +87,9 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges { layers: Layer[]; keyPosition: ClientRect; wrapPosition: ClientRect; + remapOnAllKeymap: boolean; + remapOnAllLayer: boolean; + private wrapHost: HTMLElement; private keyElement: HTMLElement; @@ -139,36 +147,38 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges { } - onKeyClick(moduleId: number, keyId: number, keyTarget: HTMLElement): void { + onKeyClick(event: SvgKeyboardKeyClickEvent): void { if (!this.popoverShown && this.popoverEnabled) { this.keyEditConfig = { - moduleId, - keyId + moduleId: event.moduleId, + keyId: event.keyId }; - this.selectedKey = { layerId: this.currentLayer, moduleId, keyId }; - const keyActionToEdit: KeyAction = this.layers[this.currentLayer].modules[moduleId].keyActions[keyId]; - this.keyElement = keyTarget; + this.selectedKey = {layerId: this.currentLayer, moduleId: event.moduleId, keyId: event.keyId}; + const keyActionToEdit: KeyAction = this.layers[this.currentLayer].modules[event.moduleId].keyActions[event.keyId]; + this.keyElement = event.keyTarget; + this.remapOnAllKeymap = event.shiftPressed; + this.remapOnAllLayer = event.altPressed; this.showPopover(keyActionToEdit); } } - onKeyHover(moduleId: number, event: MouseEvent, over: boolean, keyId: number): void { + onKeyHover(event: SvgKeyHoverEvent): void { if (this.tooltipEnabled) { - const keyActionToEdit: KeyAction = this.layers[this.currentLayer].modules[moduleId].keyActions[keyId]; + const keyActionToEdit: KeyAction = this.layers[this.currentLayer].modules[event.moduleId].keyActions[event.keyId]; - if (over) { - this.showTooltip(keyActionToEdit, event); + if (event.over) { + this.showTooltip(keyActionToEdit, event.event); } else { this.hideTooltip(); } } } - onCapture(moduleId: number, keyId: number, captured: { code: number, left: boolean[], right: boolean[] }): void { + onCapture(event: SvgKeyboardCaptureEvent): void { const keystrokeAction: KeystrokeAction = new KeystrokeAction(); - const modifiers = captured.left.concat(captured.right).map(x => x ? 1 : 0); + const modifiers = event.captured.left.concat(event.captured.right).map(x => x ? 1 : 0); - keystrokeAction.scancode = captured.code; + keystrokeAction.scancode = event.captured.code; keystrokeAction.modifierMask = 0; for (let i = 0; i < modifiers.length; ++i) { @@ -179,11 +189,11 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges { KeymapActions.saveKey( this.keymap, this.currentLayer, - moduleId, - keyId, + event.moduleId, + event.keyId, { - remapOnAllKeymap: false, - remapOnAllLayer: false, + remapOnAllKeymap: event.shiftPressed, + remapOnAllLayer: event.altPressed, action: keystrokeAction }) ); diff --git a/packages/uhk-web/src/app/models/svg-key-events.ts b/packages/uhk-web/src/app/models/svg-key-events.ts new file mode 100644 index 00000000..8a94a72d --- /dev/null +++ b/packages/uhk-web/src/app/models/svg-key-events.ts @@ -0,0 +1,42 @@ +export interface SvgKeyClickEvent { + keyTarget: HTMLElement; + shiftPressed?: boolean; + altPressed?: boolean; +} + +export interface SvgModuleKeyClickEvent extends SvgKeyClickEvent { + keyId: number; +} + +export interface SvgKeyboardKeyClickEvent extends SvgModuleKeyClickEvent { + moduleId: number; +} + +export interface KeyCaptureData { + code: number; + left: boolean[]; + right: boolean[]; +} + +export interface SvgKeyCaptureEvent { + captured: KeyCaptureData; + shiftPressed?: boolean; + altPressed?: boolean; +} + +export interface SvgModuleCaptureEvent extends SvgKeyCaptureEvent { + keyId: number; +} + +export interface SvgKeyboardCaptureEvent extends SvgModuleCaptureEvent { + moduleId: number; +} + +export interface SvgKeyHoverEvent { + keyId: number; + event: MouseEvent; + over: boolean; + moduleId: number; + shiftPressed?: boolean; + altPressed?: boolean; +}