fix: key modifier reordering (#771)
This commit is contained in:
committed by
László Monda
parent
9a845d8f6a
commit
0466916be1
@@ -36,20 +36,20 @@
|
||||
<div class="btn-toolbar modifiers">
|
||||
<div class="btn-group btn-group-sm modifiers__left">
|
||||
<button type="button" class="btn btn-default"
|
||||
*ngFor="let modifier of leftModifiers; let index = index"
|
||||
[class.btn-primary]="leftModifierSelects[index]"
|
||||
(click)="toggleModifier(false, index)"
|
||||
*ngFor="let modifier of leftModifiers; trackBy:modifiersTrackBy"
|
||||
[class.btn-primary]="modifier.checked"
|
||||
(click)="toggleModifier(modifier)"
|
||||
>
|
||||
{{modifier}}
|
||||
{{ modifier.text }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="btn-group btn-group-sm modifiers__right">
|
||||
<button type="button" class="btn btn-default"
|
||||
*ngFor="let modifier of rightModifiers; let index = index"
|
||||
[class.btn-primary]="rightModifierSelects[index]"
|
||||
(click)="toggleModifier(true, index)"
|
||||
*ngFor="let modifier of rightModifiers; trackBy:modifiersTrackBy"
|
||||
[class.btn-primary]="modifier.checked"
|
||||
(click)="toggleModifier(modifier)"
|
||||
>
|
||||
{{modifier}}
|
||||
{{ modifier.text }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,8 @@ import { KeyAction, KeystrokeAction, KeystrokeType, SCANCODES, SECONDARY_ROLES }
|
||||
import { Tab } from '../tab';
|
||||
import { MapperService } from '../../../../services/mapper.service';
|
||||
import { SelectOptionData } from '../../../../models/select-option-data';
|
||||
import { KeyModifierModel } from '../../../../models/key-modifier-model';
|
||||
import { mapLeftRigthModifierToKeyActionModifier } from '../../../../util';
|
||||
|
||||
@Component({
|
||||
selector: 'keypress-tab',
|
||||
@@ -15,11 +17,8 @@ export class KeypressTabComponent extends Tab implements OnChanges {
|
||||
@Input() defaultKeyAction: KeyAction;
|
||||
@Input() secondaryRoleEnabled: boolean;
|
||||
|
||||
leftModifiers: string[];
|
||||
rightModifiers: string[];
|
||||
|
||||
leftModifierSelects: boolean[];
|
||||
rightModifierSelects: boolean[];
|
||||
leftModifiers: KeyModifierModel[];
|
||||
rightModifiers: KeyModifierModel[];
|
||||
|
||||
scanCodeGroups: Array<SelectOptionData>;
|
||||
secondaryRoleGroups: Array<SelectOptionData>;
|
||||
@@ -29,26 +28,15 @@ export class KeypressTabComponent extends Tab implements OnChanges {
|
||||
|
||||
constructor(private mapper: MapperService) {
|
||||
super();
|
||||
this.leftModifiers = [
|
||||
'LShift',
|
||||
'LCtrl',
|
||||
mapper.getOsSpecificText('LAlt'),
|
||||
mapper.getOsSpecificText('LSuper')
|
||||
];
|
||||
this.rightModifiers = [
|
||||
'RShift',
|
||||
'RCtrl',
|
||||
mapper.getOsSpecificText('RAlt'),
|
||||
mapper.getOsSpecificText('RSuper')
|
||||
];
|
||||
this.leftModifiers = mapper.getLeftKeyModifiers();
|
||||
this.rightModifiers = mapper.getRightKeyModifiers();
|
||||
|
||||
this.scanCodeGroups = [{
|
||||
id: '0',
|
||||
text: 'None'
|
||||
}];
|
||||
this.scanCodeGroups = this.scanCodeGroups.concat(SCANCODES);
|
||||
this.secondaryRoleGroups = SECONDARY_ROLES;
|
||||
this.leftModifierSelects = Array(this.leftModifiers.length).fill(false);
|
||||
this.rightModifierSelects = Array(this.rightModifiers.length).fill(false);
|
||||
this.selectedScancodeOption = this.scanCodeGroups[0];
|
||||
this.selectedSecondaryRoleIndex = -1;
|
||||
}
|
||||
@@ -66,15 +54,15 @@ export class KeypressTabComponent extends Tab implements OnChanges {
|
||||
return (keystrokeAction) ? (keystrokeAction.scancode > 0 || keystrokeAction.modifierMask > 0) : false;
|
||||
}
|
||||
|
||||
onKeysCapture(event: { code: number, left: boolean[], right: boolean[] }) {
|
||||
onKeysCapture(event: { code: number, left: KeyModifierModel[], right: KeyModifierModel[] }) {
|
||||
if (event.code) {
|
||||
this.selectedScancodeOption = this.findScancodeOptionByScancode(event.code, KeystrokeType.basic);
|
||||
} else {
|
||||
this.selectedScancodeOption = this.scanCodeGroups[0];
|
||||
}
|
||||
|
||||
this.leftModifierSelects = event.left;
|
||||
this.rightModifierSelects = event.right;
|
||||
this.leftModifiers = event.left;
|
||||
this.rightModifiers = event.right;
|
||||
this.validAction.emit(this.keyActionValid());
|
||||
}
|
||||
|
||||
@@ -86,16 +74,12 @@ export class KeypressTabComponent extends Tab implements OnChanges {
|
||||
// Restore selectedScancodeOption
|
||||
this.selectedScancodeOption = this.findScancodeOptionByScancode(keystrokeAction.scancode || 0, keystrokeAction.type);
|
||||
|
||||
const leftModifiersLength: number = this.leftModifiers.length;
|
||||
|
||||
// Restore modifiers
|
||||
for (let i = 0; i < leftModifiersLength; ++i) {
|
||||
this.leftModifierSelects[this.mapper.modifierMapper(i)] = ((keystrokeAction.modifierMask >> i) & 1) === 1;
|
||||
for (const modifier of this.leftModifiers) {
|
||||
modifier.checked = (keystrokeAction.modifierMask & modifier.value) > 0;
|
||||
}
|
||||
|
||||
for (let i = leftModifiersLength; i < leftModifiersLength + this.rightModifierSelects.length; ++i) {
|
||||
const index: number = this.mapper.modifierMapper(i) - leftModifiersLength;
|
||||
this.rightModifierSelects[index] = ((keystrokeAction.modifierMask >> i) & 1) === 1;
|
||||
for (const modifier of this.rightModifiers) {
|
||||
modifier.checked = (keystrokeAction.modifierMask & modifier.value) > 0;
|
||||
}
|
||||
|
||||
// Restore secondaryRoleAction
|
||||
@@ -117,11 +101,7 @@ export class KeypressTabComponent extends Tab implements OnChanges {
|
||||
} else {
|
||||
keystrokeAction.type = KeystrokeType[scTypePair[1]];
|
||||
}
|
||||
keystrokeAction.modifierMask = 0;
|
||||
const modifiers = this.leftModifierSelects.concat(this.rightModifierSelects).map(x => x ? 1 : 0);
|
||||
for (let i = 0; i < modifiers.length; ++i) {
|
||||
keystrokeAction.modifierMask |= modifiers[i] << this.mapper.modifierMapper(i);
|
||||
}
|
||||
keystrokeAction.modifierMask = mapLeftRigthModifierToKeyActionModifier(this.leftModifiers, this.rightModifiers);
|
||||
|
||||
keystrokeAction.secondaryRoleAction = this.selectedSecondaryRoleIndex === -1
|
||||
? undefined
|
||||
@@ -132,9 +112,8 @@ export class KeypressTabComponent extends Tab implements OnChanges {
|
||||
}
|
||||
}
|
||||
|
||||
toggleModifier(right: boolean, index: number) {
|
||||
const modifierSelects: boolean[] = right ? this.rightModifierSelects : this.leftModifierSelects;
|
||||
modifierSelects[index] = !modifierSelects[index];
|
||||
toggleModifier(modifier: KeyModifierModel): void {
|
||||
modifier.checked = !modifier.checked;
|
||||
|
||||
this.validAction.emit(this.keyActionValid());
|
||||
}
|
||||
@@ -149,6 +128,10 @@ export class KeypressTabComponent extends Tab implements OnChanges {
|
||||
this.validAction.emit(this.keyActionValid());
|
||||
}
|
||||
|
||||
modifiersTrackBy(index: number, modifier: KeyModifierModel): string {
|
||||
return `${modifier.value}${modifier.checked}`;
|
||||
}
|
||||
|
||||
private findScancodeOptionBy(predicate: (option: SelectOptionData) => boolean): SelectOptionData {
|
||||
let selectedOption: SelectOptionData;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, HostListener, Input, Output } from '@angular/core';
|
||||
import { CaptureService } from '../../../../services/capture.service';
|
||||
import { KeyModifierModel } from '../../../../models/key-modifier-model';
|
||||
|
||||
@Component({
|
||||
selector: 'capture-keystroke-button',
|
||||
@@ -68,8 +69,8 @@ export class CaptureKeystrokeButtonComponent {
|
||||
|
||||
private saveScanCode(code?: number) {
|
||||
this.record = false;
|
||||
const left: boolean[] = this.captureService.getModifiers(true);
|
||||
const right: boolean[] = this.captureService.getModifiers(false);
|
||||
const left: KeyModifierModel[] = this.captureService.getModifiers(true);
|
||||
const right: KeyModifierModel[] = this.captureService.getModifiers(false);
|
||||
|
||||
this.capture.emit({
|
||||
code,
|
||||
|
||||
@@ -28,6 +28,7 @@ import { AppState } from '../../../../store';
|
||||
import { getMacros } from '../../../../store/reducers/user-configuration';
|
||||
import { SvgKeyCaptureEvent, SvgKeyClickEvent } from '../../../../models/svg-key-events';
|
||||
import { OperatingSystem } from '../../../../models/operating-system';
|
||||
import { KeyModifierModel } from '../../../../models/key-modifier-model';
|
||||
|
||||
enum LabelTypes {
|
||||
KeystrokeKey,
|
||||
@@ -250,8 +251,8 @@ export class SvgKeyboardKeyComponent implements OnInit, OnChanges, OnDestroy {
|
||||
}
|
||||
|
||||
private saveScanCode(code = 0) {
|
||||
const left: boolean[] = this.captureService.getModifiers(true);
|
||||
const right: boolean[] = this.captureService.getModifiers(false);
|
||||
const left: KeyModifierModel[] = this.captureService.getModifiers(true);
|
||||
const right: KeyModifierModel[] = this.captureService.getModifiers(false);
|
||||
|
||||
this.capture.emit({
|
||||
captured: {
|
||||
|
||||
@@ -49,6 +49,7 @@ import {
|
||||
SvgKeyHoverEvent
|
||||
} from '../../../models/svg-key-events';
|
||||
import { RemapInfo } from '../../../models/remap-info';
|
||||
import { mapLeftRigthModifierToKeyActionModifier } from '../../../util';
|
||||
|
||||
interface NameValuePair {
|
||||
name: string;
|
||||
@@ -181,14 +182,9 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges {
|
||||
|
||||
onCapture(event: SvgKeyboardCaptureEvent): void {
|
||||
const keystrokeAction: KeystrokeAction = new KeystrokeAction();
|
||||
const modifiers = event.captured.left.concat(event.captured.right).map(x => x ? 1 : 0);
|
||||
|
||||
keystrokeAction.scancode = event.captured.code;
|
||||
keystrokeAction.modifierMask = 0;
|
||||
|
||||
for (let i = 0; i < modifiers.length; ++i) {
|
||||
keystrokeAction.modifierMask |= modifiers[i] << this.mapper.modifierMapper(i);
|
||||
}
|
||||
keystrokeAction.modifierMask = mapLeftRigthModifierToKeyActionModifier(event.captured.left, event.captured.right);
|
||||
|
||||
this.store.dispatch(
|
||||
KeymapActions.saveKey(
|
||||
|
||||
7
packages/uhk-web/src/app/models/key-modifier-model.ts
Normal file
7
packages/uhk-web/src/app/models/key-modifier-model.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { KeyModifiers } from 'uhk-common';
|
||||
|
||||
export interface KeyModifierModel {
|
||||
text: string;
|
||||
value: KeyModifiers;
|
||||
checked: boolean;
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import { KeyModifierModel } from './key-modifier-model';
|
||||
|
||||
export interface SvgKeyClickEvent {
|
||||
keyTarget: HTMLElement;
|
||||
shiftPressed?: boolean;
|
||||
@@ -14,8 +16,8 @@ export interface SvgKeyboardKeyClickEvent extends SvgModuleKeyClickEvent {
|
||||
|
||||
export interface KeyCaptureData {
|
||||
code: number;
|
||||
left: boolean[];
|
||||
right: boolean[];
|
||||
left: KeyModifierModel[];
|
||||
right: KeyModifierModel[];
|
||||
}
|
||||
|
||||
export interface SvgKeyCaptureEvent {
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { MapperService } from './mapper.service';
|
||||
import { KeyModifiers } from 'uhk-common';
|
||||
import { KeyModifierModel } from '../models/key-modifier-model';
|
||||
|
||||
@Injectable()
|
||||
export class CaptureService {
|
||||
private mapping: Map<number, number>;
|
||||
private leftModifiers: Map<number, boolean>;
|
||||
private rightModifiers: Map<number, boolean>;
|
||||
private readonly leftModifiers: Map<number, KeyModifierModel>;
|
||||
private readonly rightModifiers: Map<number, KeyModifierModel>;
|
||||
|
||||
constructor() {
|
||||
this.leftModifiers = new Map<number, boolean>();
|
||||
this.rightModifiers = new Map<number, boolean>();
|
||||
constructor(private mapper: MapperService) {
|
||||
this.leftModifiers = new Map<number, KeyModifierModel>();
|
||||
this.rightModifiers = new Map<number, KeyModifierModel>();
|
||||
this.mapping = new Map<number, number>();
|
||||
}
|
||||
|
||||
@@ -21,26 +25,61 @@ export class CaptureService {
|
||||
}
|
||||
|
||||
public setModifier(left: boolean, code: number) {
|
||||
return left ? this.leftModifiers.set(code, true) : this.rightModifiers.set(code, true);
|
||||
const map = left ? this.leftModifiers : this.rightModifiers;
|
||||
map.get(code).checked = true;
|
||||
}
|
||||
|
||||
public getModifiers(left: boolean) {
|
||||
return left ? this.reMap(this.leftModifiers) : this.reMap(this.rightModifiers);
|
||||
const map = left ? this.leftModifiers : this.rightModifiers;
|
||||
|
||||
return Array.from(map.values());
|
||||
}
|
||||
|
||||
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.leftModifiers.set(16, {
|
||||
text: 'LShift',
|
||||
value: KeyModifiers.leftShift,
|
||||
checked: false
|
||||
});
|
||||
this.leftModifiers.set(17, {
|
||||
text: 'LCtrl',
|
||||
value: KeyModifiers.leftCtrl,
|
||||
checked: false
|
||||
});
|
||||
this.leftModifiers.set(18, {
|
||||
text: this.mapper.getOsSpecificText('LAlt'),
|
||||
value: KeyModifiers.leftAlt,
|
||||
checked: false
|
||||
});
|
||||
this.leftModifiers.set(91, {
|
||||
text: this.mapper.getOsSpecificText('LSuper'),
|
||||
value: KeyModifiers.leftGui,
|
||||
checked: false
|
||||
});
|
||||
|
||||
this.rightModifiers.set(16, false); // Shift
|
||||
this.rightModifiers.set(17, false); // Ctrl
|
||||
this.rightModifiers.set(18, false); // Alt
|
||||
this.rightModifiers.set(91, false); // Super
|
||||
this.rightModifiers.set(16, {
|
||||
text: 'RShift',
|
||||
value: KeyModifiers.rightShift,
|
||||
checked: false
|
||||
});
|
||||
this.rightModifiers.set(17, {
|
||||
text: 'RCtrl',
|
||||
value: KeyModifiers.rightCtrl,
|
||||
checked: false
|
||||
});
|
||||
this.rightModifiers.set(18, {
|
||||
text: this.mapper.getOsSpecificText('RAlt'),
|
||||
value: KeyModifiers.rightAlt,
|
||||
checked: false
|
||||
});
|
||||
this.rightModifiers.set(91, {
|
||||
text: this.mapper.getOsSpecificText('RSuper'),
|
||||
value: KeyModifiers.rightGui,
|
||||
checked: false
|
||||
});
|
||||
}
|
||||
|
||||
public populateMapping () {
|
||||
public populateMapping() {
|
||||
this.mapping.set(8, 42); // Backspace
|
||||
this.mapping.set(9, 43); // Tab
|
||||
this.mapping.set(13, 40); // Enter
|
||||
@@ -136,8 +175,4 @@ export class CaptureService {
|
||||
this.mapping.set(221, 48); // Close bracket
|
||||
this.mapping.set(222, 52); // Single quote
|
||||
}
|
||||
|
||||
private reMap(value: Map<number, boolean>): boolean[] {
|
||||
return [value.get(16), value.get(17), value.get(91), value.get(18)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { KeystrokeType, SecondaryRoleAction } from 'uhk-common';
|
||||
import { KeyModifiers, KeystrokeType, SecondaryRoleAction } from 'uhk-common';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
|
||||
import { AppState, getOperatingSystem } from '../store';
|
||||
import { OperatingSystem } from '../models/operating-system';
|
||||
import { KeyModifierModel } from '../models/key-modifier-model';
|
||||
|
||||
@Injectable()
|
||||
export class MapperService {
|
||||
@@ -124,6 +125,56 @@ export class MapperService {
|
||||
return this.secondaryRoleTexts.get(secondaryRoleAction);
|
||||
}
|
||||
|
||||
public getLeftKeyModifiers(): KeyModifierModel[] {
|
||||
return [
|
||||
{
|
||||
text: 'LShift',
|
||||
value: KeyModifiers.leftShift,
|
||||
checked: false
|
||||
},
|
||||
{
|
||||
text: 'LCtrl',
|
||||
value: KeyModifiers.leftCtrl,
|
||||
checked: false
|
||||
},
|
||||
{
|
||||
text: this.getOsSpecificText('LAlt'),
|
||||
value: KeyModifiers.leftAlt,
|
||||
checked: false
|
||||
},
|
||||
{
|
||||
text: this.getOsSpecificText('LSuper'),
|
||||
value: KeyModifiers.leftGui,
|
||||
checked: false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
public getRightKeyModifiers(): KeyModifierModel[] {
|
||||
return [
|
||||
{
|
||||
text: 'RShift',
|
||||
value: KeyModifiers.rightShift,
|
||||
checked: false
|
||||
},
|
||||
{
|
||||
text: 'RCtrl',
|
||||
value: KeyModifiers.rightCtrl,
|
||||
checked: false
|
||||
},
|
||||
{
|
||||
text: this.getOsSpecificText('RAlt'),
|
||||
value: KeyModifiers.rightAlt,
|
||||
checked: false
|
||||
},
|
||||
{
|
||||
text: this.getOsSpecificText('RSuper'),
|
||||
value: KeyModifiers.rightGui,
|
||||
checked: false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
private initOsSpecificText(): void {
|
||||
this.osSpecificTexts = new Map<string, string>();
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from './find-new-item';
|
||||
export * from './html-helper';
|
||||
export * from './key-modifier-model-mapper';
|
||||
export * from './validators';
|
||||
export * from './version-helper';
|
||||
|
||||
13
packages/uhk-web/src/app/util/key-modifier-model-mapper.ts
Normal file
13
packages/uhk-web/src/app/util/key-modifier-model-mapper.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { KeyModifierModel } from '../models/key-modifier-model';
|
||||
|
||||
export const mapLeftRigthModifierToKeyActionModifier = (left: KeyModifierModel[], right: KeyModifierModel[]): number => {
|
||||
const modifiers = [...left, ...right];
|
||||
let result = 0;
|
||||
for (const modifier of modifiers) {
|
||||
if (modifier.checked) {
|
||||
result |= modifier.value;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
Reference in New Issue
Block a user