diff --git a/src/components/keyboard/slider/keyboard-slider.component.html b/src/components/keyboard/slider/keyboard-slider.component.html index bd0dd323..2882ff0d 100644 --- a/src/components/keyboard/slider/keyboard-slider.component.html +++ b/src/components/keyboard/slider/keyboard-slider.component.html @@ -1,7 +1,9 @@ + [@layerState]="layerAnimationState[index]" + [moduleConfig]="layer.modules" + [keybindAnimationEnabled]="keybindAnimationEnabled" + (keyClick)="keyClick.emit($event)" + (keyHover)="keyHover.emit($event)" + (capture)="capture.emit($event)" +> \ No newline at end of file diff --git a/src/components/keyboard/slider/keyboard-slider.component.ts b/src/components/keyboard/slider/keyboard-slider.component.ts index 72fb8c75..0b1e5ec8 100644 --- a/src/components/keyboard/slider/keyboard-slider.component.ts +++ b/src/components/keyboard/slider/keyboard-slider.component.ts @@ -81,6 +81,7 @@ export class KeyboardSliderComponent implements OnChanges { @Input() keybindAnimationEnabled: boolean; @Output() keyClick = new EventEmitter(); @Output() keyHover = new EventEmitter(); + @Output() capture = new EventEmitter(); private layerAnimationState: AnimationKeyboard[]; diff --git a/src/components/popover/tab/keypress/keypress-tab.component.ts b/src/components/popover/tab/keypress/keypress-tab.component.ts index 43670ce3..e453f62c 100644 --- a/src/components/popover/tab/keypress/keypress-tab.component.ts +++ b/src/components/popover/tab/keypress/keypress-tab.component.ts @@ -5,6 +5,7 @@ import { Select2OptionData, Select2TemplateFunction } from 'ng2-select2'; import { KeyAction, KeystrokeAction } from '../../../../config-serializer/config-items/key-action'; import { Tab } from '../tab'; +import { MapperService } from '../../../../services/mapper.service'; @Component({ selector: 'keypress-tab', @@ -28,7 +29,7 @@ export class KeypressTabComponent implements OnChanges, Tab { private scanCode: number; private selectedLongPressIndex: number; - constructor() { + constructor(private mapper: MapperService) { this.leftModifiers = ['LShift', 'LCtrl', 'LSuper', 'LAlt']; this.rightModifiers = ['RShift', 'RCtrl', 'RSuper', 'RAlt']; this.scanCodeGroups = [{ @@ -89,17 +90,17 @@ export class KeypressTabComponent implements OnChanges, Tab { // Restore modifiers for (let i = 0; i < leftModifiersLength; ++i) { - this.leftModifierSelects[this.modifierMapper(i)] = ((keystrokeAction.modifierMask >> i) & 1) === 1; + this.leftModifierSelects[this.mapper.modifierMapper(i)] = ((keystrokeAction.modifierMask >> i) & 1) === 1; } for (let i = leftModifiersLength; i < leftModifiersLength + this.rightModifierSelects.length; ++i) { - let index: number = this.modifierMapper(i) - leftModifiersLength; + let index: number = this.mapper.modifierMapper(i) - leftModifiersLength; this.rightModifierSelects[index] = ((keystrokeAction.modifierMask >> i) & 1) === 1; } // Restore longPressAction if (keystrokeAction.longPressAction !== undefined) { - this.selectedLongPressIndex = this.modifierMapper(keystrokeAction.longPressAction); + this.selectedLongPressIndex = this.mapper.modifierMapper(keystrokeAction.longPressAction); } return true; @@ -112,12 +113,12 @@ export class KeypressTabComponent implements OnChanges, Tab { keystrokeAction.modifierMask = 0; let modifiers = this.leftModifierSelects.concat(this.rightModifierSelects).map(x => x ? 1 : 0); for (let i = 0; i < modifiers.length; ++i) { - keystrokeAction.modifierMask |= modifiers[i] << this.modifierMapper(i); + keystrokeAction.modifierMask |= modifiers[i] << this.mapper.modifierMapper(i); } keystrokeAction.longPressAction = this.selectedLongPressIndex === -1 ? undefined - : this.modifierMapper(this.selectedLongPressIndex); + : this.mapper.modifierMapper(this.selectedLongPressIndex); if (!this.keyActionValid(keystrokeAction)) { throw new Error('KeyAction is invalid!'); @@ -157,12 +158,4 @@ export class KeypressTabComponent implements OnChanges, Tab { onScancodeChange(event: {value: string}) { this.scanCode = +event.value; } - - private modifierMapper(x: number) { - if (x < 8) { - return Math.floor(x / 2) * 4 + 1 - x; // 1, 0, 3, 2, 5, 4, 7, 6 - } else { - return x; - } - }; } diff --git a/src/components/svg/keyboard/svg-keyboard.component.html b/src/components/svg/keyboard/svg-keyboard.component.html index 15174c84..e707b459 100644 --- a/src/components/svg/keyboard/svg-keyboard.component.html +++ b/src/components/svg/keyboard/svg-keyboard.component.html @@ -8,6 +8,7 @@ [keyActions]="moduleConfig[i].keyActions" (keyClick)="onKeyClick(i, $event.index, $event.keyTarget)" (keyHover)="onKeyHover($event.index, $event.event, $event.over, i)" + (capture)="onCapture(i, $event.index, $event.captured)" /> \ No newline at end of file diff --git a/src/components/svg/keyboard/svg-keyboard.component.ts b/src/components/svg/keyboard/svg-keyboard.component.ts index ef998172..a2af4309 100644 --- a/src/components/svg/keyboard/svg-keyboard.component.ts +++ b/src/components/svg/keyboard/svg-keyboard.component.ts @@ -13,6 +13,7 @@ export class SvgKeyboardComponent implements OnInit { @Input() keybindAnimationEnabled: boolean; @Output() keyClick = new EventEmitter(); @Output() keyHover = new EventEmitter(); + @Output() capture = new EventEmitter(); private modules: SvgModule[]; private svgAttributes: { viewBox: string, transform: string, fill: string }; @@ -34,6 +35,14 @@ export class SvgKeyboardComponent implements OnInit { }); } + onCapture(moduleId: number, keyId: number, captured: {code: number, left: boolean[], right: boolean[]}): void { + this.capture.emit({ + moduleId, + keyId, + captured + }); + } + onKeyHover(keyId: number, event: MouseEvent, over: boolean, moduleId: number): void { this.keyHover.emit({ moduleId, diff --git a/src/components/svg/keys/svg-keyboard-key/svg-keyboard-key.component.html b/src/components/svg/keys/svg-keyboard-key/svg-keyboard-key.component.html index ba8caf1b..13b8a808 100644 --- a/src/components/svg/keys/svg-keyboard-key/svg-keyboard-key.component.html +++ b/src/components/svg/keys/svg-keyboard-key/svg-keyboard-key.component.html @@ -1,53 +1,65 @@ - - - + + diff --git a/src/components/svg/keys/svg-keyboard-key/svg-keyboard-key.component.scss b/src/components/svg/keys/svg-keyboard-key/svg-keyboard-key.component.scss index ec252956..09055ce6 100644 --- a/src/components/svg/keys/svg-keyboard-key/svg-keyboard-key.component.scss +++ b/src/components/svg/keys/svg-keyboard-key/svg-keyboard-key.component.scss @@ -4,6 +4,7 @@ } cursor: pointer; + outline: none; &:hover { fill: #494949; diff --git a/src/components/svg/keys/svg-keyboard-key/svg-keyboard-key.component.ts b/src/components/svg/keys/svg-keyboard-key/svg-keyboard-key.component.ts index d1ee1552..a42cbe45 100644 --- a/src/components/svg/keys/svg-keyboard-key/svg-keyboard-key.component.ts +++ b/src/components/svg/keys/svg-keyboard-key/svg-keyboard-key.component.ts @@ -1,6 +1,6 @@ import { - Component, ElementRef, EventEmitter, HostListener, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChange, - animate, group, style, transition, trigger + Component, ElementRef, EventEmitter, HostListener, Input, OnChanges, OnDestroy, OnInit, Output, Renderer, + SimpleChange, animate, group, state, style, transition, trigger } from '@angular/core'; import { Store } from '@ngrx/store'; @@ -19,6 +19,7 @@ import { import { KeyModifiers } from '../../../../config-serializer/config-items/KeyModifiers'; import { Macro } from '../../../../config-serializer/config-items/Macro'; +import { CaptureService } from '../../../../services/capture.service'; import { MapperService } from '../../../../services/mapper.service'; import { AppState } from '../../../../store/index'; @@ -46,6 +47,15 @@ enum LabelTypes { })) ]) ]) + ]), + trigger('recording', [ + state('inactive', style({ + fill: 'rgba(204, 0, 0, 1)' + })), + state('active', style({ + fill: 'rgba(204, 0, 0, 0.6)' + })), + transition('inactive <=> active', animate('600ms ease-in-out')) ]) ], selector: 'g[svg-keyboard-key]', @@ -61,22 +71,79 @@ export class SvgKeyboardKeyComponent implements OnInit, OnChanges, OnDestroy { @Input() keyAction: KeyAction; @Input() keybindAnimationEnabled: boolean; @Output() keyClick = new EventEmitter(); + @Output() capture = new EventEmitter(); enumLabelTypes = LabelTypes; + public changeAnimation: string = 'inactive'; + public recordAnimation: string; + private labelSource: any; private labelType: LabelTypes; private macros: Macro[]; private subscription: Subscription; - private animation: string = 'inactive'; + private recording: boolean; - @HostListener('click') onClick() { + @HostListener('click') + onClick() { + this.reset(); this.keyClick.emit(this.element.nativeElement); } - constructor(private mapper: MapperService, private store: Store, private element: ElementRef) { + @HostListener('mousedown', ['$event']) + onMouseDown(e: MouseEvent) { + if (e.which === 2 || e.button === 1) { + e.preventDefault(); + this.renderer.invokeElementMethod(this.element.nativeElement, 'focus'); + + if (this.recording) { + this.reset(); + } else { + this.recording = true; + this.recordAnimation = 'active'; + } + } + } + + @HostListener('keyup') + onKeyUp() { + if (this.recording) { + this.saveScanCode(); + } + } + + @HostListener('keydown', ['$event']) + onKeyDown(e: KeyboardEvent) { + const code: number = e.keyCode; + + if (this.recording) { + e.preventDefault(); + + if (this.captureService.hasMap(code)) { + this.saveScanCode(this.captureService.getMap(code)); + } else { + this.captureService.setModifier((e.location === 1), code); + } + } + } + + @HostListener('focusout') + onFocusOut() { + this.reset(); + } + + constructor( + private mapper: MapperService, + private store: Store, + private element: ElementRef, + private captureService: CaptureService, + private renderer: Renderer + ) { this.subscription = store.let(getMacroEntities()) .subscribe((macros: Macro[]) => this.macros = macros); + + this.reset(); + this.captureService.populateMapping(); } ngOnInit() { @@ -84,22 +151,50 @@ export class SvgKeyboardKeyComponent implements OnInit, OnChanges, OnDestroy { } ngOnChanges(changes: { [propertyName: string]: SimpleChange }) { - /* tslint:disable:no-string-literal */ if (changes['keyAction']) { this.setLabels(); if (this.keybindAnimationEnabled) { - this.animation = 'active'; + this.changeAnimation = 'active'; } } - /* tslint:enable:no-string-literal */ } ngOnDestroy() { this.subscription.unsubscribe(); } - animationDone() { - this.animation = 'inactive'; + onChangeAnimationDone() { + this.changeAnimation = 'inactive'; + } + + onRecordingAnimationDone() { + if (this.recording && this.recordAnimation === 'inactive') { + this.recordAnimation = 'active'; + } else { + this.recordAnimation = 'inactive'; + } + } + + private reset() { + this.recording = false; + this.changeAnimation = 'inactive'; + this.captureService.initModifiers(); + } + + 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 + }); + + this.captureService.initModifiers(); } private setLabels(): void { diff --git a/src/components/svg/module/svg-module.component.html b/src/components/svg/module/svg-module.component.html index 41dd0506..5a507a5d 100644 --- a/src/components/svg/module/svg-module.component.html +++ b/src/components/svg/module/svg-module.component.html @@ -7,6 +7,7 @@ [keyAction]="keyActions[i]" [keybindAnimationEnabled]="keybindAnimationEnabled" (keyClick)="onKeyClick(i, $event)" + (capture)="onCapture(i, $event)" (mouseenter)="onKeyHover(i, $event, true)" (mouseleave)="onKeyHover(i, $event, false)" /> \ No newline at end of file diff --git a/src/components/svg/module/svg-module.component.ts b/src/components/svg/module/svg-module.component.ts index 035ea41f..82b491e2 100644 --- a/src/components/svg/module/svg-module.component.ts +++ b/src/components/svg/module/svg-module.component.ts @@ -16,6 +16,7 @@ export class SvgModuleComponent { @Input() keybindAnimationEnabled: boolean; @Output() keyClick = new EventEmitter(); @Output() keyHover = new EventEmitter(); + @Output() capture = new EventEmitter(); constructor() { this.keyboardKeys = []; @@ -36,4 +37,10 @@ export class SvgModuleComponent { }); } + onCapture(index: number, captured: {code: number, left: boolean[], right: boolean[]}) { + this.capture.emit({ + index, + captured + }); + } } diff --git a/src/components/svg/wrap/svg-keyboard-wrap.component.html b/src/components/svg/wrap/svg-keyboard-wrap.component.html index 6d9e0b2e..0bb9d8ff 100644 --- a/src/components/svg/wrap/svg-keyboard-wrap.component.html +++ b/src/components/svg/wrap/svg-keyboard-wrap.component.html @@ -4,7 +4,9 @@ [currentLayer]="currentLayer" [keybindAnimationEnabled]="keybindAnimationEnabled" (keyClick)="onKeyClick($event.moduleId, $event.keyId, $event.keyTarget)" - (keyHover)="onKeyHover($event.moduleId, $event.event, $event.over, $event.keyId)"> + (keyHover)="onKeyHover($event.moduleId, $event.event, $event.over, $event.keyId)" + (capture)="onCapture($event.moduleId, $event.keyId, $event.captured)" + >
x ? 1 : 0); + + keystrokeAction.scancode = captured.code; + keystrokeAction.modifierMask = 0; + + for (let i = 0; i < modifiers.length; ++i) { + keystrokeAction.modifierMask |= modifiers[i] << this.mapper.modifierMapper(i); + } + + this.store.dispatch( + KeymapActions.saveKey( + this.keymap, + this.currentLayer, + moduleId, + keyId, + keystrokeAction) + ); + } + onRemap(keyAction: KeyAction): void { this.store.dispatch( KeymapActions.saveKey( @@ -277,5 +298,4 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges { selectLayer(index: number): void { this.currentLayer = index; } - } diff --git a/src/services/mapper.service.ts b/src/services/mapper.service.ts index 90d5bf30..60ccff6a 100644 --- a/src/services/mapper.service.ts +++ b/src/services/mapper.service.ts @@ -38,6 +38,14 @@ export class MapperService { return 'assets/compiled_sprite.svg#' + this.nameToFileName.get(iconName); } + public modifierMapper(x: number) { + if (x < 8) { + return Math.floor(x / 2) * 4 + 1 - x; // 1, 0, 3, 2, 5, 4, 7, 6 + } else { + return x; + } + } + // TODO: read the mapping from JSON private initScanCodeTextMap(): void { this.scanCodeTextMap = new Map();