@@ -1,7 +1,9 @@
|
||||
<svg-keyboard *ngFor="let layer of layers; let index = index; trackBy: trackKeyboard"
|
||||
[@layerState]="layerAnimationState[index]"
|
||||
[moduleConfig]="layer.modules"
|
||||
[keybindAnimationEnabled]="keybindAnimationEnabled"
|
||||
(keyClick)="keyClick.emit($event)"
|
||||
(keyHover)="keyHover.emit($event)">
|
||||
[@layerState]="layerAnimationState[index]"
|
||||
[moduleConfig]="layer.modules"
|
||||
[keybindAnimationEnabled]="keybindAnimationEnabled"
|
||||
(keyClick)="keyClick.emit($event)"
|
||||
(keyHover)="keyHover.emit($event)"
|
||||
(capture)="capture.emit($event)"
|
||||
>
|
||||
</svg-keyboard>
|
||||
|
Before Width: | Height: | Size: 408 B After Width: | Height: | Size: 356 B |
@@ -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[];
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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)"
|
||||
/>
|
||||
</svg:g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 745 B After Width: | Height: | Size: 817 B |
@@ -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,
|
||||
|
||||
@@ -1,53 +1,65 @@
|
||||
<svg:rect [@change]="animation"
|
||||
(@change.done)="animationDone()"
|
||||
<svg:rect [@change]="changeAnimation"
|
||||
(@change.done)="onChangeAnimationDone()"
|
||||
[id]="id" [attr.rx]="rx" [attr.ry]="ry"
|
||||
[attr.height]="height" [attr.width]="width"
|
||||
[attr.fill]="fill"
|
||||
/>
|
||||
<svg:g [ngSwitch]="labelType"
|
||||
[attr.font-size]="19"
|
||||
[attr.font-family]="'Helvetica'"
|
||||
[attr.fill]="'white'">
|
||||
<svg:g svg-keystroke-key *ngSwitchCase="enumLabelTypes.KeystrokeKey"
|
||||
[height]="height"
|
||||
[width]="width"
|
||||
[keystrokeAction]="labelSource">
|
||||
<template [ngIf]="recording">
|
||||
<svg:circle
|
||||
[@recording]="recordAnimation"
|
||||
(@recording.done)="onRecordingAnimationDone()"
|
||||
[attr.cx]="(width / 2)"
|
||||
[attr.cy]="(height / 2)"
|
||||
[attr.r]="10"
|
||||
[attr.fill]="'#c00'"
|
||||
></svg:circle>
|
||||
</template>
|
||||
<template [ngIf]="!recording">
|
||||
<svg:g [ngSwitch]="labelType"
|
||||
[attr.font-size]="19"
|
||||
[attr.font-family]="'Helvetica'"
|
||||
[attr.fill]="'white'">
|
||||
<svg:g svg-keystroke-key *ngSwitchCase="enumLabelTypes.KeystrokeKey"
|
||||
[height]="height"
|
||||
[width]="width"
|
||||
[keystrokeAction]="labelSource">
|
||||
</svg:g>
|
||||
<svg:g svg-one-line-text-key *ngSwitchCase="enumLabelTypes.OneLineText"
|
||||
[height]="height"
|
||||
[width]="width"
|
||||
[text]="labelSource">
|
||||
</svg:g>
|
||||
<svg:g svg-two-line-text-key *ngSwitchCase="enumLabelTypes.TwoLineText"
|
||||
[height]="height"
|
||||
[width]="width"
|
||||
[texts]="labelSource">
|
||||
</svg:g>
|
||||
<svg:g svg-text-icon-key *ngSwitchCase="enumLabelTypes.TextIcon"
|
||||
[height]="height"
|
||||
[width]="width"
|
||||
[text]="labelSource.text"
|
||||
[icon]="labelSource.icon">
|
||||
</svg:g>
|
||||
<svg:g svg-icon-text-key *ngSwitchCase="enumLabelTypes.IconText"
|
||||
[height]="height"
|
||||
[width]="width"
|
||||
[icon]="labelSource.icon"
|
||||
[text]="labelSource.text">
|
||||
</svg:g>
|
||||
<svg:g svg-single-icon-key *ngSwitchCase="enumLabelTypes.SingleIcon"
|
||||
[height]="height"
|
||||
[width]="width"
|
||||
[icon]="labelSource">
|
||||
</svg:g>
|
||||
<svg:g svg-switch-keymap-key *ngSwitchCase="enumLabelTypes.SwitchKeymap"
|
||||
[height]="height"
|
||||
[width]="width"
|
||||
[abbreviation]="labelSource">
|
||||
</svg:g>
|
||||
<svg *ngSwitchCase="enumLabelTypes.MouseKey" [attr.viewBox]="'0 0 100 100'"
|
||||
[attr.width]="width"
|
||||
[attr.height]="height">
|
||||
<svg:g svg-mouse-key [mouseAction]="labelSource"></svg:g>
|
||||
</svg>
|
||||
</svg:g>
|
||||
<svg:g svg-one-line-text-key *ngSwitchCase="enumLabelTypes.OneLineText"
|
||||
[height]="height"
|
||||
[width]="width"
|
||||
[text]="labelSource">
|
||||
</svg:g>
|
||||
<svg:g svg-two-line-text-key *ngSwitchCase="enumLabelTypes.TwoLineText"
|
||||
[height]="height"
|
||||
[width]="width"
|
||||
[texts]="labelSource">
|
||||
</svg:g>
|
||||
<svg:g svg-text-icon-key *ngSwitchCase="enumLabelTypes.TextIcon"
|
||||
[height]="height"
|
||||
[width]="width"
|
||||
[text]="labelSource.text"
|
||||
[icon]="labelSource.icon">
|
||||
</svg:g>
|
||||
<svg:g svg-icon-text-key *ngSwitchCase="enumLabelTypes.IconText"
|
||||
[height]="height"
|
||||
[width]="width"
|
||||
[icon]="labelSource.icon"
|
||||
[text]="labelSource.text">
|
||||
</svg:g>
|
||||
<svg:g svg-single-icon-key *ngSwitchCase="enumLabelTypes.SingleIcon"
|
||||
[height]="height"
|
||||
[width]="width"
|
||||
[icon]="labelSource">
|
||||
</svg:g>
|
||||
<svg:g svg-switch-keymap-key *ngSwitchCase="enumLabelTypes.SwitchKeymap"
|
||||
[height]="height"
|
||||
[width]="width"
|
||||
[abbreviation]="labelSource">
|
||||
</svg:g>
|
||||
<svg *ngSwitchCase="enumLabelTypes.MouseKey" [attr.viewBox]="'0 0 100 100'"
|
||||
[attr.width]="width"
|
||||
[attr.height]="height">
|
||||
<svg:g svg-mouse-key [mouseAction]="labelSource"></svg:g>
|
||||
</svg>
|
||||
</svg:g>
|
||||
</template>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.4 KiB |
@@ -4,6 +4,7 @@
|
||||
}
|
||||
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
|
||||
&:hover {
|
||||
fill: #494949;
|
||||
|
||||
@@ -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<AppState>, 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<AppState>,
|
||||
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 {
|
||||
|
||||
@@ -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)"
|
||||
/>
|
||||
|
Before Width: | Height: | Size: 556 B After Width: | Height: | Size: 597 B |
@@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)"></keyboard-slider>
|
||||
(keyHover)="onKeyHover($event.moduleId, $event.event, $event.over, $event.keyId)"
|
||||
(capture)="onCapture($event.moduleId, $event.keyId, $event.captured)"
|
||||
></keyboard-slider>
|
||||
<popover tabindex="0" [visible]="popoverShown" [keyPosition]="keyPosition" [wrapPosition]="wrapPosition" [defaultKeyAction]="popoverInitKeyAction"
|
||||
[currentKeymap]="keymap" [currentLayer]="currentLayer" (cancel)="hidePopover()" (remap)="onRemap($event)"></popover>
|
||||
<div class="tooltip bottom"
|
||||
|
||||
@@ -139,6 +139,27 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges {
|
||||
}
|
||||
}
|
||||
|
||||
onCapture(moduleId: number, keyId: number, captured: {code: number, left: boolean[], right: boolean[]}): void {
|
||||
let keystrokeAction: KeystrokeAction = new KeystrokeAction();
|
||||
const modifiers = captured.left.concat(captured.right).map(x => 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<number, string[]>();
|
||||
|
||||