From de364fbfa91cdf203efcf13ec15787fa0e151e82 Mon Sep 17 00:00:00 2001 From: Nejc Zdovc Date: Fri, 23 Dec 2016 15:49:16 +0100 Subject: [PATCH] Added capture keystroke to the popover (#229) Resolves #228 --- src/app.module.ts | 4 +- .../tab/keypress/keypress-tab.component.html | 2 +- .../tab/keypress/keypress-tab.component.ts | 21 ++- .../capture-keystroke-button.component.html | 7 +- .../capture-keystroke-button.component.ts | 63 +++++++- src/services/capture.service.ts | 142 ++++++++++++++++++ 6 files changed, 221 insertions(+), 18 deletions(-) create mode 100644 src/services/capture.service.ts diff --git a/src/app.module.ts b/src/app.module.ts index d7e404aa..242f0e93 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -62,6 +62,7 @@ import { MainAppComponent, appRoutingProviders, routing } from './main-app'; import { CancelableDirective } from './directives'; +import { CaptureService } from './services/capture.service'; import { MapperService } from './services/mapper.service'; import { KeymapEffects, MacroEffects } from './store/effects'; @@ -154,7 +155,8 @@ const storeConfig = { MapperService, appRoutingProviders, KeymapEditGuard, - MacroNotFoundGuard + MacroNotFoundGuard, + CaptureService ], bootstrap: [MainAppComponent] }) diff --git a/src/components/popover/tab/keypress/keypress-tab.component.html b/src/components/popover/tab/keypress/keypress-tab.component.html index 9082a15b..8afd46b8 100644 --- a/src/components/popover/tab/keypress/keypress-tab.component.html +++ b/src/components/popover/tab/keypress/keypress-tab.component.html @@ -7,7 +7,7 @@ [width]="200" [options]="options" > - +
Modifiers: diff --git a/src/components/popover/tab/keypress/keypress-tab.component.ts b/src/components/popover/tab/keypress/keypress-tab.component.ts index eebc321d..43670ce3 100644 --- a/src/components/popover/tab/keypress/keypress-tab.component.ts +++ b/src/components/popover/tab/keypress/keypress-tab.component.ts @@ -66,6 +66,17 @@ export class KeypressTabComponent implements OnChanges, Tab { return keystrokeAction.scancode > 0 || keystrokeAction.modifierMask > 0; } + onKeysCapture(event: {code: number, left: boolean[], right: boolean[]}) { + if (event.code) { + this.scanCode = event.code; + } else { + this.scanCode = 0; + } + + this.leftModifierSelects = event.left; + this.rightModifierSelects = event.right; + } + fromKeyAction(keyAction: KeyAction): boolean { if (!(keyAction instanceof KeystrokeAction)) { return false; @@ -139,17 +150,11 @@ export class KeypressTabComponent implements OnChanges, Tab { modifierSelects[index] = !modifierSelects[index]; } - // TODO: change to the correct type when the wrapper has added it. - /* tslint:disable:no-unused-variable: It is used in the template. */ - private onLongpressChange(event: any) { - /* tslint:enable:no-unused-variable: */ + onLongpressChange(event: {value: string}) { this.selectedLongPressIndex = +event.value; } - // TODO: change to the correct type when the wrapper has added it. - /* tslint:disable:no-unused-variable: It is used in the template. */ - private onScancodeChange(event: any) { - /* tslint:enable:no-unused-variable */ + onScancodeChange(event: {value: string}) { this.scanCode = +event.value; } diff --git a/src/components/popover/widgets/capture-keystroke/capture-keystroke-button.component.html b/src/components/popover/widgets/capture-keystroke/capture-keystroke-button.component.html index d27114dd..91e06d41 100644 --- a/src/components/popover/widgets/capture-keystroke/capture-keystroke-button.component.html +++ b/src/components/popover/widgets/capture-keystroke/capture-keystroke-button.component.html @@ -1,11 +1,12 @@ \ No newline at end of file diff --git a/src/components/popover/widgets/capture-keystroke/capture-keystroke-button.component.ts b/src/components/popover/widgets/capture-keystroke/capture-keystroke-button.component.ts index ebb2d271..129df98c 100644 --- a/src/components/popover/widgets/capture-keystroke/capture-keystroke-button.component.ts +++ b/src/components/popover/widgets/capture-keystroke/capture-keystroke-button.component.ts @@ -1,23 +1,76 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, EventEmitter, HostListener, Output } from '@angular/core'; +import { CaptureService } from '../../../../services/capture.service'; @Component({ selector: 'capture-keystroke-button', template: require('./capture-keystroke-button.component.html'), styles: [require('./capture-keystroke-button.component.scss')] }) -export class CaptureKeystrokeButtonComponent implements OnInit { +export class CaptureKeystrokeButtonComponent { + @Output() capture = new EventEmitter(); + private record: boolean; + private first: boolean; // enable usage of Enter to start capturing - constructor() { } + constructor(private captureService: CaptureService) { + this.record = false; + this.captureService.initModifiers(); + this.captureService.populateMapping(); + } - ngOnInit() { } + @HostListener('keyup') + onKeyUp() { + if (this.record && !this.first) { + this.saveScanCode(); + } + } + + @HostListener('keydown', ['$event']) + onKeyDown(e: KeyboardEvent) { + const code: number = e.keyCode; + const enter = 13; + + if (this.record) { + e.preventDefault(); + this.first = false; + + if (this.captureService.hasMap(code)) { + this.saveScanCode(this.captureService.getMap(code)); + } else { + this.captureService.setModifier((e.location === 1), code); + } + } else if (code === enter) { + this.record = true; + this.first = true; + } + } + + @HostListener('focusout') + onFocusOut() { + this.record = false; + this.reset(); + } start(): void { this.record = true; } - stop(): void { + private saveScanCode(code?: number) { this.record = false; + const left: boolean[] = this.captureService.getModifiers(true); + const right: boolean[] = this.captureService.getModifiers(false); + + this.capture.emit({ + code, + left, + right + }); + + this.reset(); } + private reset() { + this.first = false; + this.captureService.initModifiers(); + } } diff --git a/src/services/capture.service.ts b/src/services/capture.service.ts new file mode 100644 index 00000000..dbb4b84b --- /dev/null +++ b/src/services/capture.service.ts @@ -0,0 +1,142 @@ +import { Injectable } from '@angular/core'; + +@Injectable() +export class CaptureService { + private mapping: Map; + private leftModifiers: Map; + private rightModifiers: Map; + + constructor() { + this.leftModifiers = new Map(); + this.rightModifiers = new Map(); + this.mapping = new Map(); + } + + public getMap(code: number) { + return this.mapping.get(code); + } + + public hasMap(code: number) { + return this.mapping.has(code); + } + + public setModifier(left: boolean, code: number) { + return left ? this.leftModifiers.set(code, true) : this.rightModifiers.set(code, true); + } + + public getModifiers(left: boolean) { + return left ? this.reMap(this.leftModifiers) : this.reMap(this.rightModifiers); + } + + public initModifiers() { + this.leftModifiers.set(16, false); // Shift + this.leftModifiers.set(17, false); // Ctrl + this.leftModifiers.set(18, false); // Alt + this.leftModifiers.set(91, false); // Super + + this.rightModifiers.set(16, false); // Shift + this.rightModifiers.set(17, false); // Ctrl + this.rightModifiers.set(18, false); // Alt + this.rightModifiers.set(91, false); // Super + } + + public populateMapping () { + this.mapping.set(8, 42); // Backspace + this.mapping.set(9, 43); // Tab + this.mapping.set(13, 40); // Enter + this.mapping.set(19, 72); // Pause/break + this.mapping.set(20, 57); // Caps lock + this.mapping.set(27, 41); // Escape + this.mapping.set(32, 44); // (space) + this.mapping.set(33, 75); // Page up + this.mapping.set(34, 78); // Page down + this.mapping.set(35, 77); // End + this.mapping.set(36, 74); // Home + this.mapping.set(37, 80); // Left arrow + this.mapping.set(38, 82); // Up arrow + this.mapping.set(39, 79); // Right arrow + this.mapping.set(40, 81); // Down arrow + this.mapping.set(45, 73); // Insert + this.mapping.set(46, 76); // Delete + this.mapping.set(48, 39); // 0 + this.mapping.set(49, 30); // 1 + this.mapping.set(50, 31); // 2 + this.mapping.set(51, 32); // 3 + this.mapping.set(52, 33); // 4 + this.mapping.set(53, 34); // 5 + this.mapping.set(54, 35); // 6 + this.mapping.set(55, 36); // 7 + this.mapping.set(56, 37); // 8 + this.mapping.set(57, 38); // 9 + this.mapping.set(65, 4); // A + this.mapping.set(66, 5); // B + this.mapping.set(67, 6); // C + this.mapping.set(68, 7); // D + this.mapping.set(69, 8); // E + this.mapping.set(70, 9); // F + this.mapping.set(71, 10); // G + this.mapping.set(72, 11); // H + this.mapping.set(73, 12); // I + this.mapping.set(74, 13); // J + this.mapping.set(75, 14); // K + this.mapping.set(76, 15); // L + this.mapping.set(77, 16); // M + this.mapping.set(78, 17); // N + this.mapping.set(79, 18); // O + this.mapping.set(80, 19); // P + this.mapping.set(81, 20); // Q + this.mapping.set(82, 21); // R + this.mapping.set(83, 22); // S + this.mapping.set(84, 23); // T + this.mapping.set(85, 24); // U + this.mapping.set(86, 25); // V + this.mapping.set(87, 26); // W + this.mapping.set(88, 27); // X + this.mapping.set(89, 28); // Y + this.mapping.set(90, 29); // Z + this.mapping.set(96, 98); // Num pad 0 + this.mapping.set(97, 89); // Num pad 1 + this.mapping.set(98, 90); // Num pad 2 + this.mapping.set(99, 91); // Num pad 3 + this.mapping.set(100, 92); // Num pad 4 + this.mapping.set(101, 93); // Num pad 5 + this.mapping.set(102, 94); // Num pad 6 + this.mapping.set(103, 95); // Num pad 7 + this.mapping.set(104, 96); // Num pad 8 + this.mapping.set(105, 97); // Num pad 9 + this.mapping.set(106, 85); // Multiply + this.mapping.set(107, 87); // Add + this.mapping.set(109, 86); // Subtract + this.mapping.set(110, 99); // Decimal point + this.mapping.set(111, 84); // Divide + this.mapping.set(112, 58); // F1 + this.mapping.set(113, 59); // F2 + this.mapping.set(114, 60); // F3 + this.mapping.set(115, 61); // F4 + this.mapping.set(116, 62); // F5 + this.mapping.set(117, 63); // F6 + this.mapping.set(118, 64); // F7 + this.mapping.set(119, 65); // F8 + this.mapping.set(120, 66); // F9 + this.mapping.set(121, 67); // F10 + this.mapping.set(122, 68); // F11 + this.mapping.set(123, 69); // F12 + this.mapping.set(144, 83); // Num lock + this.mapping.set(145, 71); // Scroll lock + this.mapping.set(186, 51); // Semi-colon + this.mapping.set(187, 46); // Equal sign + this.mapping.set(188, 54); // Comma + this.mapping.set(189, 45); // Dash + this.mapping.set(190, 55); // Period + this.mapping.set(191, 56); // Forward slash + this.mapping.set(192, 53); // Grave accent + this.mapping.set(219, 47); // Open bracket + this.mapping.set(220, 49); // Back slash + this.mapping.set(221, 48); // Close bracket + this.mapping.set(222, 52); // Single quote + } + + private reMap(value: Map): boolean[] { + return [value.get(16), value.get(17), value.get(91), value.get(18)]; + } +}