feat: display OS-specific modifiers (#764)

* chore: git ignore "out-tsc/" folder in uhk-web package

* feat: add OperationSystem calculation to the app reducer

* feat: create os specific key modifier

* feat: Os specific texts

* revert: KeyModifierValues and getKeyModifiers selector

* refactor: remove unnecessary return

* refactor: rename OperationSystem => OperatingSystem
This commit is contained in:
Róbert Kiss
2018-09-03 00:21:55 +02:00
committed by László Monda
parent aba0b09109
commit 3e4d439852
10 changed files with 130 additions and 27 deletions

1
packages/uhk-web/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
out-tsc/

View File

@@ -43,4 +43,4 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -29,8 +29,18 @@ export class KeypressTabComponent extends Tab implements OnChanges {
constructor(private mapper: MapperService) { constructor(private mapper: MapperService) {
super(); super();
this.leftModifiers = ['LShift', 'LCtrl', 'LSuper', 'LAlt']; this.leftModifiers = [
this.rightModifiers = ['RShift', 'RCtrl', 'RSuper', 'RAlt']; 'LShift',
'LCtrl',
mapper.getOsSpecificText('LSuper'),
mapper.getOsSpecificText('LAlt')
];
this.rightModifiers = [
'RShift',
'RCtrl',
mapper.getOsSpecificText('RSuper'),
mapper.getOsSpecificText('RAlt')
];
this.scanCodeGroups = [{ this.scanCodeGroups = [{
id: '0', id: '0',
text: 'None' text: 'None'

View File

@@ -27,6 +27,7 @@ import { MapperService } from '../../../../services/mapper.service';
import { AppState } from '../../../../store'; import { AppState } from '../../../../store';
import { getMacros } from '../../../../store/reducers/user-configuration'; import { getMacros } from '../../../../store/reducers/user-configuration';
import { SvgKeyCaptureEvent, SvgKeyClickEvent } from '../../../../models/svg-key-events'; import { SvgKeyCaptureEvent, SvgKeyClickEvent } from '../../../../models/svg-key-events';
import { OperatingSystem } from '../../../../models/operating-system';
enum LabelTypes { enum LabelTypes {
KeystrokeKey, KeystrokeKey,
@@ -293,29 +294,32 @@ export class SvgKeyboardKeyComponent implements OnInit, OnChanges, OnDestroy {
} }
} }
} else if (keyAction.hasOnlyOneActiveModifier() && !keyAction.hasScancode()) { } else if (keyAction.hasOnlyOneActiveModifier() && !keyAction.hasScancode()) {
newLabelSource = [];
switch (keyAction.modifierMask) { switch (keyAction.modifierMask) {
case KeyModifiers.leftCtrl: case KeyModifiers.leftCtrl:
case KeyModifiers.rightCtrl: case KeyModifiers.rightCtrl:
newLabelSource.push('Ctrl'); this.labelSource = ['Ctrl'];
break; break;
case KeyModifiers.leftShift: case KeyModifiers.leftShift:
case KeyModifiers.rightShift: case KeyModifiers.rightShift:
newLabelSource.push('Shift'); this.labelSource = ['Shift'];
break; break;
case KeyModifiers.leftAlt: case KeyModifiers.leftAlt:
case KeyModifiers.rightAlt: case KeyModifiers.rightAlt:
newLabelSource.push('Alt'); this.labelSource = [this.mapper.getOsSpecificText('Alt')];
break; break;
case KeyModifiers.leftGui: case KeyModifiers.leftGui:
case KeyModifiers.rightGui: case KeyModifiers.rightGui:
newLabelSource.push('Super'); if (this.mapper.getOperatingSystem() === OperatingSystem.Windows) {
this.labelSource = this.mapper.getIcon('command');
this.labelType = LabelTypes.SingleIcon;
} else {
this.labelSource = [this.mapper.getOsSpecificText('Super')];
}
break; break;
default: default:
newLabelSource.push('Undefined'); this.labelSource = ['Undefined'];
break; break;
} }
this.labelSource = newLabelSource;
} else { } else {
this.labelType = LabelTypes.KeystrokeKey; this.labelType = LabelTypes.KeystrokeKey;
this.labelSource = this.keyAction; this.labelSource = this.keyAction;

View File

@@ -28,10 +28,12 @@
</svg> </svg>
<svg viewBox="0 0 100 100" [attr.width]="option.width" [attr.height]="option.height" [attr.x]="option.x" [attr.y]="option.y" <svg viewBox="0 0 100 100" [attr.width]="option.width" [attr.height]="option.height" [attr.x]="option.x" [attr.y]="option.y"
preserveAspectRatio="none" [class.disabled]="option.disabled"> preserveAspectRatio="none" [class.disabled]="option.disabled">
<svg:use [attr.xlink:href]="modifierIconNames.option" /> <svg:use *ngIf="modifierIconNames.option" [attr.xlink:href]="modifierIconNames.option" />
<svg:text *ngIf="!modifierIconNames.option" [attr.text-anchor]="'middle'" [attr.x]="50" [attr.y]="50">A</svg:text>
</svg> </svg>
<svg viewBox="0 0 100 100" [attr.width]="command.width" [attr.height]="command.height" [attr.x]="command.x" [attr.y]="command.y" <svg viewBox="0 0 100 100" [attr.width]="command.width" [attr.height]="command.height" [attr.x]="command.x" [attr.y]="command.y"
preserveAspectRatio="none" [class.disabled]="command.disabled"> preserveAspectRatio="none" [class.disabled]="command.disabled">
<svg:use [attr.xlink:href]="modifierIconNames.command" /> <svg:use *ngIf="modifierIconNames.command" [attr.xlink:href]="modifierIconNames.command" />
<svg:text *ngIf="!modifierIconNames.command" [attr.text-anchor]="'middle'" [attr.x]="50" [attr.y]="50">S</svg:text>
</svg> </svg>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -0,0 +1,5 @@
export enum OperatingSystem {
Linux,
Mac,
Windows
}

View File

@@ -1,22 +1,37 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Store } from '@ngrx/store';
import { KeystrokeType } from 'uhk-common'; import { KeystrokeType } from 'uhk-common';
import { Subscription } from 'rxjs/Subscription';
import { AppState, getOperatingSystem } from '../store';
import { OperatingSystem } from '../models/operating-system';
@Injectable() @Injectable()
export class MapperService { export class MapperService {
private basicScanCodeTextMap: Map<number, string[]>; private basicScanCodeTextMap: Map<number, string[]>;
private mediaScanCodeTextMap: Map<number, string[]>; private mediaScanCodeTextMap: Map<number, string[]>;
private sytemScanCodeTextMap: Map<number, string[]>; private systemScanCodeTextMap: Map<number, string[]>;
private basicScancodeIcons: Map<number, string>; private basicScancodeIcons: Map<number, string>;
private mediaScancodeIcons: Map<number, string>; private mediaScancodeIcons: Map<number, string>;
private systemScancodeIcons: Map<number, string>; private systemScancodeIcons: Map<number, string>;
private nameToFileName: Map<string, string>; private nameToFileName: Map<string, string>;
private osSpecificTexts: Map<string, string>;
constructor() { private operatingSystem: OperatingSystem;
this.initScanCodeTextMap(); private osSubscription: Subscription;
this.initScancodeIcons();
this.initNameToFileNames(); constructor(private store: Store<AppState>) {
this.osSubscription = store
.select(getOperatingSystem)
.subscribe(os => {
this.operatingSystem = os;
this.initOsSpecificText();
this.initScanCodeTextMap();
this.initScancodeIcons();
this.initNameToFileNames();
});
} }
public scanCodeToText(scanCode: number, type: KeystrokeType = KeystrokeType.basic): string[] { public scanCodeToText(scanCode: number, type: KeystrokeType = KeystrokeType.basic): string[] {
@@ -27,7 +42,7 @@ export class MapperService {
map = this.mediaScanCodeTextMap; map = this.mediaScanCodeTextMap;
break; break;
case KeystrokeType.system: case KeystrokeType.system:
map = this.sytemScanCodeTextMap; map = this.systemScanCodeTextMap;
break; break;
default: default:
map = this.basicScanCodeTextMap; map = this.basicScanCodeTextMap;
@@ -79,7 +94,10 @@ export class MapperService {
} }
public getIcon(iconName: string): string { public getIcon(iconName: string): string {
return 'assets/compiled_sprite.svg#' + this.nameToFileName.get(iconName); const mappedIconName = this.nameToFileName.get(iconName);
if (mappedIconName) {
return 'assets/compiled_sprite.svg#' + mappedIconName;
}
} }
public modifierMapper(x: number) { public modifierMapper(x: number) {
@@ -90,6 +108,33 @@ export class MapperService {
} }
} }
public getOperatingSystem(): OperatingSystem {
return this.operatingSystem;
}
public getOsSpecificText(key: string): string {
const text = this.osSpecificTexts.get(key);
return text ? text : key;
}
private initOsSpecificText(): void {
this.osSpecificTexts = new Map<string, string>();
if (this.operatingSystem === OperatingSystem.Mac) {
this.osSpecificTexts.set('Enter', 'Return');
this.osSpecificTexts.set('Alt', 'Option');
this.osSpecificTexts.set('Super', 'Cmd');
this.osSpecificTexts.set('LSuper', 'LCmd');
this.osSpecificTexts.set('RSuper', 'RCmd');
this.osSpecificTexts.set('LAlt', 'LOption');
this.osSpecificTexts.set('RAlt', 'ROption');
} else if (this.operatingSystem === OperatingSystem.Windows) {
this.osSpecificTexts.set('LSuper', 'LWindows');
this.osSpecificTexts.set('RSuper', 'RWindows');
}
}
// TODO: read the mapping from JSON // TODO: read the mapping from JSON
private initScanCodeTextMap(): void { private initScanCodeTextMap(): void {
this.basicScanCodeTextMap = new Map<number, string[]>(); this.basicScanCodeTextMap = new Map<number, string[]>();
@@ -129,7 +174,7 @@ export class MapperService {
this.basicScanCodeTextMap.set(37, ['8', '*']); this.basicScanCodeTextMap.set(37, ['8', '*']);
this.basicScanCodeTextMap.set(38, ['9', '(']); this.basicScanCodeTextMap.set(38, ['9', '(']);
this.basicScanCodeTextMap.set(39, ['0', ')']); this.basicScanCodeTextMap.set(39, ['0', ')']);
this.basicScanCodeTextMap.set(40, ['Enter']); this.basicScanCodeTextMap.set(40, [this.getOsSpecificText('Enter')]);
this.basicScanCodeTextMap.set(41, ['Esc']); this.basicScanCodeTextMap.set(41, ['Esc']);
this.basicScanCodeTextMap.set(42, ['Backspace']); this.basicScanCodeTextMap.set(42, ['Backspace']);
this.basicScanCodeTextMap.set(43, ['Tab']); this.basicScanCodeTextMap.set(43, ['Tab']);
@@ -177,7 +222,7 @@ export class MapperService {
this.basicScanCodeTextMap.set(85, ['*']); this.basicScanCodeTextMap.set(85, ['*']);
this.basicScanCodeTextMap.set(86, ['-']); this.basicScanCodeTextMap.set(86, ['-']);
this.basicScanCodeTextMap.set(87, ['+']); this.basicScanCodeTextMap.set(87, ['+']);
this.basicScanCodeTextMap.set(88, ['Enter']); this.basicScanCodeTextMap.set(88, [this.getOsSpecificText('Enter')]);
this.basicScanCodeTextMap.set(89, ['end', '1']); this.basicScanCodeTextMap.set(89, ['end', '1']);
this.basicScanCodeTextMap.set(90, ['2']); this.basicScanCodeTextMap.set(90, ['2']);
this.basicScanCodeTextMap.set(91, ['pgdn', '3']); this.basicScanCodeTextMap.set(91, ['pgdn', '3']);
@@ -224,10 +269,10 @@ export class MapperService {
this.mediaScanCodeTextMap.set(394, ['Launch Email Client']); this.mediaScanCodeTextMap.set(394, ['Launch Email Client']);
this.mediaScanCodeTextMap.set(402, ['Launch Calculator']); this.mediaScanCodeTextMap.set(402, ['Launch Calculator']);
this.sytemScanCodeTextMap = new Map<number, string[]>(); this.systemScanCodeTextMap = new Map<number, string[]>();
this.sytemScanCodeTextMap.set(129, ['Power Down']); this.systemScanCodeTextMap.set(129, ['Power Down']);
this.sytemScanCodeTextMap.set(130, ['Sleep']); this.systemScanCodeTextMap.set(130, ['Sleep']);
this.sytemScanCodeTextMap.set(131, ['Wake Up']); this.systemScanCodeTextMap.set(131, ['Wake Up']);
} }
private initScancodeIcons(): void { private initScancodeIcons(): void {
@@ -266,8 +311,12 @@ export class MapperService {
this.nameToFileName.set('switch-keymap', 'icon-kbd__mod--switch-keymap'); this.nameToFileName.set('switch-keymap', 'icon-kbd__mod--switch-keymap');
this.nameToFileName.set('macro', 'icon-icon__macro'); this.nameToFileName.set('macro', 'icon-icon__macro');
this.nameToFileName.set('shift', 'icon-kbd__default--modifier-shift'); this.nameToFileName.set('shift', 'icon-kbd__default--modifier-shift');
this.nameToFileName.set('option', 'icon-kbd__default--modifier-option'); if (this.operatingSystem === OperatingSystem.Mac) {
this.nameToFileName.set('command', 'icon-kbd__default--modifier-command'); this.nameToFileName.set('option', 'icon-kbd__default--modifier-option');
this.nameToFileName.set('command', 'icon-kbd__default--modifier-command');
} else if (this.operatingSystem === OperatingSystem.Windows) {
this.nameToFileName.set('command', 'icon-kbd__default--modifier-windows');
}
this.nameToFileName.set('mouse', 'icon-kbd__mouse'); this.nameToFileName.set('mouse', 'icon-kbd__mouse');
this.nameToFileName.set('left-arrow', 'icon-kbd__mod--arrow-left'); this.nameToFileName.set('left-arrow', 'icon-kbd__mod--arrow-left');
this.nameToFileName.set('right-arrow', 'icon-kbd__mod--arrow-right'); this.nameToFileName.set('right-arrow', 'icon-kbd__mod--arrow-right');

View File

@@ -10,6 +10,7 @@ import * as fromAppUpdate from './reducers/app-update.reducer';
import * as autoUpdateSettings from './reducers/auto-update-settings'; import * as autoUpdateSettings from './reducers/auto-update-settings';
import * as fromApp from './reducers/app.reducer'; import * as fromApp from './reducers/app.reducer';
import * as fromDevice from './reducers/device'; import * as fromDevice from './reducers/device';
import * as fromSelectors from './reducers/selectors';
import { initProgressButtonState } from './reducers/progress-button-state'; import { initProgressButtonState } from './reducers/progress-button-state';
import { environment } from '../../environments/environment'; import { environment } from '../../environments/environment';
import { RouterStateUrl } from './router-util'; import { RouterStateUrl } from './router-util';
@@ -52,6 +53,7 @@ export const getKeyboardLayout = createSelector(appState, fromApp.getKeyboardLay
export const deviceConfigurationLoaded = createSelector(appState, fromApp.deviceConfigurationLoaded); export const deviceConfigurationLoaded = createSelector(appState, fromApp.deviceConfigurationLoaded);
export const getAgentVersionInfo = createSelector(appState, fromApp.getAgentVersionInfo); export const getAgentVersionInfo = createSelector(appState, fromApp.getAgentVersionInfo);
export const getPrivilegePageState = createSelector(appState, fromApp.getPrivilagePageState); export const getPrivilegePageState = createSelector(appState, fromApp.getPrivilagePageState);
export const getOperatingSystem = createSelector(appState, fromSelectors.getOperatingSystem);
export const runningOnNotSupportedWindows = createSelector(appState, fromApp.runningOnNotSupportedWindows); export const runningOnNotSupportedWindows = createSelector(appState, fromApp.runningOnNotSupportedWindows);
export const firmwareUpgradeAllowed = createSelector(runningOnNotSupportedWindows, notSupportedOs => !notSupportedOs); export const firmwareUpgradeAllowed = createSelector(runningOnNotSupportedWindows, notSupportedOs => !notSupportedOs);

View File

@@ -0,0 +1,29 @@
import { OperatingSystem } from '../../models/operating-system';
import { State } from './app.reducer';
export const getOperatingSystem = (state: State): OperatingSystem => {
if (state.runningInElectron) {
switch (state.platform) {
case 'darwin':
return OperatingSystem.Mac;
case 'win32':
return OperatingSystem.Windows;
default:
return OperatingSystem.Linux;
}
}
const platform = navigator.platform.toLowerCase();
if (platform.indexOf('mac') > -1) {
return OperatingSystem.Mac;
}
if (platform.indexOf('win') > -1) {
return OperatingSystem.Windows;
}
return OperatingSystem.Linux;
};

View File

@@ -0,0 +1 @@
export * from './get-operating-system.selector';