Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
440db56080 | ||
|
|
337e6e6bb6 | ||
|
|
a1aeda3d35 | ||
|
|
c6a83f8c9b | ||
|
|
0f24427628 | ||
|
|
f52dc36a6a | ||
|
|
63a936968d | ||
|
|
cabfde7963 | ||
|
|
79628c2351 | ||
|
|
762fa6f8bf | ||
|
|
a258c097a9 | ||
|
|
41faa98fcd | ||
|
|
c4d7318686 | ||
|
|
9ef11eaa34 | ||
|
|
f34cb2df56 | ||
|
|
83b9f0d1e9 | ||
|
|
7d81cf0c6a | ||
|
|
82b76a9455 | ||
|
|
4ae577f936 | ||
|
|
81a83994ab | ||
|
|
1d3a3c7f5f |
18
CHANGELOG.md
@@ -6,12 +6,26 @@ The format is loosely based on [Keep a Changelog](http://keepachangelog.com/en/1
|
||||
|
||||
Every Agent version includes the most recent firmware version. See the [firmware changelog](https://github.com/UltimateHackingKeyboard/firmware/blob/master/CHANGELOG.md).
|
||||
|
||||
## [1.2.3] - 2018-06-19
|
||||
|
||||
Firmware: 8.2.5 [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.2.5)] | Device Protocol: 4.3.1 | User Config: 4.0.1 | Hardware Config: 1.0.0
|
||||
|
||||
- Add checkboxes for remapping keys on all layers and/or all keymaps.
|
||||
- Add separator line between the keyboard halves.
|
||||
- Add double tap icon for switch layer actions.
|
||||
- Improve the looks and content of the tooltips of the key action popover.
|
||||
- Make the left keyboard half less likely to timeout during firmware update.
|
||||
- Terminate the firmware update process if blhost segfaults.
|
||||
- Replace the Linux x64 version of the blhost binary which should not make it segfault anymore.
|
||||
- Make the firmware update log shorter by listing one device per line and not repeating the list of available USB devices.
|
||||
- Make the firmware update help text shorter.
|
||||
|
||||
## [1.2.2] - 2018-05-27
|
||||
|
||||
Firmware: 8.2.**5** [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.2.5)] | Device Protocol: 4.3.**1** | User Config: 4.0.**1** | Hardware Config: 1.0.0
|
||||
Firmware: 8.2.**5** [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.2.5)] | Device Protocol: 4.3.**1** | User Config: 4.0.1 | Hardware Config: 1.0.0
|
||||
|
||||
- Offer recovery for bricked right keyboard halfs.
|
||||
- Detect when the hardware configuration of a device is invalid and display a notification.
|
||||
- Detect when the hardware configuration of a device is invalid and display a notification. `DEVICEPROTOCOL:PATCH`
|
||||
- Check if the keyboard is in factory reset mode and if so, display a relevant instruction.
|
||||
- Only allow ASCII characters in type text macro actions.
|
||||
- Allow uploading the same file multiple times in a row.
|
||||
|
||||
23
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "uhk-agent",
|
||||
"version": "1.2.1",
|
||||
"version": "1.2.2",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -96,6 +96,21 @@
|
||||
"@types/node": "8.0.53"
|
||||
}
|
||||
},
|
||||
"@types/lodash": {
|
||||
"version": "4.14.109",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.109.tgz",
|
||||
"integrity": "sha512-hop8SdPUEzbcJm6aTsmuwjIYQo1tqLseKCM+s2bBqTU2gErwI4fE+aqUVOlscPSQbKHKgtMMPoC+h4AIGOJYvw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/lodash-es": {
|
||||
"version": "4.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.0.tgz",
|
||||
"integrity": "sha512-h8lkWQSgT4qjs9PcIhcL2nWubZeXRVzjZxYlRFmcX9BW1PIk5qRc0djtRWZqtM+GDDFhwBt0ztRu72D/YxIcEw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/lodash": "4.14.109"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "8.0.53",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.0.53.tgz",
|
||||
@@ -8353,6 +8368,12 @@
|
||||
"integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash-es": {
|
||||
"version": "4.17.4",
|
||||
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.4.tgz",
|
||||
"integrity": "sha1-3MHXVS4VCgZABzupyzHXDwMpUOc=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash._arraymap": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._arraymap/-/lodash._arraymap-3.0.0.tgz",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"private": true,
|
||||
"author": "Ultimate Gadget Laboratories",
|
||||
"main": "electron/dist/electron-main.js",
|
||||
"version": "1.2.2",
|
||||
"version": "1.2.3",
|
||||
"firmwareVersion": "8.2.5",
|
||||
"deviceProtocolVersion": "4.3.1",
|
||||
"userConfigVersion": "4.0.1",
|
||||
@@ -25,6 +25,7 @@
|
||||
"@types/jasmine": "2.6.0",
|
||||
"@types/jquery": "3.3.1",
|
||||
"@types/jsonfile": "4.0.1",
|
||||
"@types/lodash-es": "4.17.0",
|
||||
"@types/node": "8.0.53",
|
||||
"@types/node-hid": "0.5.2",
|
||||
"@types/request": "2.0.8",
|
||||
@@ -53,6 +54,7 @@
|
||||
"gh-pages": "1.1.0",
|
||||
"jsonfile": "4.0.0",
|
||||
"lerna": "2.9.0",
|
||||
"lodash-es": "4.17.4",
|
||||
"mkdirp": "0.5.1",
|
||||
"node-hid": "0.5.7",
|
||||
"npm-run-all": "4.0.2",
|
||||
|
||||
@@ -21,7 +21,9 @@ import * as isDev from 'electron-is-dev';
|
||||
|
||||
const optionDefinitions = [
|
||||
{name: 'addons', type: Boolean},
|
||||
{name: 'spe', type: Boolean} // simulate privilege escalation error
|
||||
{name: 'spe', type: Boolean}, // simulate privilege escalation error
|
||||
// show 'Lock layer when double tapping this key' checkbox on 'Layer' tab of the config popover
|
||||
{name: 'layer-double-tap', type: Boolean}
|
||||
];
|
||||
|
||||
const options: CommandLineArgs = commandLineArgs(optionDefinitions);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BrowserWindow, ipcMain, shell } from 'electron';
|
||||
import { ipcMain, shell } from 'electron';
|
||||
import { UhkHidDevice } from 'uhk-usb';
|
||||
|
||||
import { AppStartInfo, IpcEvents, LogService } from 'uhk-common';
|
||||
@@ -25,7 +25,8 @@ export class AppService extends MainServiceBase {
|
||||
const deviceConnectionState = this.uhkHidDeviceService.getDeviceConnectionState();
|
||||
const response: AppStartInfo = {
|
||||
commandLineArgs: {
|
||||
addons: this.options.addons || false
|
||||
addons: this.options.addons || false,
|
||||
layerDoubleTap: this.options['layer-double-tap'] || false
|
||||
},
|
||||
deviceConnected: deviceConnectionState.connected,
|
||||
hasPermission: deviceConnectionState.hasPermission,
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import { binaryDefaultHelper, jsonDefaultHelper } from '../../../../test/serializer-test-helper';
|
||||
import { SwitchLayerAction } from './switch-layer-action';
|
||||
import { SwitchLayerAction, SwitchLayerMode } from './switch-layer-action';
|
||||
import { keyActionType } from './key-action';
|
||||
|
||||
// TODO: Add null, undefined, empty object, empty buffer test cases
|
||||
describe('switch-layer-action', () => {
|
||||
const action = new SwitchLayerAction(<SwitchLayerAction>{layer: 0, isLayerToggleable: false});
|
||||
const action = new SwitchLayerAction(<SwitchLayerAction>{layer: 0, switchLayerMode: SwitchLayerMode.hold});
|
||||
|
||||
it('should be instantiate', () => {
|
||||
expect(new SwitchLayerAction()).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('toString', () => {
|
||||
it('should return <SwitchLayerAction layer="0" toggle="false">', () => {
|
||||
expect(action.toString()).toEqual('<SwitchLayerAction layer="0" toggle="false">');
|
||||
it('should return <SwitchLayerAction layer="0" switchLayerMode="hold">', () => {
|
||||
expect(action.toString()).toEqual('<SwitchLayerAction layer="0" switchLayerMode="hold">');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -30,4 +31,20 @@ describe('switch-layer-action', () => {
|
||||
binaryDefaultHelper(action);
|
||||
});
|
||||
});
|
||||
|
||||
describe('backward compatibility of the "toggle" property ', () => {
|
||||
it('should map toggle=false to SwitchLayerMode.holdAndDoubleTapToggle', () => {
|
||||
const oldAction = new SwitchLayerAction();
|
||||
oldAction.fromJsonObject({keyActionType: keyActionType.SwitchLayerAction, layer: 0, toggle: false});
|
||||
|
||||
expect(oldAction.switchLayerMode).toEqual(SwitchLayerMode.holdAndDoubleTapToggle);
|
||||
});
|
||||
|
||||
it('should map toggle=true to SwitchLayerMode.toggle', () => {
|
||||
const oldAction = new SwitchLayerAction();
|
||||
oldAction.fromJsonObject({keyActionType: keyActionType.SwitchLayerAction, layer: 0, toggle: true});
|
||||
|
||||
expect(oldAction.switchLayerMode).toEqual(SwitchLayerMode.toggle);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,9 +8,48 @@ export enum LayerName {
|
||||
mouse
|
||||
}
|
||||
|
||||
export enum SwitchLayerMode {
|
||||
holdAndDoubleTapToggle = 'holdAndDoubleTapToggle',
|
||||
toggle = 'toggle',
|
||||
hold = 'hold'
|
||||
}
|
||||
|
||||
export const mapSwitchLayerModeToNumber = (switchLayerMode: SwitchLayerMode): number => {
|
||||
switch (switchLayerMode) {
|
||||
case SwitchLayerMode.holdAndDoubleTapToggle:
|
||||
return 0;
|
||||
|
||||
case SwitchLayerMode.toggle:
|
||||
return 1;
|
||||
|
||||
case SwitchLayerMode.hold:
|
||||
return 2;
|
||||
|
||||
default:
|
||||
throw new Error(`Can not map ${switchLayerMode} to number`);
|
||||
}
|
||||
};
|
||||
|
||||
export const mapNumberToSwitchLayerMode = (value: number): SwitchLayerMode => {
|
||||
switch (value) {
|
||||
case 0:
|
||||
return SwitchLayerMode.holdAndDoubleTapToggle;
|
||||
|
||||
case 1:
|
||||
return SwitchLayerMode.toggle;
|
||||
|
||||
case 2:
|
||||
return SwitchLayerMode.hold;
|
||||
|
||||
default:
|
||||
throw new Error(`Can not map "${value}" to SwitchLayerMode`);
|
||||
}
|
||||
};
|
||||
|
||||
export class SwitchLayerAction extends KeyAction {
|
||||
|
||||
isLayerToggleable: boolean;
|
||||
@assertEnum(SwitchLayerMode)
|
||||
switchLayerMode: SwitchLayerMode;
|
||||
|
||||
@assertEnum(LayerName)
|
||||
layer: LayerName;
|
||||
@@ -20,21 +59,29 @@ export class SwitchLayerAction extends KeyAction {
|
||||
if (!other) {
|
||||
return;
|
||||
}
|
||||
this.isLayerToggleable = other.isLayerToggleable;
|
||||
this.switchLayerMode = other.switchLayerMode;
|
||||
this.layer = other.layer;
|
||||
}
|
||||
|
||||
fromJsonObject(jsonObject: any): SwitchLayerAction {
|
||||
this.assertKeyActionType(jsonObject);
|
||||
this.layer = LayerName[<string>jsonObject.layer];
|
||||
this.isLayerToggleable = jsonObject.toggle;
|
||||
|
||||
// Backward compatibility when "switchLayerMode" was a boolean type as "toggle"
|
||||
if (typeof jsonObject.toggle === 'boolean') {
|
||||
this.switchLayerMode = jsonObject.toggle ? SwitchLayerMode.toggle : SwitchLayerMode.holdAndDoubleTapToggle;
|
||||
}
|
||||
else {
|
||||
this.switchLayerMode = jsonObject.switchLayerMode;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
fromBinary(buffer: UhkBuffer): SwitchLayerAction {
|
||||
this.readAndAssertKeyActionId(buffer);
|
||||
this.layer = buffer.readUInt8();
|
||||
this.isLayerToggleable = buffer.readBoolean();
|
||||
this.switchLayerMode = mapNumberToSwitchLayerMode(buffer.readUInt8());
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -42,18 +89,18 @@ export class SwitchLayerAction extends KeyAction {
|
||||
return {
|
||||
keyActionType: keyActionType.SwitchLayerAction,
|
||||
layer: LayerName[this.layer],
|
||||
toggle: this.isLayerToggleable
|
||||
switchLayerMode: this.switchLayerMode
|
||||
};
|
||||
}
|
||||
|
||||
toBinary(buffer: UhkBuffer) {
|
||||
buffer.writeUInt8(KeyActionId.SwitchLayerAction);
|
||||
buffer.writeUInt8(this.layer);
|
||||
buffer.writeBoolean(this.isLayerToggleable);
|
||||
buffer.writeUInt8(mapSwitchLayerModeToNumber(this.switchLayerMode));
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<SwitchLayerAction layer="${this.layer}" toggle="${this.isLayerToggleable}">`;
|
||||
return `<SwitchLayerAction layer="${this.layer}" switchLayerMode="${this.switchLayerMode}">`;
|
||||
}
|
||||
|
||||
public getName(): string {
|
||||
|
||||
@@ -127,7 +127,7 @@ export class Keymap {
|
||||
if (currentLayerId - 1 === baseKeyAction.layer) {
|
||||
if (currentKeyAction instanceof SwitchLayerAction) {
|
||||
if (currentKeyAction.layer === baseKeyAction.layer &&
|
||||
currentKeyAction.isLayerToggleable === baseKeyAction.isLayerToggleable) {
|
||||
currentKeyAction.switchLayerMode === baseKeyAction.switchLayerMode) {
|
||||
continue;
|
||||
}
|
||||
// tslint:disable-next-line: max-line-length
|
||||
|
||||
@@ -109,7 +109,7 @@ describe('keymap', () => {
|
||||
{
|
||||
keyActionType: 'switchLayer',
|
||||
layer: 'mod',
|
||||
toggle: false
|
||||
switchLayerMode: 'holdAndDoubleTapToggle'
|
||||
}
|
||||
]
|
||||
}]
|
||||
@@ -121,7 +121,7 @@ describe('keymap', () => {
|
||||
{
|
||||
keyActionType: 'switchLayer',
|
||||
layer: 'mod',
|
||||
toggle: false
|
||||
switchLayerMode: 'holdAndDoubleTapToggle'
|
||||
}
|
||||
]
|
||||
}]
|
||||
@@ -151,7 +151,7 @@ describe('keymap', () => {
|
||||
|
||||
expect(inputUserConfig.toJsonObject()).toEqual(expectedJsonConfig);
|
||||
// tslint:disable-next-line: max-line-length
|
||||
expect(console.warn).toHaveBeenCalledWith('QWERTY.layers[1]modules[0].keyActions[0] is not switch layer. <KeystrokeAction type="basic" scancode="44"> will be override with <SwitchLayerAction layer="0" toggle="false">');
|
||||
expect(console.warn).toHaveBeenCalledWith('QWERTY.layers[1]modules[0].keyActions[0] is not switch layer. <KeystrokeAction type="basic" scancode="44"> will be override with <SwitchLayerAction layer="0" switchLayerMode="holdAndDoubleTapToggle">');
|
||||
});
|
||||
|
||||
it('should normalize SwitchLayerAction if non base layer action is other SwitchLayerAction', () => {
|
||||
@@ -262,7 +262,7 @@ describe('keymap', () => {
|
||||
{
|
||||
keyActionType: 'switchLayer',
|
||||
layer: 'mod',
|
||||
toggle: false
|
||||
switchLayerMode: 'holdAndDoubleTapToggle'
|
||||
}
|
||||
]
|
||||
}]
|
||||
@@ -274,7 +274,7 @@ describe('keymap', () => {
|
||||
{
|
||||
keyActionType: 'switchLayer',
|
||||
layer: 'mod',
|
||||
toggle: false
|
||||
switchLayerMode: 'holdAndDoubleTapToggle'
|
||||
}
|
||||
]
|
||||
}]
|
||||
@@ -304,6 +304,6 @@ describe('keymap', () => {
|
||||
|
||||
expect(inputUserConfig.toJsonObject()).toEqual(expectedJsonConfig);
|
||||
// tslint:disable-next-line: max-line-length
|
||||
expect(console.warn).toHaveBeenCalledWith('QWERTY.layers[1]modules[0].keyActions[0] is different switch layer. <SwitchLayerAction layer="1" toggle="false"> will be override with <SwitchLayerAction layer="0" toggle="false">');
|
||||
expect(console.warn).toHaveBeenCalledWith('QWERTY.layers[1]modules[0].keyActions[0] is different switch layer. <SwitchLayerAction layer="1" switchLayerMode="holdAndDoubleTapToggle"> will be override with <SwitchLayerAction layer="0" switchLayerMode="holdAndDoubleTapToggle">');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,4 +7,9 @@ export interface CommandLineArgs {
|
||||
* simulate privilege escalation error
|
||||
*/
|
||||
spe?: boolean;
|
||||
/**
|
||||
* show 'Lock layer when double tapping this key' checkbox on 'Layer' tab of the config popover
|
||||
* if it false the checkbox invisible and the value of the checkbox = true
|
||||
*/
|
||||
layerDoubleTap?: boolean;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export namespace Constants {
|
||||
export const AGENT_GITHUB_URL = 'https://github.com/UltimateHackingKeyboard/agent';
|
||||
export const FIRMWARE_GITHUB_ISSUE_URL = 'https://github.com/UltimateHackingKeyboard/agent/issues/567';
|
||||
export const FIRMWARE_GITHUB_ISSUE_URL = 'https://github.com/UltimateHackingKeyboard/agent/issues/new';
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ export { IpcEvents } from './ipcEvents';
|
||||
export * from './log';
|
||||
export * from './constants';
|
||||
export * from './helpers';
|
||||
export * from './is-equal-array';
|
||||
|
||||
// Source: http://stackoverflow.com/questions/13720256/javascript-regex-camelcase-to-sentence
|
||||
export function camelCaseToSentence(camelCasedText: string): string {
|
||||
|
||||
15
packages/uhk-common/src/util/is-equal-array.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { isEqual } from 'lodash';
|
||||
|
||||
export const isEqualArray = (arr1: Array<any>, arr2: Array<any>): boolean => {
|
||||
if (arr1.length !== arr2.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const a of arr1) {
|
||||
if (!arr2.some(b => isEqual(a, b))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
5
packages/uhk-usb/package-lock.json
generated
@@ -144,11 +144,6 @@
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||
},
|
||||
"lodash-es": {
|
||||
"version": "4.17.10",
|
||||
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.10.tgz",
|
||||
"integrity": "sha512-iesFYPmxYYGTcmQK0sL8bX3TGHyM6b2qREaB4kamHfQyfPJP0xgoGxp19nsH16nsfquLdiyKyX3mQkfiSGV8Rg=="
|
||||
},
|
||||
"mimic-response": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.0.tgz",
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
"@types/node": "8.0.28"
|
||||
},
|
||||
"dependencies": {
|
||||
"lodash-es": "^4.17.10",
|
||||
"node-hid": "0.5.7",
|
||||
"uhk-common": "1.0.0"
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ export class UhkBlhost {
|
||||
|
||||
self.logService.debug(`[blhost] FINISHED: ${code}`);
|
||||
|
||||
if (code !== null && code !== 0) {
|
||||
if (code !== 0) {
|
||||
return reject(new Error(`blhost error code:${code}`));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { isEqual } from 'lodash';
|
||||
import { Device, devices, HID } from 'node-hid';
|
||||
import { CommandLineArgs, DeviceConnectionState, LogService } from 'uhk-common';
|
||||
import { CommandLineArgs, DeviceConnectionState, isEqualArray, LogService } from 'uhk-common';
|
||||
|
||||
import {
|
||||
ConfigBufferId,
|
||||
@@ -25,7 +24,7 @@ export class UhkHidDevice {
|
||||
* Internal variable that represent the USB UHK device
|
||||
* @private
|
||||
*/
|
||||
private _prevDevices = {};
|
||||
private _prevDevices = [];
|
||||
private _device: HID;
|
||||
private _hasPermission = false;
|
||||
|
||||
@@ -158,7 +157,7 @@ export class UhkHidDevice {
|
||||
}
|
||||
|
||||
public resetDeviceCache(): void {
|
||||
this._prevDevices = {};
|
||||
this._prevDevices = [];
|
||||
}
|
||||
|
||||
async reenumerate(enumerationMode: EnumerationModes): Promise<void> {
|
||||
@@ -252,8 +251,11 @@ export class UhkHidDevice {
|
||||
private connectToDevice(): HID {
|
||||
try {
|
||||
const devs = devices();
|
||||
if (!isEqual(this._prevDevices, devs)) {
|
||||
this.logService.debug('[UhkHidDevice] Available devices:', devs);
|
||||
if (!isEqualArray(this._prevDevices, devs)) {
|
||||
this.logService.debug('[UhkHidDevice] Available devices:');
|
||||
for (const logDevice of devs) {
|
||||
this.logService.debug(JSON.stringify(logDevice));
|
||||
}
|
||||
this._prevDevices = devs;
|
||||
} else {
|
||||
this.logService.debug('[UhkHidDevice] Available devices unchanged');
|
||||
@@ -266,7 +268,7 @@ export class UhkHidDevice {
|
||||
return null;
|
||||
}
|
||||
const device = new HID(dev.path);
|
||||
this.logService.debug('[UhkHidDevice] Used device:', dev);
|
||||
this.logService.debug('[UhkHidDevice] Used device:', JSON.stringify(dev));
|
||||
return device;
|
||||
}
|
||||
catch (err) {
|
||||
@@ -288,7 +290,7 @@ function kbootCommandName(module: ModuleSlotToI2cAddress): string {
|
||||
case ModuleSlotToI2cAddress.rightAddon:
|
||||
return 'rightAddon';
|
||||
|
||||
default :
|
||||
default:
|
||||
return 'Unknown';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,6 @@ export async function retry(command: Function, maxTry = 3, logService?: LogServi
|
||||
try {
|
||||
// logService.debug(`[retry] try to run FUNCTION:\n ${command}, \n retry: ${retryCount}`);
|
||||
await command();
|
||||
await snooze(100);
|
||||
// logService.debug(`[retry] success FUNCTION:\n ${command}, \n retry: ${retryCount}`);
|
||||
return;
|
||||
} catch (err) {
|
||||
@@ -93,6 +92,7 @@ export async function retry(command: Function, maxTry = 3, logService?: LogServi
|
||||
if (logService) {
|
||||
logService.info(`[retry] failed, but try run FUNCTION:\n ${command}, \n retry: ${retryCount}`);
|
||||
}
|
||||
await snooze(100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
18
packages/uhk-web/package-lock.json
generated
@@ -1260,19 +1260,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.2.9.tgz",
|
||||
"integrity": "sha512-AmYGadmTv+Xh6re2CH5ruyvV3znvtJbhxyT00JQAGFP2U+xgqhf+C2xfjdP/GgK5d9YmSif/UYs2ssMl4gW6fw=="
|
||||
},
|
||||
"@types/lodash": {
|
||||
"version": "4.14.106",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.106.tgz",
|
||||
"integrity": "sha512-tOSvCVrvSqFZ4A/qrqqm6p37GZoawsZtoR0SJhlF7EonNZUgrn8FfT+RNQ11h+NUpMt6QVe36033f3qEKBwfWA=="
|
||||
},
|
||||
"@types/lodash-es": {
|
||||
"version": "4.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.0.tgz",
|
||||
"integrity": "sha512-h8lkWQSgT4qjs9PcIhcL2nWubZeXRVzjZxYlRFmcX9BW1PIk5qRc0djtRWZqtM+GDDFhwBt0ztRu72D/YxIcEw==",
|
||||
"requires": {
|
||||
"@types/lodash": "4.14.106"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "9.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.2.tgz",
|
||||
@@ -6075,11 +6062,6 @@
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz",
|
||||
"integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw=="
|
||||
},
|
||||
"lodash-es": {
|
||||
"version": "4.17.4",
|
||||
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.4.tgz",
|
||||
"integrity": "sha1-3MHXVS4VCgZABzupyzHXDwMpUOc="
|
||||
},
|
||||
"lodash.assign": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz",
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
"@types/jasmine": "2.5.53",
|
||||
"@types/jasminewd2": "2.0.2",
|
||||
"@types/jquery": "3.2.9",
|
||||
"@types/lodash-es": "4.17.0",
|
||||
"@types/usb": "1.1.3",
|
||||
"angular-confirmation-popover": "3.2.0",
|
||||
"angular-notifier": "2.0.0",
|
||||
@@ -60,7 +59,6 @@
|
||||
"karma-coverage-istanbul-reporter": "1.2.1",
|
||||
"karma-jasmine": "1.1.0",
|
||||
"karma-jasmine-html-reporter": "0.2.2",
|
||||
"lodash-es": "4.17.4",
|
||||
"ng2-dragula": "1.5.0",
|
||||
"ng2-nouislider": "^1.7.7",
|
||||
"ng2-select2": "1.0.0-beta.10",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<ul class="list-unstyled btn-list">
|
||||
<li>
|
||||
<button class="btn btn-default"
|
||||
<button class="btn btn-primary"
|
||||
(click)="exportUserConfiguration($event)">Export device configuration
|
||||
</button>
|
||||
</li>
|
||||
|
||||
@@ -12,17 +12,11 @@
|
||||
Firmware {{ hardwareModules.rightModuleInfo.firmwareVersion }} is running on the right keyboard half.
|
||||
</p>
|
||||
|
||||
If the update process fails, consider the following points:
|
||||
<ol>
|
||||
<li>Windows 7, Windows Vista, and Windows XP are not supported. Use Linux, OSX, Windows 10, or Windows 8.</li>
|
||||
<li>Connect your UHK directly to the host computer. Don't use USB hubs or KVM switches.</li>
|
||||
<li>Run Agent directly on the host operating system. Don't use VirtualBox or VMware Workstation.</li>
|
||||
<li>Give a try to every USB port of your computer.</li>
|
||||
<li>Remove every other USB device from your computer.</li>
|
||||
<li>If the left half becomes unresponsive after a failed update then retry and follow the instructions displayed during the update to fix it.</li>
|
||||
<li>If the above fails, retry a couple of times.</li>
|
||||
<li>If everything else fails, please add a new comment to <a class="link-github" (click)="openFirmwareGitHubIssuePage($event)">the GitHub issue</a>, and attach the update log.</li>
|
||||
</ol>
|
||||
<p>Please note that firmware update doesn't work on Windows 7, Windows Vista, and Windows XP. Use Windows 10, Windows 8, Linux, or OSX instead.</p>
|
||||
|
||||
<p>If the update process fails, disconnect every USB device from your computer including USB hubs, KVM switches, and every USB device. Then connect only your UHK and retry.</p>
|
||||
|
||||
<p>If you tried the above and the update still keeps failing, please <a class="link-github" (click)="openFirmwareGitHubIssuePage($event)">create a GitHub issue</a>, and attach the update log.</p>
|
||||
|
||||
<p>
|
||||
<button class="btn btn-primary"
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<svg-keyboard-wrap [keymap]="keymap$ | async"
|
||||
[halvesSplit]="keyboardSplit"
|
||||
[keyboardLayout]="keyboardLayout$ | async"
|
||||
[allowLayerDoubleTap]="allowLayerDoubleTap$ | async"
|
||||
(descriptionChanged)="descriptionChanged($event)"></svg-keyboard-wrap>
|
||||
</ng-template>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, HostListener, ViewChild } from '@angular/core';
|
||||
import { Component, HostListener } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Keymap } from 'uhk-common';
|
||||
@@ -14,9 +14,8 @@ import 'rxjs/add/operator/combineLatest';
|
||||
|
||||
import { saveAs } from 'file-saver';
|
||||
|
||||
import { AppState, getKeyboardLayout } from '../../../store';
|
||||
import { allowLayerDoubleTap, AppState, getKeyboardLayout } from '../../../store';
|
||||
import { getKeymap, getKeymaps, getUserConfiguration } from '../../../store/reducers/user-configuration';
|
||||
import { SvgKeyboardWrapComponent } from '../../svg/wrap';
|
||||
import { KeyboardLayout } from '../../../keyboard/keyboard-layout.enum';
|
||||
import { KeymapActions } from '../../../store/actions';
|
||||
import { ChangeKeymapDescription } from '../../../models/ChangeKeymapDescription';
|
||||
@@ -31,13 +30,12 @@ import { ChangeKeymapDescription } from '../../../models/ChangeKeymapDescription
|
||||
})
|
||||
export class KeymapEditComponent {
|
||||
|
||||
@ViewChild(SvgKeyboardWrapComponent) wrap: SvgKeyboardWrapComponent;
|
||||
|
||||
keyboardSplit: boolean;
|
||||
|
||||
deletable$: Observable<boolean>;
|
||||
keymap$: Observable<Keymap>;
|
||||
keyboardLayout$: Observable<KeyboardLayout>;
|
||||
allowLayerDoubleTap$: Observable<boolean>;
|
||||
|
||||
constructor(protected store: Store<AppState>,
|
||||
route: ActivatedRoute) {
|
||||
@@ -52,6 +50,7 @@ export class KeymapEditComponent {
|
||||
.map((keymaps: Keymap[]) => keymaps.length > 1);
|
||||
|
||||
this.keyboardLayout$ = store.select(getKeyboardLayout);
|
||||
this.allowLayerDoubleTap$ = store.select(allowLayerDoubleTap);
|
||||
}
|
||||
|
||||
downloadKeymap() {
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
<layer-tab #tab *ngSwitchCase="tabName.Layer" class="popover-content"
|
||||
[defaultKeyAction]="defaultKeyAction"
|
||||
[currentLayer]="currentLayer"
|
||||
[allowLayerDoubleTap]="allowLayerDoubleTap"
|
||||
(validAction)="keyActionValid=$event"
|
||||
></layer-tab>
|
||||
<mouse-tab #tab *ngSwitchCase="tabName.Mouse" class="popover-content"
|
||||
@@ -75,8 +76,42 @@
|
||||
></none-tab>
|
||||
</div>
|
||||
<div class="popover-action">
|
||||
<button class="btn btn-sm btn-default" type="button" (click)="onCancelClick()"> Cancel </button>
|
||||
<button class="btn btn-sm btn-primary" [class.disabled]="!keyActionValid" type="button" (click)="onRemapKey()"> Remap Key </button>
|
||||
<form class="form-inline d-inline-block popover-action-form">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox"
|
||||
name="remapOnAllKeymap"
|
||||
[(ngModel)]="remapOnAllKeymap"> Remap on all keymaps
|
||||
</label>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox"
|
||||
name="remapOnAllLayer"
|
||||
[(ngModel)]="remapOnAllLayer"> Remap on all layers
|
||||
</label>
|
||||
</div>
|
||||
<div class="d-inline-block">
|
||||
<icon name="question-circle"
|
||||
data-toggle="tooltip"
|
||||
html="true"
|
||||
maxWidth="525"
|
||||
title="<ul class='no-indent text-left'>
|
||||
<li><strong>Default behavior</strong>: Remap the key on the the current layer of the current keymap.</li>
|
||||
<li><strong>Remap on all keymaps</strong>: Remap key on the current layer of all keymaps.</li>
|
||||
<li><strong>Remap on all layers</strong>: Remap key on all layers of the current keymap.</li>
|
||||
<li><strong>Remap on all keymaps + Remap on all layers</strong>: Remap key on all layers of all keymaps.</li>
|
||||
</ul>"
|
||||
data-placement="bottom"></icon>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="d-inline-block pull-right">
|
||||
<button class="btn btn-sm btn-default" type="button" (click)="onCancelClick()"> Cancel</button>
|
||||
<button class="btn btn-sm btn-primary" [class.disabled]="!keyActionValid" type="button"
|
||||
(click)="onRemapKey()"> Remap Key
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="popover-overlay" [class.display]="visible" (click)="onOverlay()"></div>
|
||||
|
||||
@@ -70,7 +70,6 @@
|
||||
background-color: #f7f7f7;
|
||||
border-top: 1px solid #ebebeb;
|
||||
border-radius: 0 0 5px 5px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.popover-title {
|
||||
@@ -133,3 +132,11 @@
|
||||
margin-top: -1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.popover-action-form {
|
||||
margin-top: 4px;
|
||||
|
||||
label {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,10 +27,11 @@ import {
|
||||
SwitchLayerAction
|
||||
} from 'uhk-common';
|
||||
|
||||
import { Tab } from './tab/tab';
|
||||
import { Tab } from './tab';
|
||||
|
||||
import { AppState } from '../../store';
|
||||
import { getKeymaps } from '../../store/reducers/user-configuration';
|
||||
import { KeyActionRemap } from '../../models/key-action-remap';
|
||||
|
||||
enum TabName {
|
||||
Keypress,
|
||||
@@ -59,8 +60,8 @@ enum TabName {
|
||||
})),
|
||||
transition('opened => closed', [
|
||||
animate('200ms ease-out', keyframes([
|
||||
style({ transform: 'translateY(0)', visibility: 'visible', opacity: 1, offset: 0 }),
|
||||
style({ transform: 'translateY(30px)', visibility: 'hidden', opacity: 0, offset: 1 })
|
||||
style({transform: 'translateY(0)', visibility: 'visible', opacity: 1, offset: 0}),
|
||||
style({transform: 'translateY(30px)', visibility: 'hidden', opacity: 0, offset: 1})
|
||||
]))
|
||||
]),
|
||||
transition('closed => opened', [
|
||||
@@ -68,8 +69,8 @@ enum TabName {
|
||||
visibility: 'visible'
|
||||
}),
|
||||
animate('200ms ease-out', keyframes([
|
||||
style({ transform: 'translateY(30px)', opacity: 0, offset: 0 }),
|
||||
style({ transform: 'translateY(0)', opacity: 1, offset: 1 })
|
||||
style({transform: 'translateY(30px)', opacity: 0, offset: 0}),
|
||||
style({transform: 'translateY(0)', opacity: 1, offset: 1})
|
||||
]))
|
||||
])
|
||||
])
|
||||
@@ -82,9 +83,10 @@ export class PopoverComponent implements OnChanges {
|
||||
@Input() keyPosition: any;
|
||||
@Input() wrapPosition: any;
|
||||
@Input() visible: boolean;
|
||||
@Input() allowLayerDoubleTap: boolean;
|
||||
|
||||
@Output() cancel = new EventEmitter<any>();
|
||||
@Output() remap = new EventEmitter<KeyAction>();
|
||||
@Output() remap = new EventEmitter<KeyActionRemap>();
|
||||
|
||||
@ViewChild('tab') selectedTab: Tab;
|
||||
@ViewChild('popover') popoverHost: ElementRef;
|
||||
@@ -99,6 +101,9 @@ export class PopoverComponent implements OnChanges {
|
||||
leftPosition: number = 0;
|
||||
animationState: string;
|
||||
|
||||
remapOnAllKeymap: boolean;
|
||||
remapOnAllLayer: boolean;
|
||||
|
||||
private readonly currentKeymap$ = new BehaviorSubject<Keymap>(undefined);
|
||||
|
||||
constructor(store: Store<AppState>) {
|
||||
@@ -138,6 +143,8 @@ export class PopoverComponent implements OnChanges {
|
||||
if (change['visible']) {
|
||||
if (change['visible'].currentValue) {
|
||||
this.animationState = 'opened';
|
||||
this.remapOnAllKeymap = false;
|
||||
this.remapOnAllLayer = false;
|
||||
} else {
|
||||
this.animationState = 'closed';
|
||||
}
|
||||
@@ -155,8 +162,11 @@ export class PopoverComponent implements OnChanges {
|
||||
onRemapKey(): void {
|
||||
if (this.keyActionValid) {
|
||||
try {
|
||||
const keyAction = this.selectedTab.toKeyAction();
|
||||
this.remap.emit(keyAction);
|
||||
this.remap.emit({
|
||||
remapOnAllKeymap: this.remapOnAllKeymap,
|
||||
remapOnAllLayer: this.remapOnAllLayer,
|
||||
action: this.selectedTab.toKeyAction()
|
||||
});
|
||||
} catch (e) {
|
||||
// TODO: show error dialog
|
||||
console.error(e);
|
||||
|
||||
@@ -9,7 +9,10 @@
|
||||
></select2>
|
||||
<icon name="question-circle"
|
||||
data-toggle="tooltip"
|
||||
title="Looking for a non-US character? Just pick the character of the desired key according to the US layout. For example, on US keyboards next to Tab there is the Q key, but it's й on Russian keyboards, so in this case choose Q instead of й in Agent."
|
||||
html="true"
|
||||
maxWidth="330"
|
||||
title="<p>Looking for a non-US character? Just pick the character of the desired key according to the US layout.</p>
|
||||
<p>Let's say you're a German user and want to map the Ö character. You can see that on US keyboards this is the semicolon key, so choose semicolon in this dropdown.</p>"
|
||||
data-placement="bottom"></icon>
|
||||
<capture-keystroke-button (capture)="onKeysCapture($event)" tabindex="0"></capture-keystroke-button>
|
||||
</div>
|
||||
@@ -46,7 +49,15 @@
|
||||
></select2>
|
||||
<icon name="question-circle"
|
||||
data-toggle="tooltip"
|
||||
title="The secondary role activates when another key gets pressed while holding this key."
|
||||
html="true"
|
||||
maxWidth="620"
|
||||
title="<p class='text-left'>The secondary role activates when another key gets pressed while holding this key.</p>
|
||||
<p class='text-left'>Let's say that the scancode is Escape and the secondary role is Mouse. Then:</p>
|
||||
<ul class='text-left'>
|
||||
<li>Tap this key to trigger Escape. <i>(Primary role)</i></li>
|
||||
<li>Hold this key and press another key to activate the relevant key of the Mouse layer. <i>(Secondary role)</i></li>
|
||||
</ul>
|
||||
<p class='text-left pt-3'>The secondary role can be any layer or modifier.</p>"
|
||||
data-placement="bottom"></icon>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,20 +1,32 @@
|
||||
<ng-template [ngIf]="!isNotBase">
|
||||
<select (change)="toggleChanged($event.target.value)">
|
||||
<option *ngFor="let item of toggleData" [value]="item.id" [selected]="toggle === item.id">
|
||||
{{ item.text }}
|
||||
</option>
|
||||
</select>
|
||||
<span>the</span>
|
||||
<select (change)="layerChanged($event.target.value)">
|
||||
<option *ngFor="let item of layerData" [value]="item.id" [selected]="layer === item.id">
|
||||
{{ item.text }}
|
||||
</option>
|
||||
</select>
|
||||
<span [ngSwitch]="toggle">
|
||||
<ng-template [ngSwitchCase]="true">layer by tapping this key.</ng-template>
|
||||
<ng-template ngSwitchDefault>layer by holding this key.</ng-template>
|
||||
</span>
|
||||
<div>
|
||||
<div>
|
||||
<select (change)="toggleChanged($event.target.value)">
|
||||
<option *ngFor="let item of toggleData" [value]="item.id" [selected]="toggle === item.id">
|
||||
{{ item.text }}
|
||||
</option>
|
||||
</select>
|
||||
<span>the</span>
|
||||
<select (change)="layerChanged($event.target.value)">
|
||||
<option *ngFor="let item of layerData" [value]="item.id" [selected]="layer === item.id">
|
||||
{{ item.text }}
|
||||
</option>
|
||||
</select>
|
||||
<span [ngSwitch]="toggle">
|
||||
<ng-template [ngSwitchCase]="'toggle'">layer by tapping this key.</ng-template>
|
||||
<ng-template ngSwitchDefault>layer by holding this key.</ng-template>
|
||||
</span>
|
||||
</div>
|
||||
<div *ngIf="toggle === 'active' && allowLayerDoubleTap">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox"
|
||||
[(ngModel)]="lockLayerWhenDoubleTapping"> Lock layer when double tapping this key.
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
<ng-template [ngIf]="isNotBase">
|
||||
<span> Layer switching is only possible from the base layer. </span>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { Component, HostBinding, Input, OnChanges, SimpleChanges } from '@angular/core';
|
||||
import { KeyAction, LayerName, SwitchLayerAction } from 'uhk-common';
|
||||
import { KeyAction, LayerName, SwitchLayerAction, SwitchLayerMode } from 'uhk-common';
|
||||
|
||||
import { Tab } from '../tab';
|
||||
|
||||
export type toggleType = 'active' | 'toggle';
|
||||
|
||||
@Component({
|
||||
selector: 'layer-tab',
|
||||
templateUrl: './layer-tab.component.html',
|
||||
@@ -11,16 +13,17 @@ import { Tab } from '../tab';
|
||||
export class LayerTabComponent extends Tab implements OnChanges {
|
||||
@Input() defaultKeyAction: KeyAction;
|
||||
@Input() currentLayer: number;
|
||||
@Input() allowLayerDoubleTap: boolean;
|
||||
|
||||
@HostBinding('class.no-base') isNotBase: boolean;
|
||||
|
||||
toggleData: { id: boolean, text: string }[] = [
|
||||
toggleData: { id: toggleType, text: string }[] = [
|
||||
{
|
||||
id: false,
|
||||
id: 'active',
|
||||
text: 'Activate'
|
||||
},
|
||||
{
|
||||
id: true,
|
||||
id: 'toggle',
|
||||
text: 'Toggle'
|
||||
}
|
||||
];
|
||||
@@ -40,12 +43,13 @@ export class LayerTabComponent extends Tab implements OnChanges {
|
||||
}
|
||||
];
|
||||
|
||||
toggle: boolean;
|
||||
toggle: toggleType;
|
||||
layer: LayerName;
|
||||
lockLayerWhenDoubleTapping: boolean;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.toggle = false;
|
||||
this.toggle = 'active';
|
||||
this.layer = LayerName.mod;
|
||||
}
|
||||
|
||||
@@ -71,14 +75,39 @@ export class LayerTabComponent extends Tab implements OnChanges {
|
||||
}
|
||||
|
||||
const switchLayerAction: SwitchLayerAction = <SwitchLayerAction>keyAction;
|
||||
this.toggle = switchLayerAction.isLayerToggleable;
|
||||
switch (switchLayerAction.switchLayerMode) {
|
||||
case SwitchLayerMode.holdAndDoubleTapToggle: {
|
||||
this.toggle = 'active';
|
||||
this.lockLayerWhenDoubleTapping = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SwitchLayerMode.hold: {
|
||||
this.toggle = 'active';
|
||||
this.lockLayerWhenDoubleTapping = false;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
this.toggle = 'toggle';
|
||||
this.lockLayerWhenDoubleTapping = false;
|
||||
}
|
||||
}
|
||||
|
||||
this.layer = switchLayerAction.layer;
|
||||
return true;
|
||||
}
|
||||
|
||||
toKeyAction(): SwitchLayerAction {
|
||||
const keyAction = new SwitchLayerAction();
|
||||
keyAction.isLayerToggleable = this.toggle;
|
||||
if (this.toggle === 'toggle') {
|
||||
keyAction.switchLayerMode = SwitchLayerMode.toggle;
|
||||
} else if (!this.allowLayerDoubleTap || this.lockLayerWhenDoubleTapping) {
|
||||
keyAction.switchLayerMode = SwitchLayerMode.holdAndDoubleTapToggle;
|
||||
} else {
|
||||
keyAction.switchLayerMode = SwitchLayerMode.hold;
|
||||
}
|
||||
|
||||
keyAction.layer = this.layer;
|
||||
if (!this.keyActionValid()) {
|
||||
throw new Error('KeyAction is invalid!');
|
||||
@@ -86,8 +115,8 @@ export class LayerTabComponent extends Tab implements OnChanges {
|
||||
return keyAction;
|
||||
}
|
||||
|
||||
toggleChanged(value: string) {
|
||||
this.toggle = value === 'true';
|
||||
toggleChanged(value: toggleType) {
|
||||
this.toggle = value;
|
||||
}
|
||||
|
||||
layerChanged(value: number) {
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" [attr.viewBox]="viewBox" height="100%" width="100%">
|
||||
<svg:g svg-module *ngFor="let module of modules; let i = index"
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
[attr.viewBox]="viewBox"
|
||||
height="100%"
|
||||
width="100%">
|
||||
<svg:g svg-module
|
||||
*ngFor="let module of modules; let i = index"
|
||||
[coverages]="module.coverages"
|
||||
[keyboardKeys]="module.keyboardKeys"
|
||||
[keybindAnimationEnabled]="keybindAnimationEnabled"
|
||||
@@ -11,8 +15,11 @@
|
||||
[selected]="selectedKey?.moduleId === i"
|
||||
(keyClick)="onKeyClick(i, $event.index, $event.keyTarget)"
|
||||
(keyHover)="onKeyHover($event.index, $event.event, $event.over, i)"
|
||||
(capture)="onCapture(i, $event.index, $event.captured)"
|
||||
/>
|
||||
(capture)="onCapture(i, $event.index, $event.captured)" />
|
||||
|
||||
<svg:path [ngClass]="{'separator-visible': !halvesSplit, 'separator-hide': halvesSplit}"
|
||||
[attr.d]="separator.d"
|
||||
[attr.style]="separatorStyle" />
|
||||
</svg>
|
||||
<editable-text *ngIf="showDescription"
|
||||
[ngModel]="description"
|
||||
|
||||
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.2 KiB |
@@ -8,3 +8,33 @@ editable-text {
|
||||
padding-right: 2em;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.separator-visible {
|
||||
animation: visible-fade-in 1.5s;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@keyframes visible-fade-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.separator-hide {
|
||||
animation: visible-fade-out 1.5s;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@keyframes visible-fade-out {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { Component, EventEmitter, Input, OnInit, Output, SimpleChanges, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { animate, state, trigger, style, transition } from '@angular/animations';
|
||||
import { DomSanitizer, SafeStyle } from '@angular/platform-browser';
|
||||
import { Module } from 'uhk-common';
|
||||
|
||||
import { SvgModule } from '../module';
|
||||
import { SvgModuleProviderService } from '../../../services/svg-module-provider.service';
|
||||
import { KeyboardLayout } from '../../../keyboard/keyboard-layout.enum';
|
||||
import { SvgSeparator } from '../separator';
|
||||
|
||||
@Component({
|
||||
selector: 'svg-keyboard',
|
||||
@@ -41,8 +43,11 @@ export class SvgKeyboardComponent implements OnInit {
|
||||
modules: SvgModule[];
|
||||
viewBox: string;
|
||||
moduleAnimationStates: string[];
|
||||
separator: SvgSeparator;
|
||||
separatorStyle: SafeStyle;
|
||||
|
||||
constructor(private svgModuleProvider: SvgModuleProviderService) {
|
||||
constructor(private svgModuleProvider: SvgModuleProviderService,
|
||||
private sanitizer: DomSanitizer) {
|
||||
this.modules = [];
|
||||
this.viewBox = '-520 582 1100 470';
|
||||
this.halvesSplit = false;
|
||||
@@ -98,5 +103,7 @@ export class SvgKeyboardComponent implements OnInit {
|
||||
|
||||
private setModules() {
|
||||
this.modules = this.svgModuleProvider.getSvgModules(this.keyboardLayout);
|
||||
this.separator = this.svgModuleProvider.getSvgSeparator();
|
||||
this.separatorStyle = this.sanitizer.bypassSecurityTrustStyle(this.separator.style);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,13 +17,14 @@ import {
|
||||
MouseAction,
|
||||
PlayMacroAction,
|
||||
SwitchKeymapAction,
|
||||
SwitchLayerAction
|
||||
SwitchLayerAction,
|
||||
SwitchLayerMode
|
||||
} from 'uhk-common';
|
||||
|
||||
import { CaptureService } from '../../../../services/capture.service';
|
||||
import { MapperService } from '../../../../services/mapper.service';
|
||||
|
||||
import { AppState } from '../../../../store/index';
|
||||
import { AppState } from '../../../../store';
|
||||
import { getMacros } from '../../../../store/reducers/user-configuration';
|
||||
|
||||
enum LabelTypes {
|
||||
@@ -288,12 +289,18 @@ export class SvgKeyboardKeyComponent implements OnInit, OnChanges, OnDestroy {
|
||||
break;
|
||||
}
|
||||
|
||||
if (keyAction.isLayerToggleable) {
|
||||
if (keyAction.switchLayerMode === SwitchLayerMode.toggle) {
|
||||
this.labelType = LabelTypes.TextIcon;
|
||||
this.labelSource = {
|
||||
text: newLabelSource,
|
||||
icon: this.mapper.getIcon('toggle')
|
||||
};
|
||||
} else if (keyAction.switchLayerMode === SwitchLayerMode.holdAndDoubleTapToggle) {
|
||||
this.labelType = LabelTypes.TextIcon;
|
||||
this.labelSource = {
|
||||
text: newLabelSource,
|
||||
icon: this.mapper.getIcon('double-tap')
|
||||
};
|
||||
} else {
|
||||
this.labelType = LabelTypes.OneLineText;
|
||||
this.labelSource = newLabelSource;
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import { SvgSeparator } from './svg-separator.model';
|
||||
|
||||
export const convertXmlToSvgSeparator = (obj: { path: any[], $: Object }): SvgSeparator => {
|
||||
return obj.path[0].$;
|
||||
};
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './svg-separator.model';
|
||||
export * from './convert-xml-to-svg-separator';
|
||||
@@ -0,0 +1,4 @@
|
||||
export interface SvgSeparator {
|
||||
style: string;
|
||||
d: string;
|
||||
}
|
||||
@@ -13,8 +13,18 @@
|
||||
(capture)="onCapture($event.moduleId, $event.keyId, $event.captured)"
|
||||
(descriptionChanged)="onDescriptionChanged($event)"
|
||||
></keyboard-slider>
|
||||
<popover tabindex="0" [visible]="popoverShown" [keyPosition]="keyPosition" [wrapPosition]="wrapPosition" [defaultKeyAction]="popoverInitKeyAction"
|
||||
[currentKeymap]="keymap" [currentLayer]="currentLayer" (cancel)="hidePopover()" (remap)="onRemap($event)"></popover>
|
||||
|
||||
<popover tabindex="0"
|
||||
[visible]="popoverShown"
|
||||
[keyPosition]="keyPosition"
|
||||
[wrapPosition]="wrapPosition"
|
||||
[defaultKeyAction]="popoverInitKeyAction"
|
||||
[currentKeymap]="keymap"
|
||||
[currentLayer]="currentLayer"
|
||||
[allowLayerDoubleTap]="allowLayerDoubleTap"
|
||||
(cancel)="hidePopover()"
|
||||
(remap)="onRemap($event)"></popover>
|
||||
|
||||
<div class="tooltip bottom"
|
||||
[class.in]="tooltipData.show"
|
||||
[style.top.px]="tooltipData.posTop"
|
||||
|
||||
@@ -32,7 +32,8 @@ import {
|
||||
PlayMacroAction,
|
||||
SecondaryRoleAction,
|
||||
SwitchKeymapAction,
|
||||
SwitchLayerAction
|
||||
SwitchLayerAction,
|
||||
SwitchLayerMode
|
||||
} from 'uhk-common';
|
||||
|
||||
import { MapperService } from '../../../services/mapper.service';
|
||||
@@ -41,6 +42,7 @@ import { KeymapActions } from '../../../store/actions';
|
||||
import { PopoverComponent } from '../../popover';
|
||||
import { KeyboardLayout } from '../../../keyboard/keyboard-layout.enum';
|
||||
import { ChangeKeymapDescription } from '../../../models/ChangeKeymapDescription';
|
||||
import { KeyActionRemap } from '../../../models/key-action-remap';
|
||||
|
||||
interface NameValuePair {
|
||||
name: string;
|
||||
@@ -59,6 +61,8 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges {
|
||||
@Input() tooltipEnabled: boolean = false;
|
||||
@Input() halvesSplit: boolean;
|
||||
@Input() keyboardLayout: KeyboardLayout.ANSI;
|
||||
@Input() allowLayerDoubleTap: boolean;
|
||||
|
||||
@Output() descriptionChanged = new EventEmitter<ChangeKeymapDescription>();
|
||||
|
||||
@ViewChild(PopoverComponent, { read: ElementRef }) popover: ElementRef;
|
||||
@@ -178,11 +182,15 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges {
|
||||
this.currentLayer,
|
||||
moduleId,
|
||||
keyId,
|
||||
keystrokeAction)
|
||||
{
|
||||
remapOnAllKeymap: false,
|
||||
remapOnAllLayer: false,
|
||||
action: keystrokeAction
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
onRemap(keyAction: KeyAction): void {
|
||||
onRemap(keyAction: KeyActionRemap): void {
|
||||
this.store.dispatch(
|
||||
KeymapActions.saveKey(
|
||||
this.keymap,
|
||||
@@ -350,7 +358,7 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges {
|
||||
},
|
||||
{
|
||||
name: 'Toogle',
|
||||
value: switchLayerAction.isLayerToggleable ? 'On' : 'Off'
|
||||
value: switchLayerAction.switchLayerMode === SwitchLayerMode.toggle ? 'On' : 'Off'
|
||||
}
|
||||
];
|
||||
return Observable.of(content);
|
||||
|
||||
@@ -9,15 +9,10 @@ export class TooltipDirective implements AfterContentInit, OnChanges {
|
||||
@HostBinding('attr.data-placement') placement: string;
|
||||
@Input('title') title: string;
|
||||
@Input('html') html: boolean;
|
||||
@Input() maxWidth: number;
|
||||
|
||||
private customTooltipTemplate = `
|
||||
<div class="tooltip">
|
||||
<div class="tooltip-arrow"></div>
|
||||
<div class="tooltip-inner"></div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
constructor(private elementRef: ElementRef, private sanitizer: DomSanitizer) { }
|
||||
constructor(private elementRef: ElementRef, private sanitizer: DomSanitizer) {
|
||||
}
|
||||
|
||||
ngAfterContentInit() {
|
||||
this.init();
|
||||
@@ -33,7 +28,7 @@ export class TooltipDirective implements AfterContentInit, OnChanges {
|
||||
(<any>jQuery(this.elementRef.nativeElement)).tooltip({
|
||||
placement: this.placement,
|
||||
html: this.html,
|
||||
template: this.customTooltipTemplate,
|
||||
template: this.getCustomTemplate(),
|
||||
title: this.title
|
||||
});
|
||||
}
|
||||
@@ -42,7 +37,7 @@ export class TooltipDirective implements AfterContentInit, OnChanges {
|
||||
(<any>jQuery(this.elementRef.nativeElement)).tooltip({
|
||||
placement: this.placement,
|
||||
html: this.html,
|
||||
template: this.customTooltipTemplate,
|
||||
template: this.getCustomTemplate(),
|
||||
title: this.title
|
||||
});
|
||||
|
||||
@@ -50,4 +45,19 @@ export class TooltipDirective implements AfterContentInit, OnChanges {
|
||||
.attr('title', this.title))
|
||||
.tooltip('fixTitle');
|
||||
}
|
||||
|
||||
private getCustomTemplate(): string {
|
||||
let tooltipStyle = '';
|
||||
let innerStyle = '';
|
||||
|
||||
if (this.maxWidth) {
|
||||
tooltipStyle = `style="width: ${this.maxWidth}px;"`;
|
||||
innerStyle = `style="max-width: ${this.maxWidth}px;"`;
|
||||
}
|
||||
|
||||
return `<div class="tooltip" ${tooltipStyle}>
|
||||
<div class="tooltip-arrow"></div>
|
||||
<div class="tooltip-inner" ${innerStyle}></div>
|
||||
</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
7
packages/uhk-web/src/app/models/key-action-remap.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { KeyAction } from 'uhk-common';
|
||||
|
||||
export interface KeyActionRemap {
|
||||
remapOnAllKeymap: boolean;
|
||||
remapOnAllLayer: boolean;
|
||||
action: KeyAction;
|
||||
}
|
||||
@@ -262,6 +262,7 @@ export class MapperService {
|
||||
private initNameToFileNames(): void {
|
||||
this.nameToFileName = new Map<string, string>();
|
||||
this.nameToFileName.set('toggle', 'icon-kbd__fn--toggle');
|
||||
this.nameToFileName.set('double-tap', 'icon-kbd__fn--double-tap');
|
||||
this.nameToFileName.set('switch-keymap', 'icon-kbd__mod--switch-keymap');
|
||||
this.nameToFileName.set('macro', 'icon-icon__macro');
|
||||
this.nameToFileName.set('shift', 'icon-kbd__default--modifier-shift');
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Injectable } from '@angular/core';
|
||||
|
||||
import { SvgModule } from '../components/svg/module';
|
||||
import { KeyboardLayout } from '../keyboard/keyboard-layout.enum';
|
||||
import { convertXmlToSvgSeparator, SvgSeparator } from '../components/svg/separator';
|
||||
|
||||
@Injectable()
|
||||
export class SvgModuleProviderService {
|
||||
@@ -9,11 +10,20 @@ export class SvgModuleProviderService {
|
||||
private ansiLeft: SvgModule;
|
||||
private isoLeft: SvgModule;
|
||||
private right: SvgModule;
|
||||
private separator: SvgSeparator;
|
||||
|
||||
getSvgModules(layout = KeyboardLayout.ANSI): SvgModule[] {
|
||||
return [this.getRightModule(), this.getLeftModule(layout)];
|
||||
}
|
||||
|
||||
getSvgSeparator(): SvgSeparator {
|
||||
if (!this.separator) {
|
||||
this.separator = convertXmlToSvgSeparator(require('xml-loader!../../devices/uhk60-right/separator.xml').svg);
|
||||
}
|
||||
|
||||
return this.separator;
|
||||
}
|
||||
|
||||
private getLeftModule(layout = KeyboardLayout.ANSI): SvgModule {
|
||||
if (layout === KeyboardLayout.ISO) {
|
||||
if (!this.isoLeft) {
|
||||
|
||||
@@ -179,12 +179,12 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mod",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "fn",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "keystroke",
|
||||
@@ -275,7 +275,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mouse",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "keystroke",
|
||||
@@ -356,7 +356,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "fn",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "keystroke",
|
||||
@@ -366,7 +366,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mod",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null
|
||||
]
|
||||
@@ -507,7 +507,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mod",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null,
|
||||
{
|
||||
@@ -654,7 +654,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mod",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null
|
||||
]
|
||||
@@ -732,7 +732,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "fn",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "keystroke",
|
||||
@@ -819,7 +819,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "fn",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null,
|
||||
null,
|
||||
@@ -941,7 +941,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mouse",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null,
|
||||
{
|
||||
@@ -1156,12 +1156,12 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mod",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "fn",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "keystroke",
|
||||
@@ -1252,7 +1252,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mouse",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "keystroke",
|
||||
@@ -1333,7 +1333,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "fn",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "keystroke",
|
||||
@@ -1343,7 +1343,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mod",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null
|
||||
]
|
||||
@@ -1484,7 +1484,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mod",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null,
|
||||
{
|
||||
@@ -1641,7 +1641,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mod",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null
|
||||
]
|
||||
@@ -1719,7 +1719,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "fn",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "keystroke",
|
||||
@@ -1806,7 +1806,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "fn",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null,
|
||||
null,
|
||||
@@ -1928,7 +1928,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mouse",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null,
|
||||
{
|
||||
@@ -2143,12 +2143,12 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mod",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "fn",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "keystroke",
|
||||
@@ -2239,7 +2239,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mouse",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "keystroke",
|
||||
@@ -2320,7 +2320,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "fn",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "keystroke",
|
||||
@@ -2330,7 +2330,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mod",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null
|
||||
]
|
||||
@@ -2471,7 +2471,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mod",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null,
|
||||
{
|
||||
@@ -2618,7 +2618,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mod",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null
|
||||
]
|
||||
@@ -2696,7 +2696,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "fn",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "keystroke",
|
||||
@@ -2783,7 +2783,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "fn",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null,
|
||||
null,
|
||||
@@ -2902,7 +2902,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mouse",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null,
|
||||
{
|
||||
@@ -3117,12 +3117,12 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mod",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "fn",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "keystroke",
|
||||
@@ -3213,7 +3213,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mouse",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "keystroke",
|
||||
@@ -3294,7 +3294,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "fn",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "keystroke",
|
||||
@@ -3304,7 +3304,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mod",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null
|
||||
]
|
||||
@@ -3445,7 +3445,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mod",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null,
|
||||
{
|
||||
@@ -3602,7 +3602,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mod",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null
|
||||
]
|
||||
@@ -3680,7 +3680,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "fn",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "keystroke",
|
||||
@@ -3767,7 +3767,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "fn",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null,
|
||||
null,
|
||||
@@ -3886,7 +3886,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mouse",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null,
|
||||
{
|
||||
@@ -4101,12 +4101,12 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mod",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "fn",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "keystroke",
|
||||
@@ -4197,7 +4197,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mouse",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "keystroke",
|
||||
@@ -4278,7 +4278,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "fn",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "keystroke",
|
||||
@@ -4288,7 +4288,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mod",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null
|
||||
]
|
||||
@@ -4429,7 +4429,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mod",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null,
|
||||
{
|
||||
@@ -4576,7 +4576,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mod",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null
|
||||
]
|
||||
@@ -4654,7 +4654,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "fn",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "keystroke",
|
||||
@@ -4741,7 +4741,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "fn",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null,
|
||||
null,
|
||||
@@ -4854,7 +4854,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mouse",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null,
|
||||
{
|
||||
@@ -5069,12 +5069,12 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mod",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "fn",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "keystroke",
|
||||
@@ -5165,7 +5165,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mouse",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "keystroke",
|
||||
@@ -5246,7 +5246,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "fn",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "keystroke",
|
||||
@@ -5256,7 +5256,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mod",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null
|
||||
]
|
||||
@@ -5397,7 +5397,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mod",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null,
|
||||
{
|
||||
@@ -5554,7 +5554,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mod",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null
|
||||
]
|
||||
@@ -5635,7 +5635,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "fn",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
{
|
||||
"keyActionType": "keystroke",
|
||||
@@ -5722,7 +5722,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "fn",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null,
|
||||
null,
|
||||
@@ -5835,7 +5835,7 @@
|
||||
{
|
||||
"keyActionType": "switchLayer",
|
||||
"layer": "mouse",
|
||||
"toggle": false
|
||||
"switchLayerMode": "holdAndDoubleTapToggle"
|
||||
},
|
||||
null,
|
||||
{
|
||||
@@ -6900,4 +6900,4 @@
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { Action } from '@ngrx/store';
|
||||
import { KeyAction, Keymap, Macro } from 'uhk-common';
|
||||
import { Keymap, Macro } from 'uhk-common';
|
||||
import { UndoUserConfigData } from '../../models/undo-user-config-data';
|
||||
import { ChangeKeymapDescription } from '../../models/ChangeKeymapDescription';
|
||||
import { KeyActionRemap } from '../../models/key-action-remap';
|
||||
|
||||
export type KeymapAction =
|
||||
KeymapActions.AddKeymapAction |
|
||||
@@ -60,7 +61,7 @@ export namespace KeymapActions {
|
||||
layer: number;
|
||||
module: number;
|
||||
key: number;
|
||||
keyAction: KeyAction;
|
||||
keyAction: KeyActionRemap;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -172,7 +173,11 @@ export namespace KeymapActions {
|
||||
};
|
||||
}
|
||||
|
||||
export function saveKey(keymap: Keymap, layer: number, module: number, key: number, keyAction: KeyAction): SaveKeyAction {
|
||||
export function saveKey(keymap: Keymap,
|
||||
layer: number,
|
||||
module: number,
|
||||
key: number,
|
||||
keyAction: KeyActionRemap): SaveKeyAction {
|
||||
return {
|
||||
type: KeymapActions.SAVE_KEY,
|
||||
payload: {
|
||||
|
||||
@@ -44,6 +44,7 @@ export const getUserConfiguration = (state: AppState) => state.userConfiguration
|
||||
export const appState = (state: AppState) => state.app;
|
||||
|
||||
export const showAddonMenu = createSelector(appState, fromApp.showAddonMenu);
|
||||
export const allowLayerDoubleTap = createSelector(appState, fromApp.allowLayerDoubleTap);
|
||||
export const getUndoableNotification = createSelector(appState, fromApp.getUndoableNotification);
|
||||
export const getPrevUserConfiguration = createSelector(appState, fromApp.getPrevUserConfiguration);
|
||||
export const runningInElectron = createSelector(appState, fromApp.runningInElectron);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ROUTER_NAVIGATION } from '@ngrx/router-store';
|
||||
import { Action } from '@ngrx/store';
|
||||
import {
|
||||
CommandLineArgs,
|
||||
HardwareConfiguration,
|
||||
Notification,
|
||||
NotificationType,
|
||||
@@ -18,7 +19,7 @@ import { PrivilagePageSate } from '../../models/privilage-page-sate';
|
||||
|
||||
export interface State {
|
||||
started: boolean;
|
||||
showAddonMenu: boolean;
|
||||
commandLineArgs: CommandLineArgs;
|
||||
undoableNotification?: Notification;
|
||||
navigationCountAfterNotification: number;
|
||||
prevUserConfig?: UserConfiguration;
|
||||
@@ -32,7 +33,7 @@ export interface State {
|
||||
|
||||
export const initialState: State = {
|
||||
started: false,
|
||||
showAddonMenu: false,
|
||||
commandLineArgs: {},
|
||||
navigationCountAfterNotification: 0,
|
||||
runningInElectron: runInElectron(),
|
||||
configLoading: true,
|
||||
@@ -52,7 +53,7 @@ export function reducer(state = initialState, action: Action & { payload: any })
|
||||
case ActionTypes.APPLY_COMMAND_LINE_ARGS: {
|
||||
return {
|
||||
...state,
|
||||
showAddonMenu: action.payload.addons
|
||||
commandLineArgs: action.payload
|
||||
};
|
||||
}
|
||||
|
||||
@@ -148,7 +149,8 @@ export function reducer(state = initialState, action: Action & { payload: any })
|
||||
}
|
||||
}
|
||||
|
||||
export const showAddonMenu = (state: State) => state.showAddonMenu;
|
||||
export const showAddonMenu = (state: State) => state.commandLineArgs.addons;
|
||||
export const allowLayerDoubleTap = (state: State) => state.commandLineArgs.layerDoubleTap;
|
||||
export const getUndoableNotification = (state: State) => state.undoableNotification;
|
||||
export const getPrevUserConfiguration = (state: State) => state.prevUserConfig;
|
||||
export const runningInElectron = (state: State) => state.runningInElectron;
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
import { reducer, initialState } from './user-configuration';
|
||||
import { KeystrokeAction, KeystrokeType, SwitchLayerAction, UserConfiguration, LayerName, Keymap } from 'uhk-common';
|
||||
import {
|
||||
KeystrokeAction,
|
||||
KeystrokeType,
|
||||
SwitchLayerAction,
|
||||
UserConfiguration,
|
||||
LayerName,
|
||||
Keymap,
|
||||
SwitchLayerMode
|
||||
} from 'uhk-common';
|
||||
|
||||
import { getDefaultUserConfig } from '../../../../test/user-config-helper';
|
||||
import { KeymapActions } from '../actions';
|
||||
@@ -22,7 +30,11 @@ describe('user-configuration reducer', () => {
|
||||
layer: 0,
|
||||
module: 0,
|
||||
key: 0,
|
||||
keyAction: keystrokeAction
|
||||
keyAction: {
|
||||
remapOnAllKeymap: false,
|
||||
remapOnAllLayer: false,
|
||||
action: keystrokeAction
|
||||
}
|
||||
}
|
||||
};
|
||||
const result = reducer(state, saveKeyAction);
|
||||
@@ -42,7 +54,11 @@ describe('user-configuration reducer', () => {
|
||||
const defaultUserConfig = new UserConfiguration().fromJsonObject(getDefaultUserConfig());
|
||||
const state = new UserConfiguration().fromJsonObject(getDefaultUserConfig());
|
||||
const destinationLayerId = LayerName.mod;
|
||||
const switchLayerAction = new SwitchLayerAction({isLayerToggleable: false, layer: destinationLayerId} as any);
|
||||
const switchLayerAction = new SwitchLayerAction({
|
||||
switchLayerMode: SwitchLayerMode.toggle,
|
||||
layer: destinationLayerId
|
||||
} as any);
|
||||
|
||||
const saveKeyAction: KeymapActions.SaveKeyAction = {
|
||||
type: KeymapActions.SAVE_KEY,
|
||||
payload: {
|
||||
@@ -50,7 +66,12 @@ describe('user-configuration reducer', () => {
|
||||
layer: 0,
|
||||
module: 0,
|
||||
key: 0,
|
||||
keyAction: switchLayerAction
|
||||
keyAction: {
|
||||
remapOnAllKeymap: false,
|
||||
remapOnAllLayer: false,
|
||||
action: switchLayerAction
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
const result = reducer(state, saveKeyAction);
|
||||
@@ -81,7 +102,7 @@ describe('user-configuration reducer', () => {
|
||||
{
|
||||
keyActionType: 'switchLayer',
|
||||
layer: 'mod',
|
||||
toggle: false
|
||||
switchLayerMode: 1
|
||||
},
|
||||
{
|
||||
keyActionType: 'keystroke',
|
||||
@@ -89,9 +110,9 @@ describe('user-configuration reducer', () => {
|
||||
scancode: 37
|
||||
},
|
||||
{
|
||||
'keyActionType': 'switchLayer',
|
||||
'layer': 'mod',
|
||||
'toggle': false
|
||||
keyActionType: 'switchLayer',
|
||||
layer: 'mod',
|
||||
switchLayerMode: 1
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -128,7 +149,7 @@ describe('user-configuration reducer', () => {
|
||||
{
|
||||
keyActionType: 'switchLayer',
|
||||
layer: 'mod',
|
||||
toggle: false
|
||||
switchLayerMode: 1
|
||||
},
|
||||
{
|
||||
keyActionType: 'keystroke',
|
||||
@@ -136,9 +157,9 @@ describe('user-configuration reducer', () => {
|
||||
scancode: 65
|
||||
},
|
||||
{
|
||||
'keyActionType': 'switchLayer',
|
||||
'layer': 'mod',
|
||||
'toggle': false
|
||||
keyActionType: 'switchLayer',
|
||||
layer: 'mod',
|
||||
switchLayerMode: 1
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -219,7 +240,11 @@ describe('user-configuration reducer', () => {
|
||||
const defaultUserConfig = new UserConfiguration().fromJsonObject(getDefaultUserConfig());
|
||||
const state = new UserConfiguration().fromJsonObject(getDefaultUserConfig());
|
||||
const destinationLayerId = LayerName.fn;
|
||||
const switchLayerAction = new SwitchLayerAction({isLayerToggleable: false, layer: destinationLayerId} as any);
|
||||
const switchLayerAction = new SwitchLayerAction({
|
||||
switchLayerMode: SwitchLayerMode.toggle,
|
||||
layer: destinationLayerId
|
||||
} as any);
|
||||
|
||||
const saveKeyAction: KeymapActions.SaveKeyAction = {
|
||||
type: KeymapActions.SAVE_KEY,
|
||||
payload: {
|
||||
@@ -227,7 +252,12 @@ describe('user-configuration reducer', () => {
|
||||
layer: 0,
|
||||
module: 0,
|
||||
key: 2,
|
||||
keyAction: switchLayerAction
|
||||
keyAction: {
|
||||
remapOnAllKeymap: false,
|
||||
remapOnAllLayer: false,
|
||||
action: switchLayerAction
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
const result = reducer(state, saveKeyAction);
|
||||
@@ -266,9 +296,9 @@ describe('user-configuration reducer', () => {
|
||||
scancode: 37
|
||||
},
|
||||
{
|
||||
'keyActionType': 'switchLayer',
|
||||
'layer': 'fn',
|
||||
'toggle': false
|
||||
keyActionType: 'switchLayer',
|
||||
layer: 'fn',
|
||||
switchLayerMode: 1
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -345,7 +375,7 @@ describe('user-configuration reducer', () => {
|
||||
{
|
||||
keyActionType: 'switchLayer',
|
||||
layer: 'fn',
|
||||
toggle: false
|
||||
switchLayerMode: 1
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -68,7 +68,7 @@ export function reducer(state = initialState, action: Action & { payload?: any }
|
||||
break;
|
||||
}
|
||||
|
||||
const newKeymap = Object.assign(new Keymap(), keymapToRename, { name });
|
||||
const newKeymap = Object.assign(new Keymap(), keymapToRename, {name});
|
||||
|
||||
changedUserConfiguration.keymaps = insertItemInNameOrder(
|
||||
state.keymaps,
|
||||
@@ -139,38 +139,46 @@ export function reducer(state = initialState, action: Action & { payload?: any }
|
||||
const keyIndex: number = action.payload.key;
|
||||
const layerIndex: number = action.payload.layer;
|
||||
const moduleIndex: number = action.payload.module;
|
||||
const newKeyAction = KeyActionHelper.createKeyAction(action.payload.keyAction);
|
||||
const newKeymap: Keymap = Object.assign(new Keymap(), action.payload.keymap);
|
||||
newKeymap.layers = newKeymap.layers.slice();
|
||||
|
||||
newKeymap.layers = newKeymap.layers.map((layer, index) => {
|
||||
const newLayer = Object.assign(new Layer(), layer);
|
||||
|
||||
if (index === layerIndex) {
|
||||
setKeyActionToLayer(newLayer, moduleIndex, keyIndex, newKeyAction);
|
||||
}
|
||||
// If the key action is a SwitchLayerAction then set the same SwitchLayerAction
|
||||
// on the target layer
|
||||
else if (newKeyAction instanceof SwitchLayerAction) {
|
||||
if (index - 1 === newKeyAction.layer) {
|
||||
const clonedAction = KeyActionHelper.createKeyAction(action.payload.keyAction);
|
||||
setKeyActionToLayer(newLayer, moduleIndex, keyIndex, clonedAction);
|
||||
} else {
|
||||
setKeyActionToLayer(newLayer, moduleIndex, keyIndex, null);
|
||||
}
|
||||
}
|
||||
return newLayer;
|
||||
});
|
||||
const keyActionRemap = action.payload.keyAction;
|
||||
const newKeyAction = keyActionRemap.action;
|
||||
const newKeymap: Keymap = action.payload.keymap;
|
||||
const isSwitchLayerAction = newKeyAction instanceof SwitchLayerAction;
|
||||
|
||||
changedUserConfiguration.keymaps = state.keymaps.map(keymap => {
|
||||
if (keymap.abbreviation === newKeymap.abbreviation) {
|
||||
keymap = newKeymap;
|
||||
if (keyActionRemap.remapOnAllKeymap || keymap.abbreviation === newKeymap.abbreviation) {
|
||||
keymap = new Keymap(keymap);
|
||||
|
||||
keymap.layers = keymap.layers.map((layer, index) => {
|
||||
if (keyActionRemap.remapOnAllLayer || index === layerIndex || isSwitchLayerAction) {
|
||||
layer = new Layer(layer);
|
||||
const clonedAction = KeyActionHelper.createKeyAction(newKeyAction);
|
||||
|
||||
// If the key action is a SwitchLayerAction then set the same SwitchLayerAction
|
||||
// on the target layer and remove SwitchLayerAction from other layers
|
||||
if (isSwitchLayerAction) {
|
||||
if (index === 0 || index - 1 === (newKeyAction as SwitchLayerAction).layer) {
|
||||
setKeyActionToLayer(layer, moduleIndex, keyIndex, clonedAction);
|
||||
} else {
|
||||
const actionOnLayer = layer.modules[moduleIndex].keyActions[keyIndex];
|
||||
if (actionOnLayer && actionOnLayer instanceof SwitchLayerAction) {
|
||||
setKeyActionToLayer(layer, moduleIndex, keyIndex, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
setKeyActionToLayer(layer, moduleIndex, keyIndex, clonedAction);
|
||||
}
|
||||
}
|
||||
|
||||
return layer;
|
||||
});
|
||||
}
|
||||
|
||||
return keymap;
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case KeymapActions.CHECK_MACRO:
|
||||
changedUserConfiguration.keymaps = state.keymaps.map(keymap => {
|
||||
keymap = Object.assign(new Keymap(), keymap);
|
||||
|
||||
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 88 KiB |
@@ -3,5 +3,5 @@
|
||||
<path
|
||||
id="separator"
|
||||
style="fill:none;stroke:#f00;stroke-width:3.6496063;stroke-linecap:round"
|
||||
d="M 16.455118,651.55037 16.455118,737.88305 C 16.455118,737.88305 16.419979,743.14568 11.278346,743.14568 L -10.998425,743.14568 C -10.998425,743.14568 -16.174,743.39316 -16.174,748.40667 L -16.174,804.39801 C -16.174,807.0217 -14.110808,809.66218 -10.998425,809.66218 L -4.719685,809.66218 C -4.719685,809.66218 0.315,809.66109 0.315,814.92517 L 0.315,870.91651 C 0.315,870.91651 0.31884203,876.17868 5.3503937,876.17868 L 28.187008,876.17868 C 28.187008,876.17868 33.311,876.17121 33.311,881.44014 L 33.311,937.43147 C 33.311,937.43147 33.306776,942.69568 28.187008,942.69568 L 4.719685,942.69568 C 4.719685,942.69568 -0.01,942.67983 -0.01,947.95864 L -0.01,1050.5905">
|
||||
d="M 16.455118,651.55037 16.455118,737.88305 C 16.455118,737.88305 16.419979,743.14568 11.278346,743.14568 L -10.998425,743.14568 C -10.998425,743.14568 -16.174,743.39316 -16.174,748.40667 L -16.174,804.39801 C -16.174,807.0217 -14.110808,809.66218 -10.998425,809.66218 L -4.719685,809.66218 C -4.719685,809.66218 0.315,809.66109 0.315,814.92517 L 0.315,870.91651 C 0.315,870.91651 0.31884203,876.17868 5.3503937,876.17868 L 28.187008,876.17868 C 28.187008,876.17868 33.311,876.17121 33.311,881.44014 L 33.311,937.43147 C 33.311,937.43147 33.306776,942.69568 28.187008,942.69568 L 4.719685,942.69568 C 4.719685,942.69568 -0.01,942.67983 -0.01,947.95864 L -0.01,1050.5905" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 926 B After Width: | Height: | Size: 928 B |
@@ -73,6 +73,11 @@ ul.btn-list {
|
||||
}
|
||||
}
|
||||
|
||||
ul.no-indent {
|
||||
padding-left: 1em;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.h1, .h2, .h3, h1, h2, h3 {
|
||||
margin-top: 10px;
|
||||
}
|
||||
@@ -178,3 +183,7 @@ pre {
|
||||
.ok-button {
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.d-inline-block {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="31" height="16" viewBox="0 0 31 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><svg width="16" height="16" viewBox="0 0 16 16" id="icon-0401-usb-stick" xmlns="http://www.w3.org/2000/svg"><path d="M6.5 2a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 1 0v-1a.5.5 0 0 0-.5-.5zM8.5 2a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 1 0v-1a.5.5 0 0 0-.5-.5z"/><path d="M11.5 5H11V.5a.5.5 0 0 0-.5-.5h-6a.5.5 0 0 0-.5.5V5h-.5a.5.5 0 0 0-.5.5v9.375c1 1.5 8 1.5 9 0V5.5a.5.5 0 0 0-.5-.5zM5 13.5a.5.5 0 0 1-1 0v-6a.5.5 0 0 1 1 0v6zM10 5H5V1h5v4z"/></svg><svg width="15" height="15" viewBox="0 0 15 15" id="icon-agent-icon" x="16" xmlns="http://www.w3.org/2000/svg"><path fill="#333" d="M3 0C1.338 0 0 1.338 0 3v9c0 1.662 1.338 3 3 3h9c1.662 0 3-1.338 3-3V3c0-1.662-1.338-3-3-3H3zM1.375 3.75a.36.36 0 0 1 .125 0H6c.375 0 .75.375.75.375s.375.375.75.375.75-.375.75-.375.375-.375.75-.375h4.5c.75 0 .75.75.75.75V6c0 2.25-1.5 2.25-1.5 2.25H9c-.375 0-.75-1.125-.75-1.125S7.875 6 7.5 6s-.75 1.125-.75 1.125S6.375 8.25 6 8.25H2.25S.75 8.25.75 6V4.5c0-.562.414-.715.625-.75z"/></svg></svg>
|
||||
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="31" height="16" viewBox="0 0 31 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><svg width="16" height="16" viewBox="0 0 16 16" id="icon-0401-usb-stick" xmlns="http://www.w3.org/2000/svg"><path d="M6.5 2a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 1 0v-1a.5.5 0 0 0-.5-.5zM8.5 2a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 1 0v-1a.5.5 0 0 0-.5-.5z"/><path d="M11.5 5H11V.5a.5.5 0 0 0-.5-.5h-6a.5.5 0 0 0-.5.5V5h-.5a.5.5 0 0 0-.5.5v9.375c1 1.5 8 1.5 9 0V5.5a.5.5 0 0 0-.5-.5zM5 13.5a.5.5 0 0 1-1 0v-6a.5.5 0 0 1 1 0v6zM10 5H5V1h5v4z"/></svg><svg width="15" height="15" viewBox="0 0 15 15" id="icon-agent-icon" x="16" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(12 0 0 -12 0 6)" id="abb"><stop offset="0" stop-color="#85878d"/><stop offset=".001" stop-color="#85878d"/><stop offset=".001" stop-color="#5d5f63"/><stop offset=".526" stop-color="#ccc"/><stop offset="1" stop-color="#5d5c62"/></linearGradient><linearGradient id="aba" gradientTransform="matrix(12 0 0 -12 0 6)" gradientUnits="userSpaceOnUse" x2="1"><stop offset="0" stop-color="#85878d"/><stop offset=".001" stop-color="#85878d"/><stop offset=".001" stop-color="#85878d"/><stop offset=".495" stop-color="#ccc"/><stop offset="1" stop-color="#5d5c62"/></linearGradient><clipPath id="abc"><path d="M2.398 12A2.393 2.393 0 0 1 0 9.602V2.398A2.393 2.393 0 0 1 2.398 0h7.203A2.394 2.394 0 0 1 12 2.398v7.204A2.394 2.394 0 0 1 9.601 12H2.398zM.602 7.199v1.199c0 .454.329.575.5.602.054.008.097 0 .097 0h3.602c.301 0 .597-.301.597-.301s.301-.301.602-.301.602.301.602.301.296.301.597.301h3.602c.597 0 .597-.602.597-.602V7.199c0-1.801-1.199-1.801-1.199-1.801h-3c-.301 0-.597.903-.597.903s-.301.898-.602.898-.602-.898-.602-.898-.296-.903-.597-.903h-3s-1.199 0-1.199 1.801"/></clipPath><linearGradient gradientUnits="userSpaceOnUse" x2="11.746" y1="11.542" x1=".915" id="abd" xlink:href="#aba"/><linearGradient y2="-.051" x2="12" y1="11.898" x1=".102" gradientUnits="userSpaceOnUse" id="abe" xlink:href="#abb"/></defs><g transform="matrix(1.25 0 0 -1.25 0 15)"><path d="M11.473 5.117H.416v4.266h11.057V5.117z" fill="#343434"/><g clip-path="url(#abc)" fill="url(#abd)"><path d="M2.398 12A2.393 2.393 0 0 1 0 9.602V2.398A2.393 2.393 0 0 1 2.398 0h7.203A2.394 2.394 0 0 1 12 2.398v7.204A2.394 2.394 0 0 1 9.601 12H2.398zM.602 7.199v1.199c0 .454.329.575.5.602.054.008.097 0 .097 0h3.602c.301 0 .597-.301.597-.301s.301-.301.602-.301.602.301.602.301.296.301.597.301h3.602c.597 0 .597-.602.597-.602V7.199c0-1.801-1.199-1.801-1.199-1.801h-3c-.301 0-.597.903-.597.903s-.301.898-.602.898-.602-.898-.602-.898-.296-.903-.597-.903h-3s-1.199 0-1.199 1.801" fill="url(#abe)"/></g></g></svg></svg>
|
||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 2.8 KiB |
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 26 26"
|
||||
version="1.1"
|
||||
width="26"
|
||||
height="26">
|
||||
<g id="surface1">
|
||||
<path style=" "
|
||||
d="M 13 4 C 8.5625 4 4.667969 6.410156 2.59375 10 C 2.316406 10.484375 2.484375 11.097656 2.96875 11.375 C 3.453125 11.652344 4.066406 11.484375 4.34375 11 C 6.070313 8.011719 9.289063 6 13 6 C 16.710938 6 19.929688 8.007813 21.65625 11 C 21.933594 11.484375 22.546875 11.652344 23.03125 11.375 C 23.515625 11.097656 23.683594 10.484375 23.40625 10 C 21.332031 6.410156 17.4375 4 13 4 Z M 13 8 C 8.59375 8 5 11.59375 5 16 C 4.996094 16.359375 5.183594 16.695313 5.496094 16.878906 C 5.808594 17.058594 6.191406 17.058594 6.503906 16.878906 C 6.816406 16.695313 7.003906 16.359375 7 16 C 7 12.675781 9.675781 10 13 10 C 16.324219 10 19 12.675781 19 16 C 18.996094 16.359375 19.183594 16.695313 19.496094 16.878906 C 19.808594 17.058594 20.191406 17.058594 20.503906 16.878906 C 20.816406 16.695313 21.003906 16.359375 21 16 C 21 11.59375 17.40625 8 13 8 Z M 13 12 C 10.789063 12 9 13.789063 9 16 C 9 18.210938 10.789063 20 13 20 C 15.210938 20 17 18.210938 17 16 C 17 13.789063 15.210938 12 13 12 Z "/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |