33 Commits

Author SHA1 Message Date
László Monda
3e621a2818 Bump version to 1.2.11 and update package.json 2018-10-03 05:43:41 +02:00
Róbert Kiss
247ec4c1b2 feat: add backspace and caps lock icons (#803)
Summary:
- svg sprite generate with xmlns:xlink="http://www.w3.org/1999/xlink" namespace
- uhk-icon-agent-icon css class renamed to uhk-icon-pure-agent-icon because
  it collided with agent icon sprites
- added backspace and caps lock icons
2018-10-01 02:06:23 +02:00
Róbert Kiss
edcff069fd fix: write agent version into the log when upgrade firmware (#802) 2018-09-30 22:48:42 +02:00
László Monda
8afdeac306 Fix right and middle mouse click macro actions which were exchanged. Fixes #794. 2018-09-27 00:35:13 +02:00
László Monda
425f861451 Add issue template regarding Karabiner Elements. 2018-09-26 00:05:14 +02:00
László Monda
5a843ed02c Include Agent version to the firmware update log. 2018-09-25 15:48:27 +02:00
László Monda
f3bd83af03 Bump version to 1.2.10, update changelog and package.json 2018-09-24 04:21:24 +02:00
László Monda
0b3fca63b7 Add History Back and History Forward scancodes. Resolves #776. 2018-09-24 03:56:29 +02:00
László Monda
cbd4460df0 Map Caps Lock without Ctrl on default keymaps. 2018-09-24 03:03:05 +02:00
László Monda
b941bd9a75 Set the decelerated scroll speed of the default configuration to 10. 2018-09-24 02:32:25 +02:00
László Monda
439b84affc Save decelerated mouse scroll speed properly instead of using the accelerated scroll speed by accident. Fixes https://github.com/UltimateHackingKeyboard/firmware/issues/178 2018-09-24 02:21:00 +02:00
László Monda
66d5302e6f Add play/pause icon. Improves #591. 2018-09-21 01:43:15 +02:00
László Monda
9e2e2b9c5c Add more exact instructions to the permission setup screen. Fixes #781. 2018-09-21 00:56:50 +02:00
Róbert Kiss
aa243ac7b0 feat: allow Layer Switcher secondary roles only on base layer (#790) 2018-09-21 00:20:46 +02:00
László Monda
eb421e0681 Revert "Remove unused mustache file."
This reverts commit 63aae8f578.
2018-09-20 02:31:06 +02:00
László Monda
63aae8f578 Remove unused mustache file. 2018-09-20 02:08:58 +02:00
László Monda
e577454a31 Make all SVGs non-executable. 2018-09-20 02:05:51 +02:00
László Monda
e802bb0052 Remove unused SVGs. 2018-09-20 02:05:15 +02:00
László Monda
b98e5df20a Add backspace and caps lock icons. Improves #83. 2018-09-20 01:42:05 +02:00
Róbert Kiss
7332105edb feat: remap on all keymap warning (#789) 2018-09-19 23:02:32 +02:00
László Monda
6a4feaf18d Merge branch 'master' of github.com:UltimateHackingKeyboard/agent 2018-09-16 21:30:58 +02:00
László Monda
ee637d7958 Rename Scroll Lock to ScrLk and Num Lock to NumLk on keys. Improves #83. 2018-09-16 21:28:54 +02:00
Róbert Kiss
8d161ce8ff chore: upgrade Node.js => 8.12.0 (#783)
it's fix appveyor build
2018-09-16 21:17:40 +02:00
László Monda
8010bd8195 In the scancode select2 display "Print Screen SysRq" and add SysRq above PrtScn when rendering the key. Fixes #784. 2018-09-16 21:09:54 +02:00
Jan Christoph Ebersbach
059f1d5505 Fix swapped direction title for mouse movements (#778) 2018-09-16 01:16:11 +02:00
László Monda
123cab5724 Bump Agent version to 1.2.9 2018-09-13 20:42:07 +02:00
Róbert Kiss
c16365a0e5 fix: Alt+Tab triggers "Remap on all layers" (#773) 2018-09-11 22:29:30 +02:00
Róbert Kiss
a21d278c0c fix: modifier button layout (#772) 2018-09-11 21:56:30 +02:00
Róbert Kiss
0466916be1 fix: key modifier reordering (#771) 2018-09-11 00:29:22 +02:00
László Monda
9a845d8f6a Fix eeprom.js 2018-09-10 19:29:58 +02:00
Róbert Kiss
9ae1673499 feat: secondary role visualisation (#767)
* feat: secondary role visualisation

* fix: recalculate the text position of the secondary role if changes

* fix: recalculate the text position of SvgKeystrokeKeyComponent

* fix: recalculate the text position when changes anything

* fix: two line text key position calculation

* fix: fix space positioning

* fix: visualize second character of complex key

* style: remove extra line
2018-09-08 12:09:16 +02:00
László Monda
2d5a5e7aef Exchange Alt and Super modifiers in the key action popover. 2018-09-03 03:58:03 +02:00
Róbert Kiss
3e4d439852 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
2018-09-03 00:21:55 +02:00
87 changed files with 7399 additions and 11251 deletions

2
.nvmrc
View File

@@ -1 +1 @@
8.11.2 8.12.0

View File

@@ -6,6 +6,37 @@ 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). Every Agent version includes the most recent firmware version. See the [firmware changelog](https://github.com/UltimateHackingKeyboard/firmware/blob/master/CHANGELOG.md).
## [1.2.11] - 2018-10-03
Firmware: 8.2.5 [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.2.5)] | Device Protocol: 4.4.0 | User Config: 4.0.1 | Hardware Config: 1.0.0
- Add backspace and caps lock icons which avoids the overlap of their old texts.
- Fix right and middle mouse click macro actions which were exchanged.
- Include Agent version to the firmware update log.
## [1.2.10] - 2018-09-24
Firmware: 8.2.5 [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.2.5)] | Device Protocol: 4.4.0 | User Config: 4.0.1 | Hardware Config: 1.0.0
- Add History Back and History Forward scancodes.
- Save the actual decelerated scroll speed instead of using the accelerated scroll speed by accident.
- Allow layer switcher secondary roles only on the base layer.
- When remapping modifiers, display a warning suggesting to remap them on all layers.
- Display more exact instructions on the permission setup screen.
- Set the decelerated scroll speed of the default configuration from 20 to 10.
- Map Caps Lock without Ctrl on default keymaps.
- Rename "Scroll Lock" to "ScrLk" and "Num Lock" to "NumLk" on keys to avoid text overlap.
- In the scancode select2, display "Print Screen SysRq" and add SysRq above PrtScn when rendering the key.
- Fix left and right direction titles for mouse movement macro actions.
## [1.2.9] - 2018-09-13
Firmware: 8.2.5 [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.2.5)] | Device Protocol: 4.4.0 | User Config: 4.0.1 | Hardware Config: 1.0.0
- Display OS-specific modifiers.
- Display secondary roles.
- Don't trigger "Remap on all layers" after leaving Agent with Alt+Tab.
## [1.2.8] - 2018-08-26 ## [1.2.8] - 2018-08-26
Firmware: 8.**2.5** [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.2.5)] | Device Protocol: 4.4.0 | 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.4.0 | User Config: 4.0.1 | Hardware Config: 1.0.0

1
ISSUE_TEMPLATE Normal file
View File

@@ -0,0 +1 @@
If you're using Karabiner Elements on your Mac, then stop here! Make sure to close Karabiner Elements, then try to reproduce the issue again, even if you think that Karabiner Elements shouldn't be the cause. Karabiner Elements is the source of numerous problems, and we don't want to receive any more reports it causes.

7051
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@
"private": true, "private": true,
"author": "Ultimate Gadget Laboratories", "author": "Ultimate Gadget Laboratories",
"main": "electron/dist/electron-main.js", "main": "electron/dist/electron-main.js",
"version": "1.2.8", "version": "1.2.11",
"firmwareVersion": "8.2.5", "firmwareVersion": "8.2.5",
"deviceProtocolVersion": "4.4.0", "deviceProtocolVersion": "4.4.0",
"userConfigVersion": "4.0.1", "userConfigVersion": "4.0.1",
@@ -15,8 +15,8 @@
}, },
"license": "GPL-3.0", "license": "GPL-3.0",
"engines": { "engines": {
"node": ">=8.9.1 <9.0.0", "node": ">=8.12.0 <9.0.0",
"npm": ">=5.6.0 <6.0.0" "npm": ">=6.4.0 <7.0.0"
}, },
"devDependencies": { "devDependencies": {
"@types/electron-devtools-installer": "2.0.2", "@types/electron-devtools-installer": "2.0.2",
@@ -67,7 +67,7 @@
"rimraf": "2.6.1", "rimraf": "2.6.1",
"standard-version": "4.2.0", "standard-version": "4.2.0",
"stylelint": "9.5.0", "stylelint": "9.5.0",
"svg-sprite": "1.4.0", "svg-sprite": "1.5.0",
"ts-loader": "2.3.1", "ts-loader": "2.3.1",
"ts-node": "7.0.1", "ts-node": "7.0.1",
"tslint": "5.9.1", "tslint": "5.9.1",

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,8 @@ import {
IpcResponse, IpcResponse,
LogService, LogService,
mapObjectToUserConfigBinaryBuffer, mapObjectToUserConfigBinaryBuffer,
SaveUserConfigurationData SaveUserConfigurationData,
UpdateFirmwareData
} from 'uhk-common'; } from 'uhk-common';
import { deviceConnectionStateComparer, snooze, UhkHidDevice, UhkOperations } from 'uhk-usb'; import { deviceConnectionStateComparer, snooze, UhkHidDevice, UhkOperations } from 'uhk-usb';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
@@ -157,10 +158,12 @@ export class DeviceService {
public async updateFirmware(event: Electron.Event, args?: Array<string>): Promise<void> { public async updateFirmware(event: Electron.Event, args?: Array<string>): Promise<void> {
const response = new FirmwareUpgradeIpcResponse(); const response = new FirmwareUpgradeIpcResponse();
const data: UpdateFirmwareData = JSON.parse(args[0]);
let firmwarePathData: TmpFirmware; let firmwarePathData: TmpFirmware;
try { try {
this.logService.debug('Agent version:', data.versionInformation.version);
const hardwareModules = await this.getHardwareModules(false); const hardwareModules = await this.getHardwareModules(false);
this.logService.debug('Device right firmware version:', hardwareModules.rightModuleInfo.firmwareVersion); this.logService.debug('Device right firmware version:', hardwareModules.rightModuleInfo.firmwareVersion);
this.logService.debug('Device left firmware version:', hardwareModules.leftModuleInfo.firmwareVersion); this.logService.debug('Device left firmware version:', hardwareModules.leftModuleInfo.firmwareVersion);
@@ -168,8 +171,8 @@ export class DeviceService {
this.device.resetDeviceCache(); this.device.resetDeviceCache();
this.stopPollTimer(); this.stopPollTimer();
if (args && args.length > 0) { if (data.firmware) {
firmwarePathData = await saveTmpFirmware(args[0]); firmwarePathData = await saveTmpFirmware(data.firmware);
const packageJson = await getPackageJsonFromPathAsync(firmwarePathData.packageJsonPath); const packageJson = await getPackageJsonFromPathAsync(firmwarePathData.packageJsonPath);
this.logService.debug('New firmware version:', packageJson.firmwareVersion); this.logService.debug('New firmware version:', packageJson.firmwareVersion);

View File

@@ -6,7 +6,7 @@ import * as decompressTarbz from 'decompress-tarbz2';
import { TmpFirmware } from '../models/tmp-firmware'; import { TmpFirmware } from '../models/tmp-firmware';
export async function saveTmpFirmware(data: string): Promise<TmpFirmware> { export async function saveTmpFirmware(data: Array<number>): Promise<TmpFirmware> {
const tmpDirectory = dirSync(); const tmpDirectory = dirSync();
const zipFilePath = path.join(tmpDirectory.name, 'firmware.bz2'); const zipFilePath = path.join(tmpDirectory.name, 'firmware.bz2');
@@ -21,10 +21,9 @@ export async function saveTmpFirmware(data: string): Promise<TmpFirmware> {
}; };
} }
function writeDataToFile(data: string, filePath: string): Promise<void> { function writeDataToFile(data: Array<number>, filePath: string): Promise<void> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const array: Array<number> = JSON.parse(data); const buffer = new Buffer(data);
const buffer = new Buffer(array);
fs.writeFile(filePath, buffer, err => { fs.writeFile(filePath, buffer, err => {
if (err) { if (err) {

View File

@@ -3,9 +3,9 @@ import { UhkBuffer } from '../../uhk-buffer';
import { MacroAction, MacroActionId, MacroMouseSubAction, macroActionType } from './macro-action'; import { MacroAction, MacroActionId, MacroMouseSubAction, macroActionType } from './macro-action';
export enum MouseButtons { export enum MouseButtons {
Left = 1 << 0, Left = 0,
Middle = 1 << 1, Right = 1,
Right = 1 << 2 Middle = 2
} }
export interface JsObjectMouseButtonMacroAction { export interface JsObjectMouseButtonMacroAction {

View File

@@ -259,7 +259,7 @@
}, },
{ {
"id": "70", "id": "70",
"text": "Print Screen" "text": "Print Screen SysRq"
}, },
{ {
"id": "72", "id": "72",
@@ -509,6 +509,22 @@
"type": "media", "type": "media",
"scancode": 138 "scancode": 138
} }
},
{
"id": "145",
"text": "History Back",
"additional": {
"type": "media",
"scancode": 548
}
},
{
"id": "146",
"text": "History Forward",
"additional": {
"type": "media",
"scancode": 549
}
} }
] ]
}, },

View File

@@ -1,9 +1,11 @@
import { assertUInt8, assertUInt16 } from '../assert'; import { assertUInt16, assertUInt8 } from '../assert';
import { UhkBuffer } from '../uhk-buffer'; import { UhkBuffer } from '../uhk-buffer';
import { Keymap } from './keymap'; import { Keymap } from './keymap';
import { Macro } from './macro'; import { Macro } from './macro';
import { ModuleConfiguration } from './module-configuration'; import { ModuleConfiguration } from './module-configuration';
import { ConfigSerializer } from '../config-serializer'; import { ConfigSerializer } from '../config-serializer';
import { KeystrokeAction } from './key-action';
import { SecondaryRoleAction } from './secondary-role-action';
export class UserConfiguration { export class UserConfiguration {
@@ -90,7 +92,7 @@ export class UserConfiguration {
this.mouseMoveAcceleratedSpeed = jsonObject.mouseMoveAcceleratedSpeed; this.mouseMoveAcceleratedSpeed = jsonObject.mouseMoveAcceleratedSpeed;
this.mouseScrollInitialSpeed = jsonObject.mouseScrollInitialSpeed; this.mouseScrollInitialSpeed = jsonObject.mouseScrollInitialSpeed;
this.mouseScrollAcceleration = jsonObject.mouseScrollAcceleration; this.mouseScrollAcceleration = jsonObject.mouseScrollAcceleration;
this.mouseScrollDeceleratedSpeed = jsonObject.mouseScrollAcceleration; this.mouseScrollDeceleratedSpeed = jsonObject.mouseScrollDeceleratedSpeed;
this.mouseScrollBaseSpeed = jsonObject.mouseScrollBaseSpeed; this.mouseScrollBaseSpeed = jsonObject.mouseScrollBaseSpeed;
this.mouseScrollAcceleratedSpeed = jsonObject.mouseScrollAcceleratedSpeed; this.mouseScrollAcceleratedSpeed = jsonObject.mouseScrollAcceleratedSpeed;
this.moduleConfigurations = jsonObject.moduleConfigurations.map((moduleConfiguration: any) => { this.moduleConfigurations = jsonObject.moduleConfigurations.map((moduleConfiguration: any) => {
@@ -102,7 +104,9 @@ export class UserConfiguration {
return macro; return macro;
}); });
this.keymaps = jsonObject.keymaps.map((keymap: any) => new Keymap().fromJsonObject(keymap, this.macros)); this.keymaps = jsonObject.keymaps.map((keymap: any) => new Keymap().fromJsonObject(keymap, this.macros));
this.clean();
this.recalculateConfigurationLength(); this.recalculateConfigurationLength();
return this; return this;
} }
@@ -138,6 +142,8 @@ export class UserConfiguration {
this.keymaps = buffer.readArray<Keymap>(uhkBuffer => new Keymap().fromBinary(uhkBuffer, this.macros)); this.keymaps = buffer.readArray<Keymap>(uhkBuffer => new Keymap().fromBinary(uhkBuffer, this.macros));
ConfigSerializer.resolveSwitchKeymapActions(this.keymaps); ConfigSerializer.resolveSwitchKeymapActions(this.keymaps);
this.clean();
if (this.userConfigurationLength === 0) { if (this.userConfigurationLength === 0) {
this.recalculateConfigurationLength(); this.recalculateConfigurationLength();
} }
@@ -222,4 +228,30 @@ export class UserConfiguration {
this.deviceName = 'My UHK'; this.deviceName = 'My UHK';
} }
} }
/* Remove not allowed settings/bugs
* 1. Layer Switcher secondary roles allowed only on base layers
*/
private clean(): void {
for (const keymap of this.keymaps) {
for (let layerId = 1; layerId < keymap.layers.length; layerId++) {
const layer = keymap.layers[layerId];
for (const module of layer.modules) {
for (let keyActionId = 0; keyActionId < module.keyActions.length; keyActionId++) {
const keyAction = module.keyActions[keyActionId];
if (!keyAction || !(keyAction instanceof KeystrokeAction)) {
continue;
}
if (keyAction.secondaryRoleAction === SecondaryRoleAction.fn ||
keyAction.secondaryRoleAction === SecondaryRoleAction.mod ||
keyAction.secondaryRoleAction === SecondaryRoleAction.mouse) {
(keyAction as any)._secondaryRoleAction = undefined;
}
}
}
}
}
}
} }

View File

@@ -8,3 +8,4 @@ export * from './device-connection-state';
export * from './hardware-modules'; export * from './hardware-modules';
export * from './hardware-module-info'; export * from './hardware-module-info';
export * from './save-user-configuration-data'; export * from './save-user-configuration-data';
export * from './update-firmware-data';

View File

@@ -0,0 +1,6 @@
import { VersionInformation } from './version-information';
export interface UpdateFirmwareData {
versionInformation: VersionInformation;
firmware?: Array<number>;
}

View File

@@ -25,8 +25,8 @@
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz",
"integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=",
"requires": { "requires": {
"delegates": "1.0.0", "delegates": "^1.0.0",
"readable-stream": "2.3.6" "readable-stream": "^2.0.6"
} }
}, },
"bindings": { "bindings": {
@@ -39,8 +39,8 @@
"resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
"integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
"requires": { "requires": {
"readable-stream": "2.3.6", "readable-stream": "^2.3.5",
"safe-buffer": "5.1.1" "safe-buffer": "^5.1.1"
} }
}, },
"chownr": { "chownr": {
@@ -68,7 +68,7 @@
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz",
"integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=",
"requires": { "requires": {
"mimic-response": "1.0.0" "mimic-response": "^1.0.0"
} }
}, },
"deep-extend": { "deep-extend": {
@@ -91,7 +91,7 @@
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
"integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
"requires": { "requires": {
"once": "1.4.0" "once": "^1.4.0"
} }
}, },
"expand-template": { "expand-template": {
@@ -104,14 +104,14 @@
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
"requires": { "requires": {
"aproba": "1.2.0", "aproba": "^1.0.3",
"console-control-strings": "1.1.0", "console-control-strings": "^1.0.0",
"has-unicode": "2.0.1", "has-unicode": "^2.0.0",
"object-assign": "4.1.1", "object-assign": "^4.1.0",
"signal-exit": "3.0.2", "signal-exit": "^3.0.0",
"string-width": "1.0.2", "string-width": "^1.0.1",
"strip-ansi": "3.0.1", "strip-ansi": "^3.0.1",
"wide-align": "1.1.2" "wide-align": "^1.1.0"
} }
}, },
"github-from-package": { "github-from-package": {
@@ -139,7 +139,7 @@
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"requires": { "requires": {
"number-is-nan": "1.0.1" "number-is-nan": "^1.0.0"
} }
}, },
"isarray": { "isarray": {
@@ -182,7 +182,7 @@
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.3.0.tgz", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.3.0.tgz",
"integrity": "sha512-zwm6vU3SsVgw3e9fu48JBaRBCJGIvAgysDsqtf5+vEexFE71bEOtaMWb5zr/zODZNzTPtQlqUUpC79k68Hspow==", "integrity": "sha512-zwm6vU3SsVgw3e9fu48JBaRBCJGIvAgysDsqtf5+vEexFE71bEOtaMWb5zr/zODZNzTPtQlqUUpC79k68Hspow==",
"requires": { "requires": {
"semver": "5.5.0" "semver": "^5.4.1"
} }
}, },
"node-hid": { "node-hid": {
@@ -190,9 +190,9 @@
"resolved": "https://registry.npmjs.org/node-hid/-/node-hid-0.5.7.tgz", "resolved": "https://registry.npmjs.org/node-hid/-/node-hid-0.5.7.tgz",
"integrity": "sha512-dwwpOetL2+MGYgivbO22ML+45ieCGbueWv1rYxRgBoEc2QMp6UF6ZucEkYts1IA3YPWJNkmpGh6dqQ85n19szw==", "integrity": "sha512-dwwpOetL2+MGYgivbO22ML+45ieCGbueWv1rYxRgBoEc2QMp6UF6ZucEkYts1IA3YPWJNkmpGh6dqQ85n19szw==",
"requires": { "requires": {
"bindings": "1.3.0", "bindings": "^1.3.0",
"nan": "2.10.0", "nan": "^2.6.2",
"prebuild-install": "2.5.1" "prebuild-install": "^2.2.2"
} }
}, },
"noop-logger": { "noop-logger": {
@@ -205,10 +205,10 @@
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
"requires": { "requires": {
"are-we-there-yet": "1.1.4", "are-we-there-yet": "~1.1.2",
"console-control-strings": "1.1.0", "console-control-strings": "~1.1.0",
"gauge": "2.7.4", "gauge": "~2.7.3",
"set-blocking": "2.0.0" "set-blocking": "~2.0.0"
} }
}, },
"number-is-nan": { "number-is-nan": {
@@ -226,7 +226,7 @@
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": { "requires": {
"wrappy": "1.0.2" "wrappy": "1"
} }
}, },
"os-homedir": { "os-homedir": {
@@ -239,21 +239,21 @@
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-2.5.1.tgz", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-2.5.1.tgz",
"integrity": "sha512-3DX9L6pzwc1m1ksMkW3Ky2WLgPQUBiySOfXVl3WZyAeJSyJb4wtoH9OmeRGcubAWsMlLiL8BTHbwfm/jPQE9Ag==", "integrity": "sha512-3DX9L6pzwc1m1ksMkW3Ky2WLgPQUBiySOfXVl3WZyAeJSyJb4wtoH9OmeRGcubAWsMlLiL8BTHbwfm/jPQE9Ag==",
"requires": { "requires": {
"detect-libc": "1.0.3", "detect-libc": "^1.0.3",
"expand-template": "1.1.0", "expand-template": "^1.0.2",
"github-from-package": "0.0.0", "github-from-package": "0.0.0",
"minimist": "1.2.0", "minimist": "^1.2.0",
"mkdirp": "0.5.1", "mkdirp": "^0.5.1",
"node-abi": "2.3.0", "node-abi": "^2.2.0",
"noop-logger": "0.1.1", "noop-logger": "^0.1.1",
"npmlog": "4.1.2", "npmlog": "^4.0.1",
"os-homedir": "1.0.2", "os-homedir": "^1.0.1",
"pump": "2.0.1", "pump": "^2.0.1",
"rc": "1.2.6", "rc": "^1.1.6",
"simple-get": "2.7.0", "simple-get": "^2.7.0",
"tar-fs": "1.16.0", "tar-fs": "^1.13.0",
"tunnel-agent": "0.6.0", "tunnel-agent": "^0.6.0",
"which-pm-runs": "1.0.0" "which-pm-runs": "^1.0.0"
} }
}, },
"process-nextick-args": { "process-nextick-args": {
@@ -266,8 +266,8 @@
"resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
"integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
"requires": { "requires": {
"end-of-stream": "1.4.1", "end-of-stream": "^1.1.0",
"once": "1.4.0" "once": "^1.3.1"
} }
}, },
"rc": { "rc": {
@@ -275,10 +275,10 @@
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.6.tgz", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.6.tgz",
"integrity": "sha1-6xiYnG1PTxYsOZ953dKfODVWgJI=", "integrity": "sha1-6xiYnG1PTxYsOZ953dKfODVWgJI=",
"requires": { "requires": {
"deep-extend": "0.4.2", "deep-extend": "~0.4.0",
"ini": "1.3.5", "ini": "~1.3.0",
"minimist": "1.2.0", "minimist": "^1.2.0",
"strip-json-comments": "2.0.1" "strip-json-comments": "~2.0.1"
} }
}, },
"readable-stream": { "readable-stream": {
@@ -286,13 +286,13 @@
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"requires": { "requires": {
"core-util-is": "1.0.2", "core-util-is": "~1.0.0",
"inherits": "2.0.3", "inherits": "~2.0.3",
"isarray": "1.0.0", "isarray": "~1.0.0",
"process-nextick-args": "2.0.0", "process-nextick-args": "~2.0.0",
"safe-buffer": "5.1.1", "safe-buffer": "~5.1.1",
"string_decoder": "1.1.1", "string_decoder": "~1.1.1",
"util-deprecate": "1.0.2" "util-deprecate": "~1.0.1"
} }
}, },
"safe-buffer": { "safe-buffer": {
@@ -325,9 +325,9 @@
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.7.0.tgz", "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.7.0.tgz",
"integrity": "sha512-RkE9rGPHcxYZ/baYmgJtOSM63vH0Vyq+ma5TijBcLla41SWlh8t6XYIGMR/oeZcmr+/G8k+zrClkkVrtnQ0esg==", "integrity": "sha512-RkE9rGPHcxYZ/baYmgJtOSM63vH0Vyq+ma5TijBcLla41SWlh8t6XYIGMR/oeZcmr+/G8k+zrClkkVrtnQ0esg==",
"requires": { "requires": {
"decompress-response": "3.3.0", "decompress-response": "^3.3.0",
"once": "1.4.0", "once": "^1.3.1",
"simple-concat": "1.0.0" "simple-concat": "^1.0.0"
} }
}, },
"string-width": { "string-width": {
@@ -335,9 +335,9 @@
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"requires": { "requires": {
"code-point-at": "1.1.0", "code-point-at": "^1.0.0",
"is-fullwidth-code-point": "1.0.0", "is-fullwidth-code-point": "^1.0.0",
"strip-ansi": "3.0.1" "strip-ansi": "^3.0.0"
} }
}, },
"string_decoder": { "string_decoder": {
@@ -345,7 +345,7 @@
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": { "requires": {
"safe-buffer": "5.1.1" "safe-buffer": "~5.1.0"
} }
}, },
"strip-ansi": { "strip-ansi": {
@@ -353,7 +353,7 @@
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"requires": { "requires": {
"ansi-regex": "2.1.1" "ansi-regex": "^2.0.0"
} }
}, },
"strip-json-comments": { "strip-json-comments": {
@@ -366,10 +366,10 @@
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.0.tgz", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.0.tgz",
"integrity": "sha512-I9rb6v7mjWLtOfCau9eH5L7sLJyU2BnxtEZRQ5Mt+eRKmf1F0ohXmT/Jc3fr52kDvjJ/HV5MH3soQfPL5bQ0Yg==", "integrity": "sha512-I9rb6v7mjWLtOfCau9eH5L7sLJyU2BnxtEZRQ5Mt+eRKmf1F0ohXmT/Jc3fr52kDvjJ/HV5MH3soQfPL5bQ0Yg==",
"requires": { "requires": {
"chownr": "1.0.1", "chownr": "^1.0.1",
"mkdirp": "0.5.1", "mkdirp": "^0.5.1",
"pump": "1.0.3", "pump": "^1.0.0",
"tar-stream": "1.5.5" "tar-stream": "^1.1.2"
}, },
"dependencies": { "dependencies": {
"pump": { "pump": {
@@ -377,8 +377,8 @@
"resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz",
"integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==",
"requires": { "requires": {
"end-of-stream": "1.4.1", "end-of-stream": "^1.1.0",
"once": "1.4.0" "once": "^1.3.1"
} }
} }
} }
@@ -388,10 +388,10 @@
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.5.tgz", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.5.tgz",
"integrity": "sha512-mQdgLPc/Vjfr3VWqWbfxW8yQNiJCbAZ+Gf6GDu1Cy0bdb33ofyiNGBtAY96jHFhDuivCwgW1H9DgTON+INiXgg==", "integrity": "sha512-mQdgLPc/Vjfr3VWqWbfxW8yQNiJCbAZ+Gf6GDu1Cy0bdb33ofyiNGBtAY96jHFhDuivCwgW1H9DgTON+INiXgg==",
"requires": { "requires": {
"bl": "1.2.2", "bl": "^1.0.0",
"end-of-stream": "1.4.1", "end-of-stream": "^1.0.0",
"readable-stream": "2.3.6", "readable-stream": "^2.0.0",
"xtend": "4.0.1" "xtend": "^4.0.0"
} }
}, },
"tunnel-agent": { "tunnel-agent": {
@@ -399,7 +399,7 @@
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
"requires": { "requires": {
"safe-buffer": "5.1.1" "safe-buffer": "^5.0.1"
} }
}, },
"util-deprecate": { "util-deprecate": {
@@ -417,7 +417,7 @@
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz",
"integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==",
"requires": { "requires": {
"string-width": "1.0.2" "string-width": "^1.0.2"
} }
}, },
"wrappy": { "wrappy": {

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

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
<div class="row"> <div class="row">
<h1 class="col-xs-12 pane-title"> <h1 class="col-xs-12 pane-title">
<i class="uhk-icon uhk-icon-agent-icon"></i> <i class="uhk-icon uhk-icon-pure-agent-icon"></i>
<span>About</span> <span>About</span>
</h1> </h1>
<div class="col-xs-12"> <div class="col-xs-12">

View File

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

View File

@@ -93,10 +93,17 @@
<h4 *ngIf="activeTab === TabName.Hold">Hold mouse button</h4> <h4 *ngIf="activeTab === TabName.Hold">Hold mouse button</h4>
<h4 *ngIf="activeTab === TabName.Release">Release mouse button</h4> <h4 *ngIf="activeTab === TabName.Release">Release mouse button</h4>
<div class="btn-group"> <div class="btn-group">
<button *ngFor="let buttonLabel of buttonLabels; let buttonIndex = index" <button class="btn btn-default"
class="btn btn-default" [class.btn-primary]="hasButton(MouseButtons.Left)"
[class.btn-primary]="hasButton(buttonIndex)" (click)="setMouseClick(MouseButtons.Left)">Left
(click)="setMouseClick(buttonIndex)">{{buttonLabel}} </button>
<button class="btn btn-default"
[class.btn-primary]="hasButton(MouseButtons.Middle)"
(click)="setMouseClick(MouseButtons.Middle)">Middle
</button>
<button class="btn btn-default"
[class.btn-primary]="hasButton(MouseButtons.Right)"
(click)="setMouseClick(MouseButtons.Right)">Right
</button> </button>
</div> </div>
</div> </div>

View File

@@ -1,10 +1,11 @@
import { Component, Input, OnInit, ViewChild } from '@angular/core'; import { Component, Input, OnInit, ViewChild } from '@angular/core';
import { import {
MacroMouseSubAction,
MouseButtons,
MouseButtonMacroAction, MouseButtonMacroAction,
MoveMouseMacroAction, MoveMouseMacroAction,
ScrollMouseMacroAction, ScrollMouseMacroAction
MacroMouseSubAction
} from 'uhk-common'; } from 'uhk-common';
import { Tab } from '../../../../popover/tab'; import { Tab } from '../../../../popover/tab';
import { MacroBaseComponent } from '../macro-base.component'; import { MacroBaseComponent } from '../macro-base.component';
@@ -33,6 +34,7 @@ export class MacroMouseTabComponent extends MacroBaseComponent implements OnInit
@ViewChild('tab') selectedTab: Tab; @ViewChild('tab') selectedTab: Tab;
/* tslint:disable:variable-name: It is an enum type. So it can start with uppercase. */ /* tslint:disable:variable-name: It is an enum type. So it can start with uppercase. */
MouseButtons = MouseButtons;
TabName = TabName; TabName = TabName;
/* tslint:enable:variable-name */ /* tslint:enable:variable-name */
activeTab: TabName; activeTab: TabName;

View File

@@ -5,6 +5,7 @@ import {
KeyMacroAction, KeyMacroAction,
KeyModifiers, KeyModifiers,
MacroAction, MacroAction,
MouseButtons,
MouseButtonMacroAction, MouseButtonMacroAction,
MoveMouseMacroAction, MoveMouseMacroAction,
ScrollMouseMacroAction, ScrollMouseMacroAction,
@@ -176,7 +177,7 @@ export class MacroItemComponent implements OnInit, OnChanges {
let needAnd: boolean; let needAnd: boolean;
if (Math.abs(typedAction.x) !== 0) { if (Math.abs(typedAction.x) !== 0) {
this.title += ` by ${Math.abs(typedAction.x)}px ${typedAction.x > 0 ? 'leftward' : 'rightward'}`; this.title += ` by ${Math.abs(typedAction.x)}px ${typedAction.x > 0 ? 'rightward' : 'leftward'}`;
needAnd = true; needAnd = true;
} }
if (Math.abs(typedAction.y) !== 0) { if (Math.abs(typedAction.y) !== 0) {
@@ -197,12 +198,11 @@ export class MacroItemComponent implements OnInit, OnChanges {
this.title = 'Release mouse button: '; this.title = 'Release mouse button: ';
} }
const buttonLabels: string[] = ['Left', 'Middle', 'Right'];
const selectedButtons: boolean[] = action.getMouseButtons(); const selectedButtons: boolean[] = action.getMouseButtons();
const selectedButtonLabels: string[] = []; const selectedButtonLabels: string[] = [];
selectedButtons.forEach((isSelected, idx) => { selectedButtons.forEach((isSelected, idx) => {
if (isSelected && buttonLabels[idx]) { if (isSelected && MouseButtons[idx]) {
selectedButtonLabels.push(buttonLabels[idx]); selectedButtonLabels.push(MouseButtons[idx]);
} }
}); });
this.title += selectedButtonLabels.join(', '); this.title += selectedButtonLabels.join(', ');

View File

@@ -47,10 +47,14 @@
</ul> </ul>
</div> </div>
<div [ngSwitch]="activeTab"> <div [ngSwitch]="activeTab">
<keypress-tab #tab *ngSwitchCase="tabName.Keypress" class="popover-content" <keypress-tab #tab *ngSwitchCase="tabName.Keypress" class="popover-content pr-10"
[defaultKeyAction]="defaultKeyAction" [defaultKeyAction]="shadowKeyAction"
[secondaryRoleEnabled]="true" [secondaryRoleEnabled]="true"
[allowRemapOnAllKeymapWarning]="true"
[remapInfo]="remapInfo"
[showLayerSwitcherInSecondaryRoles]="currentLayer === 0"
(validAction)="keyActionValid=$event" (validAction)="keyActionValid=$event"
(keyActionChange)="keystrokeActionChange($event)"
></keypress-tab> ></keypress-tab>
<layer-tab #tab *ngSwitchCase="tabName.Layer" class="popover-content" <layer-tab #tab *ngSwitchCase="tabName.Layer" class="popover-content"
[defaultKeyAction]="defaultKeyAction" [defaultKeyAction]="defaultKeyAction"
@@ -85,10 +89,12 @@
</label> </label>
</div> </div>
<div class="checkbox"> <div class="checkbox">
<label> <label [ngClass]="{ disabled: disableRemapOnAllLayer }">
<input type="checkbox" <input type="checkbox"
name="remapOnAllLayer" name="remapOnAllLayer"
[(ngModel)]="remapInfo.remapOnAllLayer"> Remap on all layers [(ngModel)]="remapInfo.remapOnAllLayer"
[disabled]="disableRemapOnAllLayer"
(ngModelChange)="remapInfoChange()"> Remap on all layers
</label> </label>
</div> </div>
<div class="d-inline-block"> <div class="d-inline-block">

View File

@@ -99,6 +99,10 @@
padding: 10px 24px; padding: 10px 24px;
} }
.pr-10 {
padding-right: 10px;
}
.popover-overlay { .popover-overlay {
position: fixed; position: fixed;
width: 100%; width: 100%;
@@ -121,5 +125,10 @@
label { label {
margin-right: 5px; margin-right: 5px;
&.disabled {
cursor: not-allowed;
color: #959595;
}
} }
} }

View File

@@ -1,5 +1,6 @@
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
ChangeDetectorRef,
Component, Component,
ElementRef, ElementRef,
EventEmitter, EventEmitter,
@@ -24,6 +25,7 @@ import {
KeystrokeAction, KeystrokeAction,
MouseAction, MouseAction,
PlayMacroAction, PlayMacroAction,
SecondaryRoleAction,
SwitchKeymapAction, SwitchKeymapAction,
SwitchLayerAction SwitchLayerAction
} from 'uhk-common'; } from 'uhk-common';
@@ -104,10 +106,13 @@ export class PopoverComponent implements OnChanges {
topPosition: number = 0; topPosition: number = 0;
leftPosition: number = 0; leftPosition: number = 0;
animationState: string; animationState: string;
shadowKeyAction: KeyAction;
disableRemapOnAllLayer = false;
private readonly currentKeymap$ = new BehaviorSubject<Keymap>(undefined); private readonly currentKeymap$ = new BehaviorSubject<Keymap>(undefined);
constructor(store: Store<AppState>) { constructor(private store: Store<AppState>,
private cdRef: ChangeDetectorRef) {
this.animationState = 'closed'; this.animationState = 'closed';
this.keymaps$ = store.let(getKeymaps()) this.keymaps$ = store.let(getKeymaps())
.combineLatest(this.currentKeymap$) .combineLatest(this.currentKeymap$)
@@ -123,8 +128,10 @@ export class PopoverComponent implements OnChanges {
if (change['defaultKeyAction']) { if (change['defaultKeyAction']) {
let tab: TabName; let tab: TabName;
this.disableRemapOnAllLayer = false;
if (this.defaultKeyAction instanceof KeystrokeAction) { if (this.defaultKeyAction instanceof KeystrokeAction) {
this.keystrokeActionChange(this.defaultKeyAction);
tab = TabName.Keypress; tab = TabName.Keypress;
} else if (this.defaultKeyAction instanceof SwitchLayerAction) { } else if (this.defaultKeyAction instanceof SwitchLayerAction) {
tab = TabName.Layer; tab = TabName.Layer;
@@ -188,12 +195,39 @@ export class PopoverComponent implements OnChanges {
selectTab(tab: TabName): void { selectTab(tab: TabName): void {
this.activeTab = tab; this.activeTab = tab;
if (tab === TabName.Keypress) {
this.keystrokeActionChange(this.defaultKeyAction as KeystrokeAction);
}
} }
onOverlay() { onOverlay() {
this.cancel.emit(undefined); this.cancel.emit(undefined);
} }
remapInfoChange(): void {
this.selectedTab.remapInfoChanged(this.remapInfo);
}
keystrokeActionChange(keystrokeAction: KeystrokeAction): void {
this.shadowKeyAction = keystrokeAction;
const disableRemapOnAllLayer =
keystrokeAction &&
this.currentLayer === 0 &&
(keystrokeAction.secondaryRoleAction === SecondaryRoleAction.fn ||
keystrokeAction.secondaryRoleAction === SecondaryRoleAction.mod ||
keystrokeAction.secondaryRoleAction === SecondaryRoleAction.mouse);
if (this.disableRemapOnAllLayer !== disableRemapOnAllLayer) {
this.disableRemapOnAllLayer = disableRemapOnAllLayer;
if (disableRemapOnAllLayer) {
this.remapInfo.remapOnAllLayer = false;
}
this.cdRef.markForCheck();
}
}
private calculatePosition() { private calculatePosition() {
const offsetLeft: number = this.wrapPosition.left + 265; // 265 is a width of the side menu with a margin const offsetLeft: number = this.wrapPosition.left + 265; // 265 is a width of the side menu with a margin
const popover: HTMLElement = this.popoverHost.nativeElement; const popover: HTMLElement = this.popoverHost.nativeElement;

View File

@@ -36,20 +36,20 @@
<div class="btn-toolbar modifiers"> <div class="btn-toolbar modifiers">
<div class="btn-group btn-group-sm modifiers__left"> <div class="btn-group btn-group-sm modifiers__left">
<button type="button" class="btn btn-default" <button type="button" class="btn btn-default"
*ngFor="let modifier of leftModifiers; let index = index" *ngFor="let modifier of leftModifiers; trackBy:modifiersTrackBy"
[class.btn-primary]="leftModifierSelects[index]" [class.btn-primary]="modifier.checked"
(click)="toggleModifier(false, index)" (click)="toggleModifier(modifier)"
> >
{{modifier}} {{ modifier.text }}
</button> </button>
</div> </div>
<div class="btn-group btn-group-sm modifiers__right"> <div class="btn-group btn-group-sm modifiers__right">
<button type="button" class="btn btn-default" <button type="button" class="btn btn-default"
*ngFor="let modifier of rightModifiers; let index = index" *ngFor="let modifier of rightModifiers; trackBy:modifiersTrackBy"
[class.btn-primary]="rightModifierSelects[index]" [class.btn-primary]="modifier.checked"
(click)="toggleModifier(true, index)" (click)="toggleModifier(modifier)"
> >
{{modifier}} {{ modifier.text }}
</button> </button>
</div> </div>
</div> </div>
@@ -92,6 +92,11 @@
data-placement="bottom"></icon> data-placement="bottom"></icon>
</div> </div>
<div *ngIf="warningVisible" class="alert alert-warning remap-warning" role="alert">
You're about to remap a modifier key only on this layer. You probably want to remap it on all layers. If so, check
the <strong>Remap on all layers</strong> checkbox below.
</div>
<div class="disabled-state--text"> <div class="disabled-state--text">
<i class="fa fa-info-circle"></i> <i class="fa fa-info-circle"></i>
When a key is configured as layer switcher key, you can't assign other functions to it. When a key is configured as layer switcher key, you can't assign other functions to it.

View File

@@ -89,4 +89,11 @@
display: inline-block; display: inline-block;
width: 140px; width: 140px;
} }
.remap-warning {
margin-top: 10px;
margin-bottom: 0;
padding-top: 5px;
padding-bottom: 5px;
}
} }

View File

@@ -1,9 +1,31 @@
import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
EventEmitter,
Input,
OnChanges,
Output,
SimpleChanges
} from '@angular/core';
import { KeyAction, KeystrokeAction, KeystrokeType, SCANCODES, SECONDARY_ROLES } from 'uhk-common'; import { KeyAction, KeystrokeAction, KeystrokeType, SCANCODES, SECONDARY_ROLES } from 'uhk-common';
import { Tab } from '../tab'; import { Tab } from '../tab';
import { MapperService } from '../../../../services/mapper.service'; import { MapperService } from '../../../../services/mapper.service';
import { SelectOptionData } from '../../../../models/select-option-data'; import { SelectOptionData } from '../../../../models/select-option-data';
import { KeyModifierModel } from '../../../../models/key-modifier-model';
import { mapLeftRigthModifierToKeyActionModifier } from '../../../../util';
import { RemapInfo } from '../../../../models/remap-info';
export const secondaryRoleFilter = (showLayerSwitchers: boolean) => {
return (data): boolean => {
if (showLayerSwitchers) {
return data;
}
return data.text !== 'Layer switcher';
};
};
@Component({ @Component({
selector: 'keypress-tab', selector: 'keypress-tab',
@@ -14,38 +36,43 @@ import { SelectOptionData } from '../../../../models/select-option-data';
export class KeypressTabComponent extends Tab implements OnChanges { export class KeypressTabComponent extends Tab implements OnChanges {
@Input() defaultKeyAction: KeyAction; @Input() defaultKeyAction: KeyAction;
@Input() secondaryRoleEnabled: boolean; @Input() secondaryRoleEnabled: boolean;
@Input() allowRemapOnAllKeymapWarning: boolean;
@Input() remapInfo: RemapInfo;
@Input() showLayerSwitcherInSecondaryRoles: boolean;
leftModifiers: string[]; @Output() keyActionChange = new EventEmitter<KeystrokeAction>();
rightModifiers: string[];
leftModifierSelects: boolean[]; leftModifiers: KeyModifierModel[];
rightModifierSelects: boolean[]; rightModifiers: KeyModifierModel[];
scanCodeGroups: Array<SelectOptionData>; scanCodeGroups: Array<SelectOptionData>;
secondaryRoleGroups: Array<SelectOptionData>; secondaryRoleGroups: Array<SelectOptionData> = [];
selectedScancodeOption: SelectOptionData; selectedScancodeOption: SelectOptionData;
selectedSecondaryRoleIndex: number; selectedSecondaryRoleIndex: number;
warningVisible: boolean;
constructor(private mapper: MapperService) { constructor(private mapper: MapperService,
private cdRef: ChangeDetectorRef) {
super(); super();
this.leftModifiers = ['LShift', 'LCtrl', 'LSuper', 'LAlt']; this.leftModifiers = mapper.getLeftKeyModifiers();
this.rightModifiers = ['RShift', 'RCtrl', 'RSuper', 'RAlt']; this.rightModifiers = mapper.getRightKeyModifiers();
this.scanCodeGroups = [{ this.scanCodeGroups = [{
id: '0', id: '0',
text: 'None' text: 'None'
}]; }];
this.scanCodeGroups = this.scanCodeGroups.concat(SCANCODES); this.scanCodeGroups = this.scanCodeGroups.concat(SCANCODES);
this.secondaryRoleGroups = SECONDARY_ROLES;
this.leftModifierSelects = Array(this.leftModifiers.length).fill(false);
this.rightModifierSelects = Array(this.rightModifiers.length).fill(false);
this.selectedScancodeOption = this.scanCodeGroups[0]; this.selectedScancodeOption = this.scanCodeGroups[0];
this.selectedSecondaryRoleIndex = -1; this.selectedSecondaryRoleIndex = -1;
} }
ngOnChanges() { ngOnChanges(changes: SimpleChanges) {
if (changes.showLayerSwitcherInSecondaryRoles) {
this.fillSecondaryRoles();
}
this.fromKeyAction(this.defaultKeyAction); this.fromKeyAction(this.defaultKeyAction);
this.validAction.emit(this.keyActionValid()); this.keyActionChanged(false);
} }
keyActionValid(keystrokeAction?: KeystrokeAction): boolean { keyActionValid(keystrokeAction?: KeystrokeAction): boolean {
@@ -56,16 +83,16 @@ export class KeypressTabComponent extends Tab implements OnChanges {
return (keystrokeAction) ? (keystrokeAction.scancode > 0 || keystrokeAction.modifierMask > 0) : false; return (keystrokeAction) ? (keystrokeAction.scancode > 0 || keystrokeAction.modifierMask > 0) : false;
} }
onKeysCapture(event: { code: number, left: boolean[], right: boolean[] }) { onKeysCapture(event: { code: number, left: KeyModifierModel[], right: KeyModifierModel[] }) {
if (event.code) { if (event.code) {
this.selectedScancodeOption = this.findScancodeOptionByScancode(event.code, KeystrokeType.basic); this.selectedScancodeOption = this.findScancodeOptionByScancode(event.code, KeystrokeType.basic);
} else { } else {
this.selectedScancodeOption = this.scanCodeGroups[0]; this.selectedScancodeOption = this.scanCodeGroups[0];
} }
this.leftModifierSelects = event.left; this.leftModifiers = event.left;
this.rightModifierSelects = event.right; this.rightModifiers = event.right;
this.validAction.emit(this.keyActionValid()); this.keyActionChanged();
} }
fromKeyAction(keyAction: KeyAction): boolean { fromKeyAction(keyAction: KeyAction): boolean {
@@ -76,16 +103,12 @@ export class KeypressTabComponent extends Tab implements OnChanges {
// Restore selectedScancodeOption // Restore selectedScancodeOption
this.selectedScancodeOption = this.findScancodeOptionByScancode(keystrokeAction.scancode || 0, keystrokeAction.type); this.selectedScancodeOption = this.findScancodeOptionByScancode(keystrokeAction.scancode || 0, keystrokeAction.type);
const leftModifiersLength: number = this.leftModifiers.length; for (const modifier of this.leftModifiers) {
modifier.checked = (keystrokeAction.modifierMask & modifier.value) > 0;
// Restore modifiers
for (let i = 0; i < leftModifiersLength; ++i) {
this.leftModifierSelects[this.mapper.modifierMapper(i)] = ((keystrokeAction.modifierMask >> i) & 1) === 1;
} }
for (let i = leftModifiersLength; i < leftModifiersLength + this.rightModifierSelects.length; ++i) { for (const modifier of this.rightModifiers) {
const index: number = this.mapper.modifierMapper(i) - leftModifiersLength; modifier.checked = (keystrokeAction.modifierMask & modifier.value) > 0;
this.rightModifierSelects[index] = ((keystrokeAction.modifierMask >> i) & 1) === 1;
} }
// Restore secondaryRoleAction // Restore secondaryRoleAction
@@ -107,11 +130,7 @@ export class KeypressTabComponent extends Tab implements OnChanges {
} else { } else {
keystrokeAction.type = KeystrokeType[scTypePair[1]]; keystrokeAction.type = KeystrokeType[scTypePair[1]];
} }
keystrokeAction.modifierMask = 0; keystrokeAction.modifierMask = mapLeftRigthModifierToKeyActionModifier(this.leftModifiers, this.rightModifiers);
const modifiers = this.leftModifierSelects.concat(this.rightModifierSelects).map(x => x ? 1 : 0);
for (let i = 0; i < modifiers.length; ++i) {
keystrokeAction.modifierMask |= modifiers[i] << this.mapper.modifierMapper(i);
}
keystrokeAction.secondaryRoleAction = this.selectedSecondaryRoleIndex === -1 keystrokeAction.secondaryRoleAction = this.selectedSecondaryRoleIndex === -1
? undefined ? undefined
@@ -122,21 +141,31 @@ export class KeypressTabComponent extends Tab implements OnChanges {
} }
} }
toggleModifier(right: boolean, index: number) { toggleModifier(modifier: KeyModifierModel): void {
const modifierSelects: boolean[] = right ? this.rightModifierSelects : this.leftModifierSelects; modifier.checked = !modifier.checked;
modifierSelects[index] = !modifierSelects[index]; this.keyActionChanged();
this.validAction.emit(this.keyActionValid());
} }
onSecondaryRoleChange(id: string) { onSecondaryRoleChange(id: string) {
this.selectedSecondaryRoleIndex = +id; this.selectedSecondaryRoleIndex = +id;
this.keyActionChanged();
} }
onScancodeChange(id: string) { onScancodeChange(id: string) {
this.selectedScancodeOption = this.findScancodeOptionById(id); this.selectedScancodeOption = this.findScancodeOptionById(id);
this.validAction.emit(this.keyActionValid()); this.keyActionChanged();
}
modifiersTrackBy(index: number, modifier: KeyModifierModel): string {
return `${modifier.value}${modifier.checked}`;
}
remapInfoChanged(remapInfo: RemapInfo): void {
this.remapInfo = remapInfo;
const keystrokeAction = this.toKeyAction();
this.calculateRemapOnAllLayerWarningVisibility(keystrokeAction);
this.cdRef.markForCheck();
} }
private findScancodeOptionBy(predicate: (option: SelectOptionData) => boolean): SelectOptionData { private findScancodeOptionBy(predicate: (option: SelectOptionData) => boolean): SelectOptionData {
@@ -196,4 +225,27 @@ export class KeypressTabComponent extends Tab implements OnChanges {
return [scanCode, type]; return [scanCode, type];
} }
private keyActionChanged(dispatch = true): void {
const keystrokeAction = this.toKeyAction();
this.validAction.emit(this.keyActionValid(keystrokeAction));
this.calculateRemapOnAllLayerWarningVisibility(keystrokeAction);
if (dispatch) {
this.keyActionChange.emit(keystrokeAction);
}
}
private calculateRemapOnAllLayerWarningVisibility(keystrokeAction: KeystrokeAction): void {
this.warningVisible = this.allowRemapOnAllKeymapWarning &&
this.remapInfo &&
!this.remapInfo.remapOnAllLayer &&
keystrokeAction &&
!keystrokeAction.hasScancode() &&
keystrokeAction.hasOnlyOneActiveModifier();
}
private fillSecondaryRoles(): void {
this.secondaryRoleGroups = SECONDARY_ROLES
.filter(secondaryRoleFilter(this.showLayerSwitcherInSecondaryRoles));
}
} }

View File

@@ -1,10 +1,13 @@
import { EventEmitter, Output } from '@angular/core'; import { EventEmitter, Output } from '@angular/core';
import { KeyAction } from 'uhk-common'; import { KeyAction } from 'uhk-common';
import { RemapInfo } from '../../../models/remap-info';
export abstract class Tab { export abstract class Tab {
@Output() validAction = new EventEmitter<boolean>(); @Output() validAction = new EventEmitter<boolean>();
abstract keyActionValid(): boolean; abstract keyActionValid(): boolean;
abstract fromKeyAction(keyAction: KeyAction): boolean; abstract fromKeyAction(keyAction: KeyAction): boolean;
abstract toKeyAction(): KeyAction; abstract toKeyAction(): KeyAction;
remapInfoChanged(remapInfo: RemapInfo): void {}
} }

View File

@@ -1,5 +1,6 @@
import { ChangeDetectionStrategy, Component, EventEmitter, HostListener, Input, Output } from '@angular/core'; import { ChangeDetectionStrategy, Component, EventEmitter, HostListener, Input, Output } from '@angular/core';
import { CaptureService } from '../../../../services/capture.service'; import { CaptureService } from '../../../../services/capture.service';
import { KeyModifierModel } from '../../../../models/key-modifier-model';
@Component({ @Component({
selector: 'capture-keystroke-button', selector: 'capture-keystroke-button',
@@ -68,8 +69,8 @@ export class CaptureKeystrokeButtonComponent {
private saveScanCode(code?: number) { private saveScanCode(code?: number) {
this.record = false; this.record = false;
const left: boolean[] = this.captureService.getModifiers(true); const left: KeyModifierModel[] = this.captureService.getModifiers(true);
const right: boolean[] = this.captureService.getModifiers(false); const right: KeyModifierModel[] = this.captureService.getModifiers(false);
this.capture.emit({ this.capture.emit({
code, code,

View File

@@ -21,9 +21,13 @@
</p> </p>
<div *ngIf="state.showWhatWillThisDoContent"> <div *ngIf="state.showWhatWillThisDoContent">
Agent uses the following script to set up permissions. You can run it manually as root, then If you want to set up permissions manually:
<a class="link-inline" <ol>
(click)="retry()">retry</a>. <li>Open a terminal.</li>
<li>Run <code>su</code> to become root.</li>
<li>Paste the following script, and <a class="link-inline" (click)="retry()">retry</a>.</li>
</ol>
<div class="copy-container"> <div class="copy-container">
<span class="fa fa-2x fa-copy" <span class="fa fa-2x fa-copy"
ngxClipboard ngxClipboard

View File

@@ -131,7 +131,7 @@
</li> </li>
<li class="sidebar__level-0--item" [routerLinkActive]="['active']"> <li class="sidebar__level-0--item" [routerLinkActive]="['active']">
<div class="sidebar__level-0"> <div class="sidebar__level-0">
<i class="uhk-icon uhk-icon-agent-icon"></i> Agent <i class="uhk-icon uhk-icon-pure-agent-icon"></i> Agent
<i class="fa fa-chevron-up pull-right" <i class="fa fa-chevron-up pull-right"
(click)="toggleHide($event, 'agent')"></i> (click)="toggleHide($event, 'agent')"></i>
</div> </div>

View File

@@ -0,0 +1 @@
export const SECONDARY_ROLE_BOTTOM_MARGIN = 1;

View File

@@ -11,3 +11,4 @@ export { SvgSingleIconKeyComponent } from './svg-single-icon-key';
export { SvgSwitchKeymapKeyComponent } from './svg-switch-keymap-key'; export { SvgSwitchKeymapKeyComponent } from './svg-switch-keymap-key';
export { SvgTextIconKeyComponent } from './svg-text-icon-key'; export { SvgTextIconKeyComponent } from './svg-text-icon-key';
export { SvgTwoLineTextKeyComponent } from './svg-two-line-text-key'; export { SvgTwoLineTextKeyComponent } from './svg-two-line-text-key';
export { SvgSecondaryRoleComponent } from './svg-secondary-role';

View File

@@ -10,4 +10,11 @@
[attr.text-anchor]="'middle'" [attr.text-anchor]="'middle'"
[attr.font-size]="11"> [attr.font-size]="11">
<tspan [attr.x]="spanX">{{ text }}</tspan> <tspan [attr.x]="spanX">{{ text }}</tspan>
</svg:text> </svg:text>
<svg:g svg-secondary-role
*ngIf="secondaryText"
[height]="20"
[width]="width"
[y]="secondaryTextY"
[text]="secondaryText">
</svg:g>

Before

Width:  |  Height:  |  Size: 331 B

After

Width:  |  Height:  |  Size: 499 B

View File

@@ -1,15 +1,19 @@
import { Component, Input, OnInit, ChangeDetectionStrategy } from '@angular/core'; import { Component, Input, ChangeDetectionStrategy, OnChanges, SimpleChanges } from '@angular/core';
import { isRectangleAsSecondaryRoleKey } from '../util';
import { SECONDARY_ROLE_BOTTOM_MARGIN } from '../../constants';
@Component({ @Component({
selector: 'g[svg-icon-text-key]', selector: 'g[svg-icon-text-key]',
templateUrl: './svg-icon-text-key.component.html', templateUrl: './svg-icon-text-key.component.html',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class SvgIconTextKeyComponent implements OnInit { export class SvgIconTextKeyComponent implements OnChanges {
@Input() width: number; @Input() width: number;
@Input() height: number; @Input() height: number;
@Input() icon: string; @Input() icon: string;
@Input() text: string; @Input() text: string;
@Input() secondaryText: string;
useWidth: number; useWidth: number;
useHeight: number; useHeight: number;
@@ -17,16 +21,33 @@ export class SvgIconTextKeyComponent implements OnInit {
useY: number; useY: number;
textY: number; textY: number;
spanX: number; spanX: number;
secondaryTextY: number;
secondaryHeight: number;
constructor() { constructor() {
} }
ngOnInit() { ngOnChanges(changes: SimpleChanges): void {
this.calculatePositions();
}
private calculatePositions(): void {
let textYModifier = 0;
let secondaryYModifier = 0;
if (this.secondaryText && isRectangleAsSecondaryRoleKey(this.width, this.height)) {
textYModifier = this.height / 5;
secondaryYModifier = 5;
}
this.useWidth = this.width / 3; this.useWidth = this.width / 3;
this.useHeight = this.height / 3; this.useHeight = this.height / 3;
this.useX = (this.width > 2 * this.height) ? 0 : this.width / 3; this.useX = (this.width > 2 * this.height) ? 0 : this.width / 3;
this.useY = (this.width > 2 * this.height) ? this.height / 3 : this.height / 10; this.useY = (this.width > 2 * this.height) ? this.height / 3 : this.height / 10;
this.textY = (this.width > 2 * this.height) ? this.height / 2 : this.height * 0.6; this.textY = (this.width > 2 * this.height) ? this.height / 2 : this.height * 0.6;
this.spanX = (this.width > 2 * this.height) ? this.width * 0.6 : this.width / 2; this.spanX = (this.width > 2 * this.height) ? this.width * 0.6 : this.width / 2;
this.secondaryHeight = this.height / 4;
this.secondaryTextY = this.height - this.secondaryHeight - SECONDARY_ROLE_BOTTOM_MARGIN - secondaryYModifier;
} }
} }

View File

@@ -25,34 +25,40 @@
<svg:g svg-keystroke-key *ngSwitchCase="enumLabelTypes.KeystrokeKey" <svg:g svg-keystroke-key *ngSwitchCase="enumLabelTypes.KeystrokeKey"
[height]="height" [height]="height"
[width]="width" [width]="width"
[keystrokeAction]="labelSource"> [keystrokeAction]="labelSource"
[secondaryText]="secondaryText">
</svg:g> </svg:g>
<svg:g svg-one-line-text-key *ngSwitchCase="enumLabelTypes.OneLineText" <svg:g svg-one-line-text-key *ngSwitchCase="enumLabelTypes.OneLineText"
[height]="height" [height]="height"
[width]="width" [width]="width"
[text]="labelSource"> [text]="labelSource"
[secondaryText]="secondaryText">
</svg:g> </svg:g>
<svg:g svg-two-line-text-key *ngSwitchCase="enumLabelTypes.TwoLineText" <svg:g svg-two-line-text-key *ngSwitchCase="enumLabelTypes.TwoLineText"
[height]="height" [height]="height"
[width]="width" [width]="width"
[texts]="labelSource"> [texts]="labelSource"
[secondaryText]="secondaryText">
</svg:g> </svg:g>
<svg:g svg-text-icon-key *ngSwitchCase="enumLabelTypes.TextIcon" <svg:g svg-text-icon-key *ngSwitchCase="enumLabelTypes.TextIcon"
[height]="height" [height]="height"
[width]="width" [width]="width"
[text]="labelSource.text" [text]="labelSource.text"
[icon]="labelSource.icon"> [icon]="labelSource.icon"
[secondaryText]="secondaryText">
</svg:g> </svg:g>
<svg:g svg-icon-text-key *ngSwitchCase="enumLabelTypes.IconText" <svg:g svg-icon-text-key *ngSwitchCase="enumLabelTypes.IconText"
[height]="height" [height]="height"
[width]="width" [width]="width"
[icon]="labelSource.icon" [icon]="labelSource.icon"
[text]="labelSource.text"> [text]="labelSource.text"
[secondaryText]="secondaryText">
</svg:g> </svg:g>
<svg:g svg-single-icon-key *ngSwitchCase="enumLabelTypes.SingleIcon" <svg:g svg-single-icon-key *ngSwitchCase="enumLabelTypes.SingleIcon"
[height]="height" [height]="height"
[width]="width" [width]="width"
[icon]="labelSource"> [icon]="labelSource"
[secondaryText]="secondaryText">
</svg:g> </svg:g>
<svg:g svg-switch-keymap-key *ngSwitchCase="enumLabelTypes.SwitchKeymap" <svg:g svg-switch-keymap-key *ngSwitchCase="enumLabelTypes.SwitchKeymap"
[height]="height" [height]="height"

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -27,6 +27,8 @@ 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';
import { KeyModifierModel } from '../../../../models/key-modifier-model';
enum LabelTypes { enum LabelTypes {
KeystrokeKey, KeystrokeKey,
@@ -94,6 +96,7 @@ export class SvgKeyboardKeyComponent implements OnInit, OnChanges, OnDestroy {
labelType: LabelTypes; labelType: LabelTypes;
labelSource: any; labelSource: any;
secondaryText: string;
macros: Macro[]; macros: Macro[];
private subscription: Subscription; private subscription: Subscription;
private scanCodePressed: boolean; private scanCodePressed: boolean;
@@ -117,13 +120,13 @@ export class SvgKeyboardKeyComponent implements OnInit, OnChanges, OnDestroy {
this.scanCodePressed = false; this.scanCodePressed = false;
} }
@HostListener('click') @HostListener('click', ['$event'])
onClick() { onClick(e: MouseEvent) {
this.reset(); this.reset();
this.keyClick.emit({ this.keyClick.emit({
keyTarget: this.element.nativeElement, keyTarget: this.element.nativeElement,
shiftPressed: this.pressedShiftLocation > -1, shiftPressed: e.shiftKey,
altPressed: this.pressedAltLocation > -1 altPressed: e.altKey
}); });
this.pressedShiftLocation = -1; this.pressedShiftLocation = -1;
this.pressedAltLocation = -1; this.pressedAltLocation = -1;
@@ -140,14 +143,8 @@ export class SvgKeyboardKeyComponent implements OnInit, OnChanges, OnDestroy {
} else { } else {
this.recording = true; this.recording = true;
this.recordAnimation = 'active'; this.recordAnimation = 'active';
this.shiftPressed = e.shiftKey;
if (this.pressedShiftLocation > -1) { this.altPressed = e.altKey;
this.shiftPressed = true;
}
if (this.pressedAltLocation > -1) {
this.altPressed = true;
}
} }
} }
} }
@@ -248,8 +245,8 @@ export class SvgKeyboardKeyComponent implements OnInit, OnChanges, OnDestroy {
} }
private saveScanCode(code = 0) { private saveScanCode(code = 0) {
const left: boolean[] = this.captureService.getModifiers(true); const left: KeyModifierModel[] = this.captureService.getModifiers(true);
const right: boolean[] = this.captureService.getModifiers(false); const right: KeyModifierModel[] = this.captureService.getModifiers(false);
this.capture.emit({ this.capture.emit({
captured: { captured: {
@@ -265,17 +262,18 @@ export class SvgKeyboardKeyComponent implements OnInit, OnChanges, OnDestroy {
} }
private setLabels(): void { private setLabels(): void {
this.labelType = LabelTypes.OneLineText;
this.labelSource = undefined;
this.secondaryText = undefined;
if (!this.keyAction) { if (!this.keyAction) {
this.labelSource = undefined;
this.labelType = LabelTypes.OneLineText;
return; return;
} }
this.labelType = LabelTypes.OneLineText;
if (this.keyAction instanceof KeystrokeAction) { if (this.keyAction instanceof KeystrokeAction) {
const keyAction: KeystrokeAction = this.keyAction as KeystrokeAction; const keyAction: KeystrokeAction = this.keyAction as KeystrokeAction;
let newLabelSource: string[]; let newLabelSource: string[];
this.secondaryText = this.mapper.getSecondaryRoleText(keyAction.secondaryRoleAction);
if (!keyAction.hasActiveModifier() && keyAction.hasScancode()) { if (!keyAction.hasActiveModifier() && keyAction.hasScancode()) {
const scancode: number = keyAction.scancode; const scancode: number = keyAction.scancode;
@@ -293,29 +291,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

@@ -13,7 +13,8 @@
<svg:g svg-two-line-text-key *ngSwitchCase="'two-line'" <svg:g svg-two-line-text-key *ngSwitchCase="'two-line'"
[height]="height" [height]="height"
[width]="width" [width]="width"
[texts]="labelSource"> [texts]="labelSource"
[secondaryText]="subComponentSecondaryRoleText">
</svg:g> </svg:g>
</svg> </svg>
<svg [attr.viewBox]="viewBox" [attr.width]="modifierContainer.width" [attr.height]="modifierContainer.height" [attr.x]="modifierContainer.x" <svg [attr.viewBox]="viewBox" [attr.width]="modifierContainer.width" [attr.height]="modifierContainer.height" [attr.x]="modifierContainer.x"
@@ -28,10 +29,19 @@
</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>
<svg:g svg-secondary-role
*ngIf="thisSecondaryRoleText"
[height]="20"
[width]="secondaryTextWidth"
[y]="secondaryTextY"
[text]="thisSecondaryRoleText">
</svg:g>

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -1,7 +1,9 @@
import { Component, Input, OnChanges, OnInit, ChangeDetectionStrategy } from '@angular/core'; import { Component, Input, OnChanges, ChangeDetectionStrategy } from '@angular/core';
import { KeyModifiers, KeystrokeAction } from 'uhk-common'; import { KeyModifiers, KeystrokeAction } from 'uhk-common';
import { MapperService } from '../../../../services/mapper.service'; import { MapperService } from '../../../../services/mapper.service';
import { isRectangleAsSecondaryRoleKey } from '../util';
import { SECONDARY_ROLE_BOTTOM_MARGIN } from '../../constants';
class SvgAttributes { class SvgAttributes {
width: number; width: number;
@@ -25,10 +27,11 @@ class SvgAttributes {
styleUrls: ['./svg-keystroke-key.component.scss'], styleUrls: ['./svg-keystroke-key.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class SvgKeystrokeKeyComponent implements OnInit, OnChanges { export class SvgKeystrokeKeyComponent implements OnChanges {
@Input() height: number; @Input() height: number;
@Input() width: number; @Input() width: number;
@Input() keystrokeAction: KeystrokeAction; @Input() keystrokeAction: KeystrokeAction;
@Input() secondaryText: string;
viewBox: string; viewBox: string;
textContainer: SvgAttributes; textContainer: SvgAttributes;
@@ -46,6 +49,11 @@ export class SvgKeystrokeKeyComponent implements OnInit, OnChanges {
option?: string, option?: string,
command?: string command?: string
}; };
secondaryTextY: number;
secondaryTextWidth: number;
secondaryHeight: number;
thisSecondaryRoleText: string;
subComponentSecondaryRoleText: string;
constructor(private mapper: MapperService) { constructor(private mapper: MapperService) {
this.modifierIconNames = {}; this.modifierIconNames = {};
@@ -57,15 +65,75 @@ export class SvgKeystrokeKeyComponent implements OnInit, OnChanges {
this.command = new SvgAttributes(); this.command = new SvgAttributes();
} }
ngOnInit() { ngOnChanges() {
this.calculatePositions();
}
private calculatePositions(): void {
let textYModifier = 0;
let secondaryYModifier = 0;
this.thisSecondaryRoleText = this.secondaryText;
this.subComponentSecondaryRoleText = null;
const bottomSideMode: boolean = this.width < this.height * 1.8;
const isRectangleAsSecondaryRole = isRectangleAsSecondaryRoleKey(this.width, this.height);
if (this.secondaryText && isRectangleAsSecondaryRole) {
textYModifier = this.height / 5;
secondaryYModifier = 5;
}
if (this.keystrokeAction.hasScancode()) {
const scancode: number = this.keystrokeAction.scancode;
this.labelSource = this.mapper.scanCodeToSvgImagePath(scancode, this.keystrokeAction.type);
if (this.labelSource) {
this.labelType = 'icon';
} else {
let newLabelSource: string[];
newLabelSource = this.mapper.scanCodeToText(scancode, this.keystrokeAction.type);
if (newLabelSource) {
if (this.secondaryText && newLabelSource.length === 2) {
if (isRectangleAsSecondaryRole || bottomSideMode) {
this.labelSource = newLabelSource[0];
this.labelType = 'one-line';
} else {
this.labelSource = newLabelSource;
this.labelType = 'two-line';
this.thisSecondaryRoleText = null;
this.subComponentSecondaryRoleText = this.secondaryText;
}
}
else {
if (newLabelSource.length === 1) {
this.labelSource = newLabelSource[0];
this.labelType = 'one-line';
} else {
this.labelSource = newLabelSource;
this.labelType = 'two-line';
}
}
}
}
} else {
this.labelType = 'empty';
}
this.shift.disabled = !this.keystrokeAction.isActive(KeyModifiers.leftShift | KeyModifiers.rightShift);
this.control.disabled = !this.keystrokeAction.isActive(KeyModifiers.leftCtrl | KeyModifiers.rightCtrl);
this.option.disabled = !this.keystrokeAction.isActive(KeyModifiers.leftAlt | KeyModifiers.rightAlt);
this.command.disabled = !this.keystrokeAction.isActive(KeyModifiers.leftGui | KeyModifiers.rightGui);
this.secondaryHeight = this.secondaryText ? this.height / 4 : 0;
this.secondaryTextY = this.height - this.secondaryHeight - SECONDARY_ROLE_BOTTOM_MARGIN - secondaryYModifier;
this.viewBox = [0, 0, this.width, this.height].join(' '); this.viewBox = [0, 0, this.width, this.height].join(' ');
this.modifierIconNames.shift = this.mapper.getIcon('shift'); this.modifierIconNames.shift = this.mapper.getIcon('shift');
this.modifierIconNames.option = this.mapper.getIcon('option'); this.modifierIconNames.option = this.mapper.getIcon('option');
this.modifierIconNames.command = this.mapper.getIcon('command'); this.modifierIconNames.command = this.mapper.getIcon('command');
this.textContainer.y = 0;
const bottomSideMode: boolean = this.width < this.height * 1.8;
const heightWidthRatio = this.height / this.width; const heightWidthRatio = this.height / this.width;
this.secondaryTextWidth = this.width;
if (bottomSideMode) { if (bottomSideMode) {
const maxIconWidth = this.width / 4; const maxIconWidth = this.width / 4;
@@ -75,7 +143,7 @@ export class SvgKeystrokeKeyComponent implements OnInit, OnChanges {
const iconHeight = iconScalingFactor * maxIconHeight; const iconHeight = iconScalingFactor * maxIconHeight;
this.modifierContainer.width = this.width; this.modifierContainer.width = this.width;
this.modifierContainer.height = this.height / 5; this.modifierContainer.height = this.height / 5;
this.modifierContainer.y = this.height - this.modifierContainer.height; this.modifierContainer.y = this.height - this.modifierContainer.height - this.secondaryHeight;
this.shift.width = iconWidth; this.shift.width = iconWidth;
this.shift.height = iconHeight; this.shift.height = iconHeight;
this.shift.x = (maxIconWidth - iconWidth) / 2; this.shift.x = (maxIconWidth - iconWidth) / 2;
@@ -92,7 +160,7 @@ export class SvgKeystrokeKeyComponent implements OnInit, OnChanges {
this.command.height = iconHeight; this.command.height = iconHeight;
this.command.x = this.option.x + maxIconWidth; this.command.x = this.option.x + maxIconWidth;
this.command.y = this.shift.y; this.command.y = this.shift.y;
this.textContainer.y = -this.modifierContainer.height / 2; this.textContainer.y = -this.modifierContainer.height / 2 - this.secondaryHeight / 2;
} else { } else {
this.modifierContainer.width = this.width / 4; this.modifierContainer.width = this.width / 4;
this.modifierContainer.height = this.height; this.modifierContainer.height = this.height;
@@ -120,40 +188,11 @@ export class SvgKeystrokeKeyComponent implements OnInit, OnChanges {
this.command.x = this.option.x + this.width / 2; this.command.x = this.option.x + this.width / 2;
this.command.y = this.option.y; this.command.y = this.option.y;
this.textContainer.x = -this.modifierContainer.width / 2; this.textContainer.x = -this.modifierContainer.width / 2;
this.secondaryTextWidth = this.width - this.modifierContainer.width;
} }
this.textContainer.y -= textYModifier;
this.textContainer.width = this.width; this.textContainer.width = this.width;
this.textContainer.height = this.height; this.textContainer.height = this.height;
} }
ngOnChanges() {
if (this.keystrokeAction.hasScancode()) {
const scancode: number = this.keystrokeAction.scancode;
this.labelSource = this.mapper.scanCodeToSvgImagePath(scancode, this.keystrokeAction.type);
if (this.labelSource) {
this.labelType = 'icon';
} else {
let newLabelSource: string[];
newLabelSource = this.mapper.scanCodeToText(scancode, this.keystrokeAction.type);
if (newLabelSource) {
if (newLabelSource.length === 1) {
this.labelSource = newLabelSource[0];
this.labelType = 'one-line';
} else {
this.labelSource = newLabelSource;
this.labelType = 'two-line';
}
}
}
} else {
this.labelType = 'empty';
}
this.shift.disabled = !this.keystrokeAction.isActive(KeyModifiers.leftShift | KeyModifiers.rightShift);
this.control.disabled = !this.keystrokeAction.isActive(KeyModifiers.leftCtrl | KeyModifiers.rightCtrl);
this.option.disabled = !this.keystrokeAction.isActive(KeyModifiers.leftAlt | KeyModifiers.rightAlt);
this.command.disabled = !this.keystrokeAction.isActive(KeyModifiers.leftGui | KeyModifiers.rightGui);
}
} }

View File

@@ -1,6 +1,13 @@
<svg:text <svg:text
[attr.x]="0" [attr.x]="0"
[attr.y]="textY" [attr.y]="textY"
[attr.text-anchor]="'middle'"> [attr.text-anchor]="'middle'">
<tspan [attr.x]="spanX" dy="0">{{ text }}</tspan> <tspan [attr.x]="spanX" dy="0">{{ text }}</tspan>
</svg:text> </svg:text>
<svg:g svg-secondary-role
*ngIf="secondaryText"
[height]="20"
[width]="width"
[y]="secondaryTextY"
[text]="secondaryText">
</svg:g>

Before

Width:  |  Height:  |  Size: 154 B

After

Width:  |  Height:  |  Size: 316 B

View File

@@ -1,22 +1,43 @@
import { Component, Input, OnInit, ChangeDetectionStrategy } from '@angular/core'; import { Component, Input, ChangeDetectionStrategy, OnChanges, SimpleChanges } from '@angular/core';
import { isRectangleAsSecondaryRoleKey } from '../util';
import { SECONDARY_ROLE_BOTTOM_MARGIN } from '../../constants';
@Component({ @Component({
selector: 'g[svg-one-line-text-key]', selector: 'g[svg-one-line-text-key]',
templateUrl: './svg-one-line-text-key.component.html', templateUrl: './svg-one-line-text-key.component.html',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class SvgOneLineTextKeyComponent implements OnInit { export class SvgOneLineTextKeyComponent implements OnChanges {
@Input() height: number; @Input() height: number;
@Input() width: number; @Input() width: number;
@Input() text: string; @Input() text: string;
@Input() secondaryText: string;
textY: number; textY: number;
spanX: number; spanX: number;
secondaryTextY: number;
secondaryHeight: number;
constructor() { } constructor() { }
ngOnInit() { ngOnChanges(changes: SimpleChanges): void {
this.textY = this.height / 2; this.calculatePositions();
}
calculatePositions() {
let textYModifier = 0;
let secondaryYModifier = 0;
if (this.secondaryText && isRectangleAsSecondaryRoleKey(this.width, this.height)) {
textYModifier = this.height / 5;
secondaryYModifier = 5;
}
this.textY = this.height / 2 - textYModifier;
this.spanX = this.width / 2; this.spanX = this.width / 2;
this.secondaryHeight = this.height / 4;
this.secondaryTextY = this.height - this.secondaryHeight - SECONDARY_ROLE_BOTTOM_MARGIN - secondaryYModifier;
} }
} }

View File

@@ -0,0 +1 @@
export * from './svg-secondary-role.component';

View File

@@ -0,0 +1,15 @@
<svg [attr.viewBox]="viewBox" [attr.width]="width" [attr.height]="height" [attr.y]="y">
<g id="secondaryContent" [attr.transform]="transform">
<svg viewBox="0 0 14 14" width="12" height="12" x="2" [attr.y]="textY / 3.5">
<ellipse stroke="#fff" rx="6.5" ry="6.5" cy="7" cx="7" stroke-width="1" fill-opacity="0"/>
<text text-anchor="start" font-family="Helvetica" font-size="12" y="7.8" x="4" stroke-width="0">2
</text>
</svg>
<text [attr.y]="textY"
[attr.x]="textIndent"
font-size="12"
text-anchor="start">
{{ text }}
</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 667 B

View File

@@ -0,0 +1,52 @@
import {
ChangeDetectionStrategy,
Component,
ElementRef,
Input,
OnChanges,
OnInit,
SimpleChanges,
ViewChild
} from '@angular/core';
import { getContentWidth } from '../../../../util';
const SECONDARY_STYLE: CSSStyleDeclaration = {
font: '12px Helvetica'
} as any;
@Component({
selector: 'g[svg-secondary-role]',
templateUrl: './svg-secondary-role.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class SvgSecondaryRoleComponent implements OnInit, OnChanges {
@Input() height: number;
@Input() width: number;
@Input() y: number;
@Input() text: string;
@ViewChild('secondary') svgElement: ElementRef;
viewBox: string;
textY: number;
transform: string;
textIndent = 16;
ngOnInit(): void {
this.viewBox = [0, 0, this.width, this.height].join(' ');
this.textY = this.height / 2 - 2;
}
ngOnChanges(changes: SimpleChanges): void {
if (changes.text) {
this.calculateTextPosition();
}
}
private calculateTextPosition(): void {
const textWidth = getContentWidth(SECONDARY_STYLE, this.text) + this.textIndent;
const translateValue = Math.max(0, (this.width - textWidth) / 2);
this.transform = `translate(${ translateValue },0)`;
}
}

View File

@@ -4,3 +4,10 @@
[attr.x]="svgWidth" [attr.x]="svgWidth"
[attr.y]="svgHeight"> [attr.y]="svgHeight">
</svg:use> </svg:use>
<svg:g svg-secondary-role
*ngIf="secondaryText"
[height]="20"
[width]="width"
[y]="secondaryTextY"
[text]="secondaryText">
</svg:g>

Before

Width:  |  Height:  |  Size: 173 B

After

Width:  |  Height:  |  Size: 340 B

View File

@@ -1,22 +1,42 @@
import { Component, Input, OnInit, ChangeDetectionStrategy } from '@angular/core'; import { Component, Input, ChangeDetectionStrategy, OnChanges, SimpleChanges } from '@angular/core';
import { isRectangleAsSecondaryRoleKey } from '../util';
import { SECONDARY_ROLE_BOTTOM_MARGIN } from '../../constants';
@Component({ @Component({
selector: 'g[svg-single-icon-key]', selector: 'g[svg-single-icon-key]',
templateUrl: './svg-single-icon-key.component.html', templateUrl: './svg-single-icon-key.component.html',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class SvgSingleIconKeyComponent implements OnInit { export class SvgSingleIconKeyComponent implements OnChanges {
@Input() width: number; @Input() width: number;
@Input() height: number; @Input() height: number;
@Input() icon: string; @Input() icon: string;
@Input() secondaryText: string;
svgHeight: number; svgHeight: number;
svgWidth: number; svgWidth: number;
secondaryTextY: number;
secondaryHeight: number;
constructor() { } constructor() { }
ngOnInit() { ngOnChanges(changes: SimpleChanges): void {
this.calculatePositions();
}
calculatePositions(): void {
let textYModifier = 0;
let secondaryYModifier = 0;
if (this.secondaryText && isRectangleAsSecondaryRoleKey(this.width, this.height)) {
textYModifier = this.height / 5;
secondaryYModifier = 5;
}
this.svgWidth = this.width / 3; this.svgWidth = this.width / 3;
this.svgHeight = this.height / 3; this.svgHeight = this.height / 3;
this.secondaryHeight = this.height / 4;
this.secondaryTextY = this.height - this.secondaryHeight - SECONDARY_ROLE_BOTTOM_MARGIN - secondaryYModifier;
} }
} }

View File

@@ -9,4 +9,11 @@
[attr.height]="useHeight" [attr.height]="useHeight"
[attr.x]="useX" [attr.x]="useX"
[attr.y]="useY"> [attr.y]="useY">
</svg:use> </svg:use>
<svg:g svg-secondary-role
*ngIf="secondaryText"
[height]="20"
[width]="width"
[y]="secondaryTextY"
[text]="secondaryText">
</svg:g>

Before

Width:  |  Height:  |  Size: 309 B

After

Width:  |  Height:  |  Size: 484 B

View File

@@ -1,15 +1,19 @@
import { Component, Input, OnInit, ChangeDetectionStrategy } from '@angular/core'; import { Component, Input, ChangeDetectionStrategy, OnChanges, SimpleChanges } from '@angular/core';
import { isRectangleAsSecondaryRoleKey } from '../util';
import { SECONDARY_ROLE_BOTTOM_MARGIN } from '../../constants';
@Component({ @Component({
selector: 'g[svg-text-icon-key]', selector: 'g[svg-text-icon-key]',
templateUrl: './svg-text-icon-key.component.html', templateUrl: './svg-text-icon-key.component.html',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class SvgTextIconKeyComponent implements OnInit { export class SvgTextIconKeyComponent implements OnChanges {
@Input() width: number; @Input() width: number;
@Input() height: number; @Input() height: number;
@Input() text: string; @Input() text: string;
@Input() icon: string; @Input() icon: string;
@Input() secondaryText: string;
useWidth: number; useWidth: number;
useHeight: number; useHeight: number;
@@ -18,16 +22,33 @@ export class SvgTextIconKeyComponent implements OnInit {
textY: number; textY: number;
textAnchor: string; textAnchor: string;
spanX: number; spanX: number;
secondaryTextY: number;
secondaryHeight: number;
constructor() { } constructor() { }
ngOnInit() { ngOnChanges(changes: SimpleChanges): void {
this.calculatePositions();
}
calculatePositions(): void {
let textYModifier = 0;
let secondaryYModifier = 0;
if (this.secondaryText && isRectangleAsSecondaryRoleKey(this.width, this.height)) {
textYModifier = this.height / 5;
secondaryYModifier = 5;
}
this.useWidth = this.width / 3; this.useWidth = this.width / 3;
this.useHeight = this.height / 3; this.useHeight = this.height / 3;
this.useX = (this.width > 2 * this.height) ? this.width * 0.6 : this.width / 3; this.useX = (this.width > 2 * this.height) ? this.width * 0.6 : this.width / 3;
this.useY = (this.width > 2 * this.height) ? this.height / 3 : this.height / 2; this.useY = (this.width > 2 * this.height) ? this.height / 3 : this.height / 2;
this.textY = (this.width > 2 * this.height) ? this.height / 2 : this.height / 3; this.textY = ((this.width > 2 * this.height) ? this.height / 2 : this.height / 3) - textYModifier;
this.textAnchor = (this.width > 2 * this.height) ? 'end' : 'middle'; this.textAnchor = (this.width > 2 * this.height) ? 'end' : 'middle';
this.spanX = (this.width > 2 * this.height) ? 0.6 * this.width : this.width / 2; this.spanX = (this.width > 2 * this.height) ? 0.6 * this.width : this.width / 2;
this.secondaryHeight = this.height / 4;
this.secondaryTextY = this.height - this.secondaryHeight - SECONDARY_ROLE_BOTTOM_MARGIN - secondaryYModifier;
} }
} }

View File

@@ -8,4 +8,11 @@
[attr.y]="spanYs[index]" [attr.y]="spanYs[index]"
dy="0" dy="0"
>{{ text }}</tspan> >{{ text }}</tspan>
</svg:text> </svg:text>
<svg:g svg-secondary-role
*ngIf="secondaryText"
[height]="20"
[width]="width"
[y]="secondaryTextY"
[text]="secondaryText">
</svg:g>

Before

Width:  |  Height:  |  Size: 306 B

After

Width:  |  Height:  |  Size: 474 B

View File

@@ -1,28 +1,51 @@
import { Component, Input, OnInit, ChangeDetectionStrategy } from '@angular/core'; import { Component, Input, ChangeDetectionStrategy, SimpleChanges, OnChanges } from '@angular/core';
import { SECONDARY_ROLE_BOTTOM_MARGIN } from '../../constants';
@Component({ @Component({
selector: 'g[svg-two-line-text-key]', selector: 'g[svg-two-line-text-key]',
templateUrl: './svg-two-line-text-key.component.html', templateUrl: './svg-two-line-text-key.component.html',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class SvgTwoLineTextKeyComponent implements OnInit { export class SvgTwoLineTextKeyComponent implements OnChanges {
@Input() height: number; @Input() height: number;
@Input() width: number; @Input() width: number;
@Input() texts: string[]; @Input() texts: string[];
@Input() secondaryText: string;
textY: number; textY: number;
spanX: number; spanX: number;
spanYs: number[]; spanYs: number[];
secondaryTextY: number;
secondaryHeight: number;
constructor() { constructor() {
this.spanYs = []; this.spanYs = [];
} }
ngOnInit() { ngOnChanges(changes: SimpleChanges): void {
this.textY = this.height / 2; this.calculatePositions();
this.spanX = this.width / 2; }
for (let i = 0; i < this.texts.length; ++i) {
this.spanYs.push((0.75 - i * 0.5) * this.height); calculatePositions(): void {
let textYModifier = 0;
let secondaryYModifier = 0;
this.secondaryHeight = 0;
let textContainerHeight = this.height;
if (this.secondaryText) {
textYModifier = this.height / 5;
secondaryYModifier = 0;
this.secondaryHeight = this.height / 4;
textContainerHeight -= this.secondaryHeight;
} }
this.textY = textContainerHeight / 2;
this.spanX = this.width / 2;
this.spanYs = [];
for (let i = 0; i < this.texts.length; ++i) {
this.spanYs.push((0.75 - i * 0.5) * textContainerHeight);
}
this.secondaryTextY = this.height - this.secondaryHeight - SECONDARY_ROLE_BOTTOM_MARGIN - secondaryYModifier;
} }
} }

View File

@@ -0,0 +1,3 @@
export const isRectangleAsSecondaryRoleKey = (width: number, height: number): boolean => {
return width > height * 2.4;
};

View File

@@ -49,6 +49,7 @@ import {
SvgKeyHoverEvent SvgKeyHoverEvent
} from '../../../models/svg-key-events'; } from '../../../models/svg-key-events';
import { RemapInfo } from '../../../models/remap-info'; import { RemapInfo } from '../../../models/remap-info';
import { mapLeftRigthModifierToKeyActionModifier } from '../../../util';
interface NameValuePair { interface NameValuePair {
name: string; name: string;
@@ -181,14 +182,9 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges {
onCapture(event: SvgKeyboardCaptureEvent): void { onCapture(event: SvgKeyboardCaptureEvent): void {
const keystrokeAction: KeystrokeAction = new KeystrokeAction(); const keystrokeAction: KeystrokeAction = new KeystrokeAction();
const modifiers = event.captured.left.concat(event.captured.right).map(x => x ? 1 : 0);
keystrokeAction.scancode = event.captured.code; keystrokeAction.scancode = event.captured.code;
keystrokeAction.modifierMask = 0; keystrokeAction.modifierMask = mapLeftRigthModifierToKeyActionModifier(event.captured.left, event.captured.right);
for (let i = 0; i < modifiers.length; ++i) {
keystrokeAction.modifierMask |= modifiers[i] << this.mapper.modifierMapper(i);
}
this.store.dispatch( this.store.dispatch(
KeymapActions.saveKey( KeymapActions.saveKey(

View File

@@ -0,0 +1,7 @@
import { KeyModifiers } from 'uhk-common';
export interface KeyModifierModel {
text: string;
value: KeyModifiers;
checked: boolean;
}

View File

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

View File

@@ -1,3 +1,5 @@
import { KeyModifierModel } from './key-modifier-model';
export interface SvgKeyClickEvent { export interface SvgKeyClickEvent {
keyTarget: HTMLElement; keyTarget: HTMLElement;
shiftPressed?: boolean; shiftPressed?: boolean;
@@ -14,8 +16,8 @@ export interface SvgKeyboardKeyClickEvent extends SvgModuleKeyClickEvent {
export interface KeyCaptureData { export interface KeyCaptureData {
code: number; code: number;
left: boolean[]; left: KeyModifierModel[];
right: boolean[]; right: KeyModifierModel[];
} }
export interface SvgKeyCaptureEvent { export interface SvgKeyCaptureEvent {

View File

@@ -1,14 +1,18 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { MapperService } from './mapper.service';
import { KeyModifiers } from 'uhk-common';
import { KeyModifierModel } from '../models/key-modifier-model';
@Injectable() @Injectable()
export class CaptureService { export class CaptureService {
private mapping: Map<number, number>; private mapping: Map<number, number>;
private leftModifiers: Map<number, boolean>; private readonly leftModifiers: Map<number, KeyModifierModel>;
private rightModifiers: Map<number, boolean>; private readonly rightModifiers: Map<number, KeyModifierModel>;
constructor() { constructor(private mapper: MapperService) {
this.leftModifiers = new Map<number, boolean>(); this.leftModifiers = new Map<number, KeyModifierModel>();
this.rightModifiers = new Map<number, boolean>(); this.rightModifiers = new Map<number, KeyModifierModel>();
this.mapping = new Map<number, number>(); this.mapping = new Map<number, number>();
} }
@@ -21,26 +25,61 @@ export class CaptureService {
} }
public setModifier(left: boolean, code: number) { public setModifier(left: boolean, code: number) {
return left ? this.leftModifiers.set(code, true) : this.rightModifiers.set(code, true); const map = left ? this.leftModifiers : this.rightModifiers;
map.get(code).checked = true;
} }
public getModifiers(left: boolean) { public getModifiers(left: boolean) {
return left ? this.reMap(this.leftModifiers) : this.reMap(this.rightModifiers); const map = left ? this.leftModifiers : this.rightModifiers;
return Array.from(map.values());
} }
public initModifiers() { public initModifiers() {
this.leftModifiers.set(16, false); // Shift this.leftModifiers.set(16, {
this.leftModifiers.set(17, false); // Ctrl text: 'LShift',
this.leftModifiers.set(18, false); // Alt value: KeyModifiers.leftShift,
this.leftModifiers.set(91, false); // Super checked: false
});
this.leftModifiers.set(17, {
text: 'LCtrl',
value: KeyModifiers.leftCtrl,
checked: false
});
this.leftModifiers.set(18, {
text: this.mapper.getOsSpecificText('LAlt'),
value: KeyModifiers.leftAlt,
checked: false
});
this.leftModifiers.set(91, {
text: this.mapper.getOsSpecificText('LSuper'),
value: KeyModifiers.leftGui,
checked: false
});
this.rightModifiers.set(16, false); // Shift this.rightModifiers.set(16, {
this.rightModifiers.set(17, false); // Ctrl text: 'RShift',
this.rightModifiers.set(18, false); // Alt value: KeyModifiers.rightShift,
this.rightModifiers.set(91, false); // Super checked: false
});
this.rightModifiers.set(17, {
text: 'RCtrl',
value: KeyModifiers.rightCtrl,
checked: false
});
this.rightModifiers.set(18, {
text: this.mapper.getOsSpecificText('RAlt'),
value: KeyModifiers.rightAlt,
checked: false
});
this.rightModifiers.set(91, {
text: this.mapper.getOsSpecificText('RSuper'),
value: KeyModifiers.rightGui,
checked: false
});
} }
public populateMapping () { public populateMapping() {
this.mapping.set(8, 42); // Backspace this.mapping.set(8, 42); // Backspace
this.mapping.set(9, 43); // Tab this.mapping.set(9, 43); // Tab
this.mapping.set(13, 40); // Enter this.mapping.set(13, 40); // Enter
@@ -136,8 +175,4 @@ export class CaptureService {
this.mapping.set(221, 48); // Close bracket this.mapping.set(221, 48); // Close bracket
this.mapping.set(222, 52); // Single quote this.mapping.set(222, 52); // Single quote
} }
private reMap(value: Map<number, boolean>): boolean[] {
return [value.get(16), value.get(17), value.get(91), value.get(18)];
}
} }

View File

@@ -1,7 +1,14 @@
import { Injectable, NgZone } from '@angular/core'; import { Injectable, NgZone } from '@angular/core';
import { Action, Store } from '@ngrx/store'; import { Action, Store } from '@ngrx/store';
import { DeviceConnectionState, IpcEvents, IpcResponse, LogService, SaveUserConfigurationData } from 'uhk-common'; import {
DeviceConnectionState,
IpcEvents,
IpcResponse,
LogService,
SaveUserConfigurationData,
UpdateFirmwareData
} from 'uhk-common';
import { AppState } from '../store'; import { AppState } from '../store';
import { IpcCommonRenderer } from './ipc-common-renderer'; import { IpcCommonRenderer } from './ipc-common-renderer';
import { import {
@@ -34,12 +41,8 @@ export class DeviceRendererService {
this.ipcRenderer.send(IpcEvents.device.loadConfigurations); this.ipcRenderer.send(IpcEvents.device.loadConfigurations);
} }
updateFirmware(data?: Array<number>): void { updateFirmware(data: UpdateFirmwareData): void {
if (data) { this.ipcRenderer.send(IpcEvents.device.updateFirmware, JSON.stringify(data));
this.ipcRenderer.send(IpcEvents.device.updateFirmware, JSON.stringify(data));
} else {
this.ipcRenderer.send(IpcEvents.device.updateFirmware);
}
} }
startConnectionPoller(): void { startConnectionPoller(): void {

View File

@@ -1,22 +1,40 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { KeystrokeType } from 'uhk-common'; import { Store } from '@ngrx/store';
import { KeyModifiers, KeystrokeType, SecondaryRoleAction } from 'uhk-common';
import { Subscription } from 'rxjs/Subscription';
import { AppState, getOperatingSystem } from '../store';
import { OperatingSystem } from '../models/operating-system';
import { KeyModifierModel } from '../models/key-modifier-model';
@Injectable() @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>;
private secondaryRoleTexts: Map<number, 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();
this.initSecondaryRoleTexts();
});
} }
public scanCodeToText(scanCode: number, type: KeystrokeType = KeystrokeType.basic): string[] { public scanCodeToText(scanCode: number, type: KeystrokeType = KeystrokeType.basic): string[] {
@@ -27,7 +45,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 +97,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 +111,87 @@ export class MapperService {
} }
} }
public getOperatingSystem(): OperatingSystem {
return this.operatingSystem;
}
public getOsSpecificText(key: string): string {
const text = this.osSpecificTexts.get(key);
return text ? text : key;
}
public getSecondaryRoleText(secondaryRoleAction: SecondaryRoleAction): string {
return this.secondaryRoleTexts.get(secondaryRoleAction);
}
public getLeftKeyModifiers(): KeyModifierModel[] {
return [
{
text: 'LShift',
value: KeyModifiers.leftShift,
checked: false
},
{
text: 'LCtrl',
value: KeyModifiers.leftCtrl,
checked: false
},
{
text: this.getOsSpecificText('LAlt'),
value: KeyModifiers.leftAlt,
checked: false
},
{
text: this.getOsSpecificText('LSuper'),
value: KeyModifiers.leftGui,
checked: false
}
];
}
public getRightKeyModifiers(): KeyModifierModel[] {
return [
{
text: 'RShift',
value: KeyModifiers.rightShift,
checked: false
},
{
text: 'RCtrl',
value: KeyModifiers.rightCtrl,
checked: false
},
{
text: this.getOsSpecificText('RAlt'),
value: KeyModifiers.rightAlt,
checked: false
},
{
text: this.getOsSpecificText('RSuper'),
value: KeyModifiers.rightGui,
checked: false
}
];
}
private initOsSpecificText(): void {
this.osSpecificTexts = new Map<string, string>();
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 +231,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']);
@@ -159,8 +261,8 @@ export class MapperService {
this.basicScanCodeTextMap.set(67, ['F10']); this.basicScanCodeTextMap.set(67, ['F10']);
this.basicScanCodeTextMap.set(68, ['F11']); this.basicScanCodeTextMap.set(68, ['F11']);
this.basicScanCodeTextMap.set(69, ['F12']); this.basicScanCodeTextMap.set(69, ['F12']);
this.basicScanCodeTextMap.set(70, ['PrtScn']); this.basicScanCodeTextMap.set(70, ['PrtScn', 'SysRq']);
this.basicScanCodeTextMap.set(71, ['Scroll Lock']); this.basicScanCodeTextMap.set(71, ['ScrLk']);
this.basicScanCodeTextMap.set(72, ['Pause']); this.basicScanCodeTextMap.set(72, ['Pause']);
this.basicScanCodeTextMap.set(73, ['Insert']); this.basicScanCodeTextMap.set(73, ['Insert']);
this.basicScanCodeTextMap.set(74, ['Home']); this.basicScanCodeTextMap.set(74, ['Home']);
@@ -172,12 +274,12 @@ export class MapperService {
this.basicScanCodeTextMap.set(80, ['Left Arrow']); this.basicScanCodeTextMap.set(80, ['Left Arrow']);
this.basicScanCodeTextMap.set(81, ['Down Arrow']); this.basicScanCodeTextMap.set(81, ['Down Arrow']);
this.basicScanCodeTextMap.set(82, ['Up Arrow']); this.basicScanCodeTextMap.set(82, ['Up Arrow']);
this.basicScanCodeTextMap.set(83, ['Num Lock']); this.basicScanCodeTextMap.set(83, ['NumLk']);
this.basicScanCodeTextMap.set(84, ['/']); this.basicScanCodeTextMap.set(84, ['/']);
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,14 +326,19 @@ 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.mediaScanCodeTextMap.set(548, ['Hist -']);
this.sytemScanCodeTextMap.set(129, ['Power Down']); this.mediaScanCodeTextMap.set(549, ['Hist +']);
this.sytemScanCodeTextMap.set(130, ['Sleep']);
this.sytemScanCodeTextMap.set(131, ['Wake Up']); this.systemScanCodeTextMap = new Map<number, string[]>();
this.systemScanCodeTextMap.set(129, ['Power Down']);
this.systemScanCodeTextMap.set(130, ['Sleep']);
this.systemScanCodeTextMap.set(131, ['Wake Up']);
} }
private initScancodeIcons(): void { private initScancodeIcons(): void {
this.basicScancodeIcons = new Map<number, string>(); this.basicScancodeIcons = new Map<number, string>();
this.basicScancodeIcons.set(42, 'icon-kbd__backspace');
this.basicScancodeIcons.set(57, 'icon-kbd__caps-lock');
this.basicScancodeIcons.set(79, 'icon-kbd__mod--arrow-right'); this.basicScancodeIcons.set(79, 'icon-kbd__mod--arrow-right');
this.basicScancodeIcons.set(80, 'icon-kbd__mod--arrow-left'); this.basicScancodeIcons.set(80, 'icon-kbd__mod--arrow-left');
this.basicScancodeIcons.set(81, 'icon-kbd__mod--arrow-down'); this.basicScancodeIcons.set(81, 'icon-kbd__mod--arrow-down');
@@ -266,8 +373,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');
@@ -279,4 +390,18 @@ export class MapperService {
this.nameToFileName.set('scroll-up', 'icon-kbd__mouse--scroll-up'); this.nameToFileName.set('scroll-up', 'icon-kbd__mouse--scroll-up');
} }
private initSecondaryRoleTexts(): void {
this.secondaryRoleTexts = new Map<number, string>();
this.secondaryRoleTexts.set(0, 'LCtrl');
this.secondaryRoleTexts.set(1, 'LShift');
this.secondaryRoleTexts.set(2, 'LAlt');
this.secondaryRoleTexts.set(3, 'LSuper');
this.secondaryRoleTexts.set(4, 'RCtrl');
this.secondaryRoleTexts.set(5, 'RShift');
this.secondaryRoleTexts.set(6, 'RAlt');
this.secondaryRoleTexts.set(7, 'RSuper');
this.secondaryRoleTexts.set(8, 'Mod');
this.secondaryRoleTexts.set(9, 'Fn');
this.secondaryRoleTexts.set(10, 'Mouse');
}
} }

View File

@@ -14,7 +14,7 @@
"mouseMoveAcceleratedSpeed": 64, "mouseMoveAcceleratedSpeed": 64,
"mouseScrollInitialSpeed": 20, "mouseScrollInitialSpeed": 20,
"mouseScrollAcceleration": 20, "mouseScrollAcceleration": 20,
"mouseScrollDeceleratedSpeed": 20, "mouseScrollDeceleratedSpeed": 10,
"mouseScrollBaseSpeed": 20, "mouseScrollBaseSpeed": 20,
"mouseScrollAcceleratedSpeed": 50, "mouseScrollAcceleratedSpeed": 50,
"moduleConfigurations": [], "moduleConfigurations": [],
@@ -595,8 +595,7 @@
{ {
"keyActionType": "keystroke", "keyActionType": "keystroke",
"type": "basic", "type": "basic",
"scancode": 57, "scancode": 57
"modifierMask": 1
}, },
{ {
"keyActionType": "keystroke", "keyActionType": "keystroke",
@@ -1581,8 +1580,7 @@
{ {
"keyActionType": "keystroke", "keyActionType": "keystroke",
"type": "basic", "type": "basic",
"scancode": 57, "scancode": 57
"modifierMask": 1
}, },
{ {
"keyActionType": "keystroke", "keyActionType": "keystroke",
@@ -2576,8 +2574,7 @@
{ {
"keyActionType": "keystroke", "keyActionType": "keystroke",
"type": "basic", "type": "basic",
"scancode": 57, "scancode": 57
"modifierMask": 1
}, },
{ {
"keyActionType": "keystroke", "keyActionType": "keystroke",
@@ -3559,8 +3556,7 @@
{ {
"keyActionType": "keystroke", "keyActionType": "keystroke",
"type": "basic", "type": "basic",
"scancode": 57, "scancode": 57
"modifierMask": 1
}, },
{ {
"keyActionType": "keystroke", "keyActionType": "keystroke",
@@ -4551,8 +4547,7 @@
{ {
"keyActionType": "keystroke", "keyActionType": "keystroke",
"type": "basic", "type": "basic",
"scancode": 57, "scancode": 57
"modifierMask": 1
}, },
{ {
"keyActionType": "keystroke", "keyActionType": "keystroke",
@@ -5528,8 +5523,7 @@
{ {
"keyActionType": "keystroke", "keyActionType": "keystroke",
"type": "basic", "type": "basic",
"scancode": 57, "scancode": 57
"modifierMask": 1
}, },
{ {
"keyActionType": "keystroke", "keyActionType": "keystroke",
@@ -6513,8 +6507,7 @@
{ {
"keyActionType": "keystroke", "keyActionType": "keystroke",
"type": "basic", "type": "basic",
"scancode": 57, "scancode": 57
"modifierMask": 1
}, },
{ {
"keyActionType": "keystroke", "keyActionType": "keystroke",

View File

@@ -59,6 +59,7 @@ import {
SvgMouseScrollKeyComponent, SvgMouseScrollKeyComponent,
SvgMouseSpeedKeyComponent, SvgMouseSpeedKeyComponent,
SvgOneLineTextKeyComponent, SvgOneLineTextKeyComponent,
SvgSecondaryRoleComponent,
SvgSingleIconKeyComponent, SvgSingleIconKeyComponent,
SvgSwitchKeymapKeyComponent, SvgSwitchKeymapKeyComponent,
SvgTextIconKeyComponent, SvgTextIconKeyComponent,
@@ -186,7 +187,8 @@ import { HelpPageComponent } from './components/agent/help-page/help-page.compon
FileUploadComponent, FileUploadComponent,
AutoGrowInputComponent, AutoGrowInputComponent,
HelpPageComponent, HelpPageComponent,
ExternalUrlDirective ExternalUrlDirective,
SvgSecondaryRoleComponent
], ],
imports: [ imports: [
CommonModule, CommonModule,

View File

@@ -50,6 +50,7 @@ import {
} from '../actions/user-config'; } from '../actions/user-config';
import { DefaultUserConfigurationService } from '../../services/default-user-configuration.service'; import { DefaultUserConfigurationService } from '../../services/default-user-configuration.service';
import { DataStorageRepositoryService } from '../../services/datastorage-repository.service'; import { DataStorageRepositoryService } from '../../services/datastorage-repository.service';
import { getVersions } from '../../util';
@Injectable() @Injectable()
export class DeviceEffects { export class DeviceEffects {
@@ -201,12 +202,17 @@ export class DeviceEffects {
@Effect({dispatch: false}) updateFirmware$ = this.actions$ @Effect({dispatch: false}) updateFirmware$ = this.actions$
.ofType<UpdateFirmwareAction>(ActionTypes.UPDATE_FIRMWARE) .ofType<UpdateFirmwareAction>(ActionTypes.UPDATE_FIRMWARE)
.do(() => this.deviceRendererService.updateFirmware()); .do(() => this.deviceRendererService.updateFirmware({
versionInformation: getVersions()
}));
@Effect({dispatch: false}) updateFirmwareWith$ = this.actions$ @Effect({dispatch: false}) updateFirmwareWith$ = this.actions$
.ofType<UpdateFirmwareWithAction>(ActionTypes.UPDATE_FIRMWARE_WITH) .ofType<UpdateFirmwareWithAction>(ActionTypes.UPDATE_FIRMWARE_WITH)
.map(action => action.payload) .map(action => action.payload)
.do(data => this.deviceRendererService.updateFirmware(data)); .do(data => this.deviceRendererService.updateFirmware({
versionInformation: getVersions(),
firmware: data
}));
@Effect() updateFirmwareReply$ = this.actions$ @Effect() updateFirmwareReply$ = this.actions$
.ofType<UpdateFirmwareReplyAction>(ActionTypes.UPDATE_FIRMWARE_REPLY) .ofType<UpdateFirmwareReplyAction>(ActionTypes.UPDATE_FIRMWARE_REPLY)

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';

View File

@@ -1,4 +1,5 @@
export * from './find-new-item'; export * from './find-new-item';
export * from './html-helper'; export * from './html-helper';
export * from './key-modifier-model-mapper';
export * from './validators'; export * from './validators';
export * from './version-helper'; export * from './version-helper';

View File

@@ -0,0 +1,13 @@
import { KeyModifierModel } from '../models/key-modifier-model';
export const mapLeftRigthModifierToKeyActionModifier = (left: KeyModifierModel[], right: KeyModifierModel[]): number => {
const modifiers = [...left, ...right];
let result = 0;
for (const modifier of modifiers) {
if (modifier.checked) {
result |= modifier.value;
}
}
return result;
};

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -16,6 +16,10 @@ html, body {
height: 100%; height: 100%;
} }
.uhk-icon-pure-agent-icon {
background: url('assets/images/agent-icon.png') no-repeat;
}
.uhk-icon { .uhk-icon {
display: inline-block; display: inline-block;
width: 1em; width: 1em;

View File

@@ -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"><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> <?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 x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(12 0 0 -12 0 6)" spreadMethod="pad" id="bb"><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="ba" spreadMethod="pad" gradientTransform="matrix(12 0 0 -12 0 6)" gradientUnits="userSpaceOnUse" y2="0" x2="1" y1="0" x1="0"><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 clipPathUnits="userSpaceOnUse" id="bc"><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" y2="0" x2="11.746" y1="11.542" x1=".915" id="bd" xlink:href="#ba"/><linearGradient y2="-.051" x2="12" y1="11.898" x1=".102" gradientUnits="userSpaceOnUse" id="be" xlink:href="#bb"/></defs><path d="M14.341 8.604H.52V3.27h13.821v5.333z" fill="#343434"/><g clip-path="url(#bc)" fill="url(#bd)" transform="matrix(1.25 0 0 -1.25 0 15)"><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(#be)"/></g></svg></svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -8,5 +8,6 @@
} }
.uhk-icon-agent-icon { .uhk-icon-agent-icon {
background: url('assets/images/agent-icon.png') no-repeat; @extend %svg-common;
background-position: 100% 0;
} }

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 36 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path d="M576 64H205.26A63.97 63.97 0 0 0 160 82.75L9.37 233.37c-12.5 12.5-12.5 32.76 0 45.25L160 429.25c12 12 28.28 18.75 45.25 18.75H576c35.35 0 64-28.65 64-64V128c0-35.35-28.65-64-64-64zm-84.69 254.06c6.25 6.25 6.25 16.38 0 22.63l-22.62 22.62c-6.25 6.25-16.38 6.25-22.63 0L384 301.25l-62.06 62.06c-6.25 6.25-16.38 6.25-22.63 0l-22.62-22.62c-6.25-6.25-6.25-16.38 0-22.63L338.75 256l-62.06-62.06c-6.25-6.25-6.25-16.38 0-22.63l22.62-22.62c6.25-6.25 16.38-6.25 22.63 0L384 210.75l62.06-62.06c6.25-6.25 16.38-6.25 22.63 0l22.62 22.62c6.25 6.25 6.25 16.38 0 22.63L429.25 256l62.06 62.06z"/></svg>
<!--
Font Awesome Free 5.3.1 by @fontawesome - https://fontawesome.com
License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
-->

After

Width:  |  Height:  |  Size: 890 B

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
<path d="M 224 0 C 140.2 0 72 68.2 72 152 L 72 224 L 48 224 C 21.5 224 0 245.5 0 272 L 0 464 C 0 490.5 21.5 512 48 512 L 400 512 C 426.5 512 448 490.5 448 464 L 448 272 C 448 245.5 426.5 224 400 224 L 376 224 L 376 152 C 376 68.2 307.8 0 224 0 z M 224 80 C 263.7 80 296 112.3 296 152 L 296 224 L 152 224 L 152 152 C 152 112.3 184.3 80 224 80 z M 211.47656 290.19141 L 236.63477 290.19141 L 299.14648 454.2168 L 276.07422 454.2168 L 261.13281 412.13867 L 187.19531 412.13867 L 172.25391 454.2168 L 148.85352 454.2168 L 211.47656 290.19141 z M 224 312.05469 L 193.89844 393.68164 L 254.21289 393.68164 L 224 312.05469 z " />
</svg>
<!--
Based on Font Awesome Free 5.3.1 by @fontawesome - https://fontawesome.com
License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
-->

After

Width:  |  Height:  |  Size: 939 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 522 B

After

Width:  |  Height:  |  Size: 522 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 988.74573 512.02081">
<path d="M 49.021484 0.013671875 C 24.637109 -0.54414061 3.5527137e-15 16.517187 0 47.867188 L 0 463.96875 C 0 501.46875 40.700391 524.06758 72.400391 505.26758 L 424.40039 297.26758 C 455.80039 278.76758 455.90039 233.16797 424.40039 214.66797 L 72.400391 6.5683594 C 65.250391 2.3433594 57.149609 0.19960937 49.021484 0.013671875 z M 588.74609 33.052734 C 562.24609 33.052734 540.74609 54.552734 540.74609 81.052734 L 540.74609 433.05273 C 540.74609 459.55273 562.24609 481.05273 588.74609 481.05273 L 684.74609 481.05273 C 711.24609 481.05273 732.74609 459.55273 732.74609 433.05273 L 732.74609 81.052734 C 732.74609 54.552734 711.24609 33.052734 684.74609 33.052734 L 588.74609 33.052734 z M 844.74609 33.052734 C 818.24609 33.052734 796.74609 54.552734 796.74609 81.052734 L 796.74609 433.05273 C 796.74609 459.55273 818.24609 481.05273 844.74609 481.05273 L 940.74609 481.05273 C 967.24604 481.05273 988.74609 459.55273 988.74609 433.05273 L 988.74609 81.052734 C 988.74609 54.552734 967.24604 33.052734 940.74609 33.052734 L 844.74609 33.052734 z " />
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 716 B

After

Width:  |  Height:  |  Size: 716 B

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1,176 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="31.177315mm"
height="14.907915mm"
viewBox="0 0 110.4708 52.823321"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="segments_dvr.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="12.310946"
inkscape:cx="55.235392"
inkscape:cy="26.411669"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
showguides="true"
inkscape:guide-bbox="true"
inkscape:snap-bbox="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:object-paths="false"
inkscape:object-nodes="true"
inkscape:window-width="1920"
inkscape:window-height="1144"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(967.89459,-355.26718)">
<rect
style="opacity:1;fill:#000000;fill-opacity:1"
id="rect4658"
width="110.4708"
height="52.823322"
x="-967.89459"
y="355.26718"
ry="2.2743988" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -926.64583,399.89017 -0.9734,-0.97353 0,-7.48741 0,-7.48737 0.9733,-0.97384 0.9734,-0.97384 0.9736,0.9735 0.9736,0.9735 0,7.4955 0,7.49553 -0.9658,0.96575 c -0.5313,0.53114 -0.9693,0.96571 -0.9736,0.96571 0,0 -0.4457,-0.43807 -0.9811,-0.9735 z"
id="path3399"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -923.27903,396.77639 0,-2.02518 3.2037,-5.3394 3.2036,-5.33941 0.9135,0 0.9134,0 0,2.02331 0,2.02331 -3.2051,5.34097 -3.2052,5.34093 -0.9119,0 -0.912,0 0,-2.0252 z"
id="path3393"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -926.64593,380.38988 -0.9733,-0.97384 0,-7.48747 0,-7.4875 0.9773,-0.97724 0.9773,-0.97724 0.9697,0.96955 0.9696,0.96955 0,7.4955 0,7.49553 -0.9736,0.9735 -0.9736,0.9735 -0.9734,-0.97384 z"
id="path3385"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -910.27363,377.26274 0,-2.02282 3.2052,-5.3417 3.2052,-5.34171 0.9119,-6e-5 0.9119,-6e-5 0,2.02518 0,2.02521 -3.2036,5.3394 -3.2036,5.33941 -0.9135,0 -0.9135,0 0,-2.02282 z"
id="path3377"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -958.32118,402.15653 -0.9695,-0.96964 0.9695,-0.96961 0.9695,-0.96964 4.2481,0 4.24795,0 0.9695,0.96964 0.9696,0.96961 -0.9696,0.96964 -0.9695,0.96964 -4.24795,0 -4.2481,0 -0.9695,-0.96964 z"
id="path3371"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -945.31583,402.15653 -0.9695,-0.96964 0.9695,-0.96961 0.9696,-0.96964 4.248,0 4.248,0 0.9695,0.96964 0.96951,0.96961 -0.96951,0.96964 -0.9695,0.96964 -4.248,0 -4.248,0 -0.9696,-0.96964 z"
id="path3369"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -947.57453,399.89817 -0.9657,-0.96584 0,-7.50313 0,-7.5031 0.9696,-0.96955 0.9696,-0.96954 0.9697,0.96954 0.9696,0.96955 0,7.50319 0,7.50322 -0.9658,0.96575 c -0.5312,0.53114 -0.96929,0.96572 -0.97349,0.96572 -0.01,0 -0.44231,-0.43461 -0.9735,-0.96581 z"
id="path3365"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -934.56913,399.89817 -0.9657,-0.96584 0,-7.49544 0,-7.4954 0.9736,-0.9735 0.9736,-0.97351 0.9733,0.97384 0.9734,0.97384 0,7.48747 0,7.4875 -0.9735,0.97344 c -0.53539,0.53537 -0.97699,0.97341 -0.98119,0.97341 -0.01,0 -0.44231,-0.43461 -0.9735,-0.96581 z"
id="path3363"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -947.57453,380.39788 -0.9657,-0.96584 0,-7.5031 0,-7.50312 0.9696,-0.96955 0.9696,-0.96955 0.9697,0.96955 0.9696,0.96955 0,7.50322 0,7.50319 -0.9658,0.96574 c -0.5312,0.53114 -0.96929,0.96575 -0.97349,0.96575 -0.01,0 -0.44231,-0.43464 -0.9735,-0.96584 z"
id="path3351"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -934.56133,380.38988 -0.9735,-0.97359 0,-7.49544 0,-7.49541 0.9696,-0.96954 0.9697,-0.96955 0.9773,0.97724 0.9773,0.97724 0,7.48753 0,7.4875 -0.9735,0.97381 -0.97339,0.9738 -0.9735,-0.97359 z"
id="path3349"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -958.32118,363.14038 -0.9695,-0.96961 0.9695,-0.96964 0.9695,-0.96964 4.2481,0 4.24795,0 0.9695,0.96964 0.9696,0.96964 -0.9696,0.96961 -0.9695,0.96964 -4.24795,0 -4.2481,0 -0.9695,-0.96964 z"
id="path3343"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -945.31583,363.14038 -0.9695,-0.96961 0.9695,-0.96964 0.9696,-0.96964 4.248,0 4.248,0 0.9695,0.96964 0.96951,0.96964 -0.96951,0.96961 -0.9695,0.96964 -4.248,0 -4.248,0 -0.9696,-0.96964 z"
id="path4610-4-6"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -892.70413,399.89017 -0.9734,-0.97353 0,-7.48741 0,-7.48737 0.9734,-0.97384 0.9734,-0.97384 0.9735,0.9735 0.9736,0.9735 0,7.4955 0,7.49553 -0.9658,0.96575 c -0.5312,0.53114 -0.9693,0.96571 -0.9735,0.96571 0,0 -0.4458,-0.43807 -0.9812,-0.9735 z"
id="path3431"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -873.12673,393.45965 -3.2051,-5.34195 0,-2.02266 0,-2.02264 0.9134,0 0.9135,0 3.2036,5.33941 3.2037,5.3394 0,2.02518 0,2.02521 -0.912,0 -0.9119,0 -3.20519,-5.34195 z"
id="path3423"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -890.44163,382.65253 -0.9734,-0.97354 0.9735,-0.9734 0.9735,-0.97344 4.2479,0 4.248,0 0.9734,0.97353 0.9734,0.9735 -0.9735,0.97344 -0.9735,0.97344 -4.2479,0 -4.248,0 -0.9734,-0.97353 z"
id="path3421"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -877.43623,382.65253 -0.9734,-0.97354 0.9735,-0.9734 0.9735,-0.97344 4.248,0 4.2479,0 0.9734,0.97353 0.9734,0.9735 -0.9735,0.97344 -0.9735,0.97344 -4.2479,0 -4.2479,0 -0.97349,-0.97353 z"
id="path3419"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -892.70413,380.38988 -0.9734,-0.97384 0,-7.48747 0,-7.4875 0.9773,-0.97724 0.9774,-0.97724 0.9696,0.96955 0.9696,0.96955 0,7.4955 0,7.49553 -0.9736,0.9735 -0.9735,0.9735 -0.9734,-0.97384 z"
id="path3417"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -866.67783,380.38988 -0.9735,-0.97359 0,-7.49544 0,-7.49541 0.9696,-0.96954 0.9697,-0.96955 0.9773,0.97724 0.9773,0.97724 0,7.48753 0,7.4875 -0.97349,0.97381 -0.9734,0.9738 -0.9735,-0.97359 z"
id="path3413"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -890.43773,363.14038 -0.9695,-0.96961 0.9695,-0.96964 0.9695,-0.96964 4.2481,0 4.248,0 0.96951,0.96964 0.9696,0.96964 -0.9696,0.96961 -0.96951,0.96964 -4.248,0 -4.2481,0 -0.9695,-0.96964 z"
id="path3407"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -877.43233,363.14038 -0.9695,-0.96961 0.9695,-0.96964 0.9696,-0.96964 4.248,0 4.248,0 0.96951,0.96964 0.9695,0.96964 -0.9695,0.96961 -0.96951,0.96964 -4.248,0 -4.248,0 -0.9696,-0.96964 z"
id="path4610-1-5"
inkscape:connector-curvature="0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 8.6 KiB

View File

@@ -1,186 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="31.177315mm"
height="14.907915mm"
viewBox="0 0 110.4708 52.823321"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="segments_qwe.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="12.310946"
inkscape:cx="55.23539"
inkscape:cy="26.411671"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
showguides="true"
inkscape:guide-bbox="true"
inkscape:snap-bbox="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:object-paths="false"
inkscape:object-nodes="true"
inkscape:window-width="1920"
inkscape:window-height="1144"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(967.89459,-355.26718)">
<rect
style="opacity:1;fill:#000000;fill-opacity:1"
id="rect4658"
width="110.4708"
height="52.823322"
x="-967.89459"
y="355.26718"
ry="2.2743988" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -926.64583,399.89017 -0.9734,-0.97353 0,-7.48741 0,-7.48737 0.9733,-0.97384 0.9734,-0.97384 0.9736,0.9735 0.9736,0.9735 0,7.4955 0,7.49553 -0.9658,0.96575 c -0.5313,0.53114 -0.9693,0.96571 -0.9736,0.96571 0,0 -0.4457,-0.43807 -0.9811,-0.9735 z"
id="path4765"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -900.62733,399.89817 -0.9657,-0.96584 0,-7.49544 0,-7.4954 0.9735,-0.9735 0.9736,-0.97351 0.9734,0.97384 0.9734,0.97384 0,7.48747 0,7.4875 -0.9735,0.97344 c -0.5355,0.53537 -0.977,0.97341 -0.9813,0.97341 -0.01,0 -0.4422,-0.43461 -0.9734,-0.96581 z"
id="path4761"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -923.27903,396.77639 0,-2.02518 3.2037,-5.3394 3.2036,-5.33941 0.9135,0 0.9134,0 0,2.02331 0,2.02331 -3.2051,5.34097 -3.2052,5.34093 -0.9119,0 -0.912,0 0,-2.0252 z"
id="path4759"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -907.06843,393.45965 -3.2052,-5.34195 0,-2.02266 0,-2.02264 0.9135,0 0.9135,0 3.2036,5.33941 3.2036,5.3394 0,2.02518 0,2.02521 -0.9119,0 -0.91189,0 -3.2052,-5.34195 z"
id="path4757"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -926.64593,380.38988 -0.9733,-0.97384 0,-7.48747 0,-7.4875 0.9773,-0.97724 0.9773,-0.97724 0.9697,0.96955 0.9696,0.96955 0,7.4955 0,7.49553 -0.9736,0.9735 -0.9736,0.9735 -0.9734,-0.97384 z"
id="path4751"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -900.61953,380.38988 -0.9735,-0.97359 0,-7.49544 0,-7.49541 0.9696,-0.96954 0.9696,-0.96955 0.9774,0.97724 0.9773,0.97724 0,7.48753 0,7.4875 -0.9735,0.97381 -0.9735,0.9738 -0.97339,-0.97359 z"
id="path4747"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -958.32118,402.15653 -0.9695,-0.96964 0.9695,-0.96961 0.9695,-0.96964 4.2481,0 4.24795,0 0.9695,0.96964 0.9696,0.96961 -0.9696,0.96964 -0.9695,0.96964 -4.24795,0 -4.2481,0 -0.9695,-0.96964 z"
id="path4737"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -945.31583,402.15653 -0.9695,-0.96964 0.9695,-0.96961 0.9696,-0.96964 4.248,0 4.248,0 0.9695,0.96964 0.96951,0.96961 -0.96951,0.96964 -0.9695,0.96964 -4.248,0 -4.248,0 -0.9696,-0.96964 z"
id="path4735"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -960.58758,399.89017 -0.9734,-0.97353 0,-7.48741 0,-7.48737 0.9734,-0.97384 0.9734,-0.97384 0.9735,0.9735 0.9736,0.9735 0,7.4955 0,7.49553 -0.9658,0.96575 c -0.5312,0.53114 -0.9693,0.96571 -0.9735,0.96571 0,0 -0.4458,-0.43807 -0.9812,-0.9735 z"
id="path4733"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -934.56913,399.89817 -0.9657,-0.96584 0,-7.49544 0,-7.4954 0.9736,-0.9735 0.9736,-0.97351 0.9733,0.97384 0.9734,0.97384 0,7.48747 0,7.4875 -0.9735,0.97344 c -0.53539,0.53537 -0.97699,0.97341 -0.98119,0.97341 -0.01,0 -0.44231,-0.43461 -0.9735,-0.96581 z"
id="path4729"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -941.01023,393.45965 -3.2051,-5.34195 0,-2.02266 0,-2.02264 0.9134,0 0.9135,0 3.2036,5.33941 3.2037,5.3394 0,2.02518 0,2.02521 -0.912,0 -0.9119,0 -3.2052,-5.34195 z"
id="path4725"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -960.58758,380.38988 -0.9734,-0.97384 0,-7.48747 0,-7.4875 0.9773,-0.97724 0.9774,-0.97724 0.9696,0.96955 0.9696,0.96955 0,7.4955 0,7.49553 -0.9736,0.9735 -0.9735,0.9735 -0.9734,-0.97384 z"
id="path4719"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -934.56133,380.38988 -0.9735,-0.97359 0,-7.49544 0,-7.49541 0.9696,-0.96954 0.9697,-0.96955 0.9773,0.97724 0.9773,0.97724 0,7.48753 0,7.4875 -0.9735,0.97381 -0.97339,0.9738 -0.9735,-0.97359 z"
id="path4715"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -958.32118,363.14038 -0.9695,-0.96961 0.9695,-0.96964 0.9695,-0.96964 4.2481,0 4.24795,0 0.9695,0.96964 0.9696,0.96964 -0.9696,0.96961 -0.9695,0.96964 -4.24795,0 -4.2481,0 -0.9695,-0.96964 z"
id="path4709"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -945.31583,363.14038 -0.9695,-0.96961 0.9695,-0.96964 0.9696,-0.96964 4.248,0 4.248,0 0.9695,0.96964 0.96951,0.96964 -0.96951,0.96961 -0.9695,0.96964 -4.248,0 -4.248,0 -0.9696,-0.96964 z"
id="path4610-4-6"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -890.43773,402.15653 -0.9695,-0.96964 0.9695,-0.96961 0.9695,-0.96964 4.2481,0 4.248,0 0.96951,0.96964 0.9696,0.96961 -0.9696,0.96964 -0.96951,0.96964 -4.248,0 -4.2481,0 -0.9695,-0.96964 z"
id="path4801"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -877.43233,402.15653 -0.9695,-0.96964 0.9695,-0.96961 0.9696,-0.96964 4.248,0 4.248,0 0.96951,0.96964 0.9695,0.96961 -0.9695,0.96964 -0.96951,0.96964 -4.248,0 -4.248,0 -0.9696,-0.96964 z"
id="path4799"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -892.70413,399.89017 -0.9734,-0.97353 0,-7.48741 0,-7.48737 0.9734,-0.97384 0.9734,-0.97384 0.9735,0.9735 0.9736,0.9735 0,7.4955 0,7.49553 -0.9658,0.96575 c -0.5312,0.53114 -0.9693,0.96571 -0.9735,0.96571 0,0 -0.4458,-0.43807 -0.9812,-0.9735 z"
id="path4797"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -890.44163,382.65253 -0.9734,-0.97354 0.9735,-0.9734 0.9735,-0.97344 4.2479,0 4.248,0 0.9734,0.97353 0.9734,0.9735 -0.9735,0.97344 -0.9735,0.97344 -4.2479,0 -4.248,0 -0.9734,-0.97353 z"
id="path4787"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -892.70413,380.38988 -0.9734,-0.97384 0,-7.48747 0,-7.4875 0.9773,-0.97724 0.9774,-0.97724 0.9696,0.96955 0.9696,0.96955 0,7.4955 0,7.49553 -0.9736,0.9735 -0.9735,0.9735 -0.9734,-0.97384 z"
id="path4783"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -890.43773,363.14038 -0.9695,-0.96961 0.9695,-0.96964 0.9695,-0.96964 4.2481,0 4.248,0 0.96951,0.96964 0.9696,0.96964 -0.9696,0.96961 -0.96951,0.96964 -4.248,0 -4.2481,0 -0.9695,-0.96964 z"
id="path4773"
inkscape:connector-curvature="0" />
<path
style="fill:#ff0000;fill-opacity:1"
d="m -877.43233,363.14038 -0.9695,-0.96961 0.9695,-0.96964 0.9696,-0.96964 4.248,0 4.248,0 0.96951,0.96964 0.9695,0.96964 -0.9695,0.96961 -0.96951,0.96964 -4.248,0 -4.248,0 -0.9696,-0.96964 z"
id="path4610-1-5"
inkscape:connector-curvature="0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 9.2 KiB

View File

@@ -1,95 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="31.177315mm"
height="14.907915mm"
viewBox="0 0 110.4708 52.823321"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="segments_template.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="12.310946"
inkscape:cx="55.235392"
inkscape:cy="26.411669"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
showguides="true"
inkscape:guide-bbox="true"
inkscape:snap-bbox="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:object-paths="false"
inkscape:object-nodes="true"
inkscape:window-width="1920"
inkscape:window-height="1144"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(967.89459,-355.26718)">
<rect
style="opacity:1;fill:#000000;fill-opacity:1"
id="rect4658"
width="110.4708"
height="52.823322"
x="-967.89459"
y="355.26718"
ry="2.2743988" />
<g
id="g4660"
transform="translate(0.78135242,3.819203)">
<path
inkscape:connector-curvature="0"
id="path4610-2"
d="m -925.16078,398.33733 -0.9696,-0.96964 0.9696,-0.96961 0.9695,-0.96964 4.248,0 4.248,0 0.9696,0.96964 0.9695,0.96961 -0.9695,0.96964 -0.9696,0.96964 -4.248,0 -4.248,0 -0.9695,-0.96964 z m 13.0054,0 -0.9696,-0.96964 0.9696,-0.96961 0.9695,-0.96964 4.248,0 4.2481,0 0.9695,0.96964 0.9695,0.96961 -0.9695,0.96964 -0.9695,0.96964 -4.2481,0 -4.248,0 -0.9695,-0.96964 z m -15.2718,-2.26636 -0.9734,-0.97353 0,-7.48741 0,-7.48737 0.9733,-0.97384 0.9734,-0.97384 0.9736,0.9735 0.9736,0.9735 0,7.4955 0,7.49553 -0.9658,0.96575 c -0.5313,0.53114 -0.9693,0.96571 -0.9736,0.96571 0,0 -0.4457,-0.43807 -0.9811,-0.9735 z m 13.0131,0.008 -0.9657,-0.96584 0,-7.50313 0,-7.5031 0.9696,-0.96955 0.9696,-0.96954 0.9697,0.96954 0.9696,0.96955 0,7.50319 0,7.50322 -0.9658,0.96575 c -0.5312,0.53114 -0.9693,0.96572 -0.9736,0.96572 -0.01,0 -0.4422,-0.43461 -0.9734,-0.96581 z m 13.0054,0 -0.9657,-0.96584 0,-7.49544 0,-7.4954 0.9735,-0.9735 0.9736,-0.97351 0.9734,0.97384 0.9734,0.97384 0,7.48747 0,7.4875 -0.9735,0.97344 c -0.5355,0.53537 -0.977,0.97341 -0.9813,0.97341 -0.01,0 -0.4422,-0.43461 -0.9734,-0.96581 z m -22.6517,-3.12178 0,-2.02518 3.2037,-5.3394 3.2036,-5.33941 0.9135,0 0.9134,0 0,2.02331 0,2.02331 -3.2051,5.34097 -3.2052,5.34093 -0.9119,0 -0.912,0 0,-2.0252 z m 16.2106,-3.31674 -3.2052,-5.34195 0,-2.02266 0,-2.02264 0.9135,0 0.9135,0 3.2036,5.33941 3.2036,5.3394 0,2.02518 0,2.02521 -0.9119,0 -0.91189,0 -3.2052,-5.34195 z m -17.3149,-10.80712 -0.9735,-0.97354 0.9736,-0.9734 0.9735,-0.97344 4.2479,0 4.2479,0 0.9735,0.97353 0.9734,0.9735 -0.9735,0.97344 -0.9735,0.97344 -4.248,0 -4.2479,0 -0.9734,-0.97353 z m 13.0054,0 -0.9735,-0.97354 0.9736,-0.9734 0.9735,-0.97344 4.2479,0 4.248,0 0.9734,0.97353 0.9734,0.9735 -0.9735,0.97344 -0.9735,0.97344 -4.248,0 -4.2479,0 -0.9734,-0.97353 z m -15.268,-2.26265 -0.9733,-0.97384 0,-7.48747 0,-7.4875 0.9773,-0.97724 0.9773,-0.97724 0.9697,0.96955 0.9696,0.96955 0,7.4955 0,7.49553 -0.9736,0.9735 -0.9736,0.9735 -0.9734,-0.97384 z m 13.0132,0.008 -0.9657,-0.96584 0,-7.5031 0,-7.50312 0.9696,-0.96955 0.9696,-0.96955 0.9697,0.96955 0.9696,0.96955 0,7.50322 0,7.50319 -0.9658,0.96574 c -0.5312,0.53114 -0.9693,0.96575 -0.9736,0.96575 -0.01,0 -0.4422,-0.43464 -0.9734,-0.96584 z m 13.0132,-0.008 -0.9735,-0.97359 0,-7.49544 0,-7.49541 0.9696,-0.96954 0.9696,-0.96955 0.9774,0.97724 0.9773,0.97724 0,7.48753 0,7.4875 -0.9735,0.97381 -0.9735,0.9738 -0.97339,-0.97359 z m -19.4558,-6.44373 -3.2037,-5.33941 0,-2.02517 0,-2.02521 0.912,0 0.9119,0 3.2052,5.34054 3.2051,5.34057 0,2.02343 0,2.02346 -0.9134,0 -0.9135,0 -3.2036,-5.3394 z m 9.8017,3.31659 0,-2.02282 3.2052,-5.3417 3.2052,-5.34171 0.9119,-6e-5 0.9119,-6e-5 0,2.02518 0,2.02521 -3.2036,5.3394 -3.2036,5.33941 -0.9135,0 -0.9135,0 0,-2.02282 z m -14.1058,-14.12236 -0.9696,-0.96961 0.9696,-0.96964 0.9695,-0.96964 4.248,0 4.248,0 0.9696,0.96964 0.9695,0.96964 -0.9695,0.96961 -0.9696,0.96964 -4.248,0 -4.248,0 -0.9695,-0.96964 z m 13.0054,0 -0.9696,-0.96961 0.9696,-0.96964 0.9695,-0.96964 4.248,0 4.2481,0 0.9695,0.96964 0.9695,0.96964 -0.9695,0.96961 -0.9695,0.96964 -4.2481,0 -4.248,0 -0.9695,-0.96964 z"
style="fill:#ff0000;fill-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path4610-4-6"
d="m -959.10253,398.33733 -0.9695,-0.96964 0.9695,-0.96961 0.9695,-0.96964 4.2481,0 4.24795,0 0.9695,0.96964 0.9696,0.96961 -0.9696,0.96964 -0.9695,0.96964 -4.24795,0 -4.2481,0 -0.9695,-0.96964 z m 13.00535,0 -0.9695,-0.96964 0.9695,-0.96961 0.9696,-0.96964 4.248,0 4.248,0 0.9695,0.96964 0.96951,0.96961 -0.96951,0.96964 -0.9695,0.96964 -4.248,0 -4.248,0 -0.9696,-0.96964 z m -15.27175,-2.26636 -0.9734,-0.97353 0,-7.48741 0,-7.48737 0.9734,-0.97384 0.9734,-0.97384 0.9735,0.9735 0.9736,0.9735 0,7.4955 0,7.49553 -0.9658,0.96575 c -0.5312,0.53114 -0.9693,0.96571 -0.9735,0.96571 0,0 -0.4458,-0.43807 -0.9812,-0.9735 z m 13.01305,0.008 -0.9657,-0.96584 0,-7.50313 0,-7.5031 0.9696,-0.96955 0.9696,-0.96954 0.9697,0.96954 0.9696,0.96955 0,7.50319 0,7.50322 -0.9658,0.96575 c -0.5312,0.53114 -0.96929,0.96572 -0.97349,0.96572 -0.01,0 -0.44231,-0.43461 -0.9735,-0.96581 z m 13.0054,0 -0.9657,-0.96584 0,-7.49544 0,-7.4954 0.9736,-0.9735 0.9736,-0.97351 0.9733,0.97384 0.9734,0.97384 0,7.48747 0,7.4875 -0.9735,0.97344 c -0.53539,0.53537 -0.97699,0.97341 -0.98119,0.97341 -0.01,0 -0.44231,-0.43461 -0.9735,-0.96581 z m -22.65155,-3.12178 0,-2.02518 3.2036,-5.3394 3.20355,-5.33941 0.9135,0 0.9135,0 0,2.02331 0,2.02331 -3.20515,5.34097 -3.2052,5.34093 -0.9119,0 -0.9119,0 0,-2.0252 z m 16.21045,-3.31674 -3.2051,-5.34195 0,-2.02266 0,-2.02264 0.9134,0 0.9135,0 3.2036,5.33941 3.2037,5.3394 0,2.02518 0,2.02521 -0.912,0 -0.9119,0 -3.2052,-5.34195 z m -17.31485,-10.80712 -0.9734,-0.97354 0.9735,-0.9734 0.9735,-0.97344 4.2479,0 4.24795,0 0.9734,0.97353 0.9734,0.9735 -0.9735,0.97344 -0.9735,0.97344 -4.24785,0 -4.248,0 -0.9734,-0.97353 z m 13.00535,0 -0.9734,-0.97354 0.9735,-0.9734 0.9735,-0.97344 4.248,0 4.2479,0 0.9734,0.97353 0.9734,0.9735 -0.9735,0.97344 -0.9735,0.97344 -4.2479,0 -4.2479,0 -0.97349,-0.97353 z m -15.26785,-2.26265 -0.9734,-0.97384 0,-7.48747 0,-7.4875 0.9773,-0.97724 0.9774,-0.97724 0.9696,0.96955 0.9696,0.96955 0,7.4955 0,7.49553 -0.9736,0.9735 -0.9735,0.9735 -0.9734,-0.97384 z m 13.01305,0.008 -0.9657,-0.96584 0,-7.5031 0,-7.50312 0.9696,-0.96955 0.9696,-0.96955 0.9697,0.96955 0.9696,0.96955 0,7.50322 0,7.50319 -0.9658,0.96574 c -0.5312,0.53114 -0.96929,0.96575 -0.97349,0.96575 -0.01,0 -0.44231,-0.43464 -0.9735,-0.96584 z m 13.0132,-0.008 -0.9735,-0.97359 0,-7.49544 0,-7.49541 0.9696,-0.96954 0.9697,-0.96955 0.9773,0.97724 0.9773,0.97724 0,7.48753 0,7.4875 -0.9735,0.97381 -0.97339,0.9738 -0.9735,-0.97359 z m -19.45575,-6.44373 -3.2036,-5.33941 0,-2.02517 0,-2.02521 0.9119,0 0.9119,0 3.2052,5.34054 3.20515,5.34057 0,2.02343 0,2.02346 -0.9135,0 -0.9135,0 -3.20355,-5.3394 z m 9.80175,3.31659 0,-2.02282 3.2051,-5.3417 3.2052,-5.34171 0.9119,-6e-5 0.912,-6e-5 0,2.02518 0,2.02521 -3.2037,5.3394 -3.2036,5.33941 -0.9135,0 -0.9134,0 0,-2.02282 z m -14.10585,-14.12236 -0.9695,-0.96961 0.9695,-0.96964 0.9695,-0.96964 4.2481,0 4.24795,0 0.9695,0.96964 0.9696,0.96964 -0.9696,0.96961 -0.9695,0.96964 -4.24795,0 -4.2481,0 -0.9695,-0.96964 z m 13.00535,0 -0.9695,-0.96961 0.9695,-0.96964 0.9696,-0.96964 4.248,0 4.248,0 0.9695,0.96964 0.96951,0.96964 -0.96951,0.96961 -0.9695,0.96964 -4.248,0 -4.248,0 -0.9696,-0.96964 z"
style="fill:#ff0000;fill-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path4610-1-5"
d="m -891.21908,398.33733 -0.9695,-0.96964 0.9695,-0.96961 0.9695,-0.96964 4.2481,0 4.248,0 0.96951,0.96964 0.9696,0.96961 -0.9696,0.96964 -0.96951,0.96964 -4.248,0 -4.2481,0 -0.9695,-0.96964 z m 13.0054,0 -0.9695,-0.96964 0.9695,-0.96961 0.9696,-0.96964 4.248,0 4.248,0 0.96951,0.96964 0.9695,0.96961 -0.9695,0.96964 -0.96951,0.96964 -4.248,0 -4.248,0 -0.9696,-0.96964 z m -15.2718,-2.26636 -0.9734,-0.97353 0,-7.48741 0,-7.48737 0.9734,-0.97384 0.9734,-0.97384 0.9735,0.9735 0.9736,0.9735 0,7.4955 0,7.49553 -0.9658,0.96575 c -0.5312,0.53114 -0.9693,0.96571 -0.9735,0.96571 0,0 -0.4458,-0.43807 -0.9812,-0.9735 z m 13.0131,0.008 -0.9657,-0.96584 0,-7.50313 0,-7.5031 0.9696,-0.96955 0.9696,-0.96954 0.9697,0.96954 0.9696,0.96955 0,7.50319 0,7.50322 -0.96579,0.96575 c -0.53121,0.53114 -0.9693,0.96572 -0.9735,0.96572 -0.01,0 -0.4423,-0.43461 -0.9735,-0.96581 z m 13.0054,0 -0.9657,-0.96584 0,-7.49544 0,-7.4954 0.9736,-0.9735 0.9736,-0.97351 0.9733,0.97384 0.9734,0.97384 0,7.48747 0,7.4875 -0.97349,0.97344 c -0.5354,0.53537 -0.977,0.97341 -0.9812,0.97341 -0.01,0 -0.4423,-0.43461 -0.9735,-0.96581 z m -22.6516,-3.12178 0,-2.02518 3.2036,-5.3394 3.2036,-5.33941 0.9135,0 0.9135,0 0,2.02331 0,2.02331 -3.2052,5.34097 -3.2052,5.34093 -0.91189,0 -0.9119,0 0,-2.0252 z m 16.2105,-3.31674 -3.2051,-5.34195 0,-2.02266 0,-2.02264 0.9134,0 0.9135,0 3.2036,5.33941 3.2037,5.3394 0,2.02518 0,2.02521 -0.912,0 -0.9119,0 -3.20519,-5.34195 z m -17.3149,-10.80712 -0.9734,-0.97354 0.9735,-0.9734 0.9735,-0.97344 4.2479,0 4.248,0 0.9734,0.97353 0.9734,0.9735 -0.9735,0.97344 -0.9735,0.97344 -4.2479,0 -4.248,0 -0.9734,-0.97353 z m 13.0054,0 -0.9734,-0.97354 0.9735,-0.9734 0.9735,-0.97344 4.248,0 4.2479,0 0.9734,0.97353 0.9734,0.9735 -0.9735,0.97344 -0.9735,0.97344 -4.2479,0 -4.2479,0 -0.97349,-0.97353 z m -15.2679,-2.26265 -0.9734,-0.97384 0,-7.48747 0,-7.4875 0.9773,-0.97724 0.9774,-0.97724 0.9696,0.96955 0.9696,0.96955 0,7.4955 0,7.49553 -0.9736,0.9735 -0.9735,0.9735 -0.9734,-0.97384 z m 13.0131,0.008 -0.9657,-0.96584 0,-7.5031 0,-7.50312 0.9696,-0.96955 0.9696,-0.96955 0.9697,0.96955 0.9696,0.96955 0,7.50322 0,7.50319 -0.96579,0.96574 c -0.53121,0.53114 -0.9693,0.96575 -0.9735,0.96575 -0.01,0 -0.4423,-0.43464 -0.9735,-0.96584 z m 13.0132,-0.008 -0.9735,-0.97359 0,-7.49544 0,-7.49541 0.9696,-0.96954 0.9697,-0.96955 0.9773,0.97724 0.9773,0.97724 0,7.48753 0,7.4875 -0.97349,0.97381 -0.9734,0.9738 -0.9735,-0.97359 z m -19.4558,-6.44373 -3.2036,-5.33941 0,-2.02517 0,-2.02521 0.9119,0 0.9119,0 3.2052,5.34054 3.2052,5.34057 0,2.02343 0,2.02346 -0.9135,0 -0.9135,0 -3.2036,-5.3394 z m 9.8018,3.31659 0,-2.02282 3.2051,-5.3417 3.2052,-5.34171 0.9119,-6e-5 0.912,-6e-5 0,2.02518 0,2.02521 -3.2037,5.3394 -3.2036,5.33941 -0.9135,0 -0.9134,0 0,-2.02282 z m -14.1059,-14.12236 -0.9695,-0.96961 0.9695,-0.96964 0.9695,-0.96964 4.2481,0 4.248,0 0.96951,0.96964 0.9696,0.96964 -0.9696,0.96961 -0.96951,0.96964 -4.248,0 -4.2481,0 -0.9695,-0.96964 z m 13.0054,0 -0.9695,-0.96961 0.9695,-0.96964 0.9696,-0.96964 4.248,0 4.248,0 0.96951,0.96964 0.9695,0.96964 -0.9695,0.96961 -0.96951,0.96964 -4.248,0 -4.248,0 -0.9696,-0.96964 z"
style="fill:#ff0000;fill-opacity:1" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -1,13 +1,21 @@
#!/usr/bin/env node #!/usr/bin/env node
const uhk = require('./uhk'); const uhk = require('./uhk');
const device = uhk.getUhkDevice();
const eepromTransferType = process.argv[2]; (async function() {
const eepromTransfer = uhk.eepromTransfer[eepromTransferType]; const operationArg = process.argv[2];
const operation = uhk.eepromOperations[operationArg];
if (operation === undefined) {
console.error(`Invalid operation: Gotta provide one of ${Object.keys(uhk.eepromOperations).join(', ')}`);
process.exit(1);
}
if (eepromTransfer === undefined) { const bufferIdArg = process.argv[3];
console.error(`Gotta provide one of ${Object.keys(uhk.eepromTransfer).join(', ')}`); const bufferId = uhk.configBufferIds[bufferIdArg]
process.exit(1); if (bufferId === undefined) {
} console.error(`Invalid bufferId: Gotta provide one of ${Object.keys(uhk.configBufferIds).join(', ')}`);
process.exit(1);
// const buffer = await uhk.writeDevice(device, [uhk.usbCommands.launchEepromTransfer, eepromTransfer.operation, eepromTransfer.configBuffer]); }
const buffer = await uhk.launchEepromTransfer(device, operation, bufferId);
})();

File diff suppressed because it is too large Load Diff

View File

@@ -19,6 +19,12 @@ let config = {
'sprite': 'compiled_sprite.svg', 'sprite': 'compiled_sprite.svg',
bust: false bust: false
} }
},
svg: { // General options for created SVG files
namespaceIDs: true,
rootAttributes: {
"xmlns:xlink":"http://www.w3.org/1999/xlink"
}
} }
}; };