Compare commits
65 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f3bd83af03 | ||
|
|
0b3fca63b7 | ||
|
|
cbd4460df0 | ||
|
|
b941bd9a75 | ||
|
|
439b84affc | ||
|
|
66d5302e6f | ||
|
|
9e2e2b9c5c | ||
|
|
aa243ac7b0 | ||
|
|
eb421e0681 | ||
|
|
63aae8f578 | ||
|
|
e577454a31 | ||
|
|
e802bb0052 | ||
|
|
b98e5df20a | ||
|
|
7332105edb | ||
|
|
6a4feaf18d | ||
|
|
ee637d7958 | ||
|
|
8d161ce8ff | ||
|
|
8010bd8195 | ||
|
|
059f1d5505 | ||
|
|
123cab5724 | ||
|
|
c16365a0e5 | ||
|
|
a21d278c0c | ||
|
|
0466916be1 | ||
|
|
9a845d8f6a | ||
|
|
9ae1673499 | ||
|
|
2d5a5e7aef | ||
|
|
3e4d439852 | ||
|
|
aba0b09109 | ||
|
|
af608ee17d | ||
|
|
df817e86d6 | ||
|
|
a7d3b62512 | ||
|
|
b41f14192a | ||
|
|
475ec71983 | ||
|
|
b5cff2fa93 | ||
|
|
80e8c014ec | ||
|
|
67d42f666c | ||
|
|
fa32f95438 | ||
|
|
06878dd56a | ||
|
|
374f6a3e6e | ||
|
|
0b9c804a3d | ||
|
|
365a459d61 | ||
|
|
cec891a2c0 | ||
|
|
8eb8aa3032 | ||
|
|
38184e7968 | ||
|
|
f6092ea195 | ||
|
|
ac7d66e338 | ||
|
|
b82a1da92a | ||
|
|
b8859f7b64 | ||
|
|
a04fa67446 | ||
|
|
ac89aff018 | ||
|
|
e7cf8dc966 | ||
|
|
d0102f5bdb | ||
|
|
eb0daadf98 | ||
|
|
49d6ca173d | ||
|
|
a3eb6a6b7e | ||
|
|
144ed57b20 | ||
|
|
6086ddabf0 | ||
|
|
84f378a276 | ||
|
|
648e8d5f2c | ||
|
|
15df8d7129 | ||
|
|
cfc0af9655 | ||
|
|
f02e3181a6 | ||
|
|
3d59bcf97e | ||
|
|
5e4fc983fb | ||
|
|
32d9635b34 |
61
CHANGELOG.md
@@ -6,12 +6,71 @@ 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.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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
- Uncheck the "Remap on all keymaps" and "Remap on all layers" checkboxes of the key action popover by default.
|
||||||
|
- Bind left and right Shift on the Mouse layer of all keymaps in the default configuration.
|
||||||
|
- Make ng2-select2 widgets faster.
|
||||||
|
- Add note to the LED brightness page saying that current UHK versions are not backlit.
|
||||||
|
- Fix the padding of the secondary role tooltip.
|
||||||
|
- Remove the redundant scrollbar from the LED brightness page.
|
||||||
|
|
||||||
|
## [1.2.7] - 2018-07-26
|
||||||
|
|
||||||
|
Firmware: 8.4.0 [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.4.0)] | Device Protocol: 4.4.0 | User Config: 4.0.1 | Hardware Config: 1.0.0
|
||||||
|
|
||||||
|
- Fix Agent startup exception on Linux by upgrading Electron builder.
|
||||||
|
- Change the shortcut which enables the USB stack test code, so that it can be triggered with the default Mac US keymap.
|
||||||
|
|
||||||
|
## [1.2.6] - 2018-07-26
|
||||||
|
|
||||||
|
Firmware: 8.**4.0** [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.4.0)] | Device Protocol: 4.**4.0** | User Config: 4.0.1 | Hardware Config: 1.0.0
|
||||||
|
|
||||||
|
- Replace the Linux blhost binary with a statically compiled version that doesn't use special instructions and shouldn't segfault.
|
||||||
|
- Keep the current layer when changing keymaps.
|
||||||
|
- Fix the sleep key of Mac keymaps.
|
||||||
|
- Add help page.
|
||||||
|
- Add "save to keyboard" and "remap key" shortcuts.
|
||||||
|
- Build only AppImages for Linux.
|
||||||
|
- Replace ng2-select2 widgets with ngx-select-ex that always shows up in the correct position.
|
||||||
|
- Improve the phrasing of the firmware update error message.
|
||||||
|
- Tweak unsupported Windows firmware update notification.
|
||||||
|
- Hide the Settings menu until auto update is implemented.
|
||||||
|
- Don't scroll when the macro tab of the key action popover gets selected.
|
||||||
|
- Add keyboard shortcut for enabling the USB stack test mode of the firmware. `DEVICEPROTOCOL:MINOR`
|
||||||
|
- Tone down the color of the separator line.
|
||||||
|
|
||||||
## [1.2.5] - 2018-06-26
|
## [1.2.5] - 2018-06-26
|
||||||
|
|
||||||
Firmware: 8.2.5 [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.2.5)] | Device Protocol: 4.3.1 | User Config: 4.0.1 | Hardware Config: 1.0.0
|
Firmware: 8.2.5 [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.2.5)] | Device Protocol: 4.3.1 | User Config: 4.0.1 | Hardware Config: 1.0.0
|
||||||
|
|
||||||
- When remapping a switch keymap action on all keymaps, don't set it on its own keymap.
|
- When remapping a switch keymap action on all keymaps, don't set it on its own keymap.
|
||||||
- Make the key action popver always contain the action of the current key, even after cancelled.
|
- Make the key action popover always contain the action of the current key, even after cancelled.
|
||||||
- Include the firmware version to be updated to the firmware update log.
|
- Include the firmware version to be updated to the firmware update log.
|
||||||
- Update the Agent icon of the side menu and the about page.
|
- Update the Agent icon of the side menu and the about page.
|
||||||
- When remapping a key, only flash the affected key instead of all keys.
|
- When remapping a key, only flash the affected key instead of all keys.
|
||||||
|
|||||||
13265
package-lock.json
generated
35
package.json
@@ -3,9 +3,9 @@
|
|||||||
"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.5",
|
"version": "1.2.10",
|
||||||
"firmwareVersion": "8.2.5",
|
"firmwareVersion": "8.2.5",
|
||||||
"deviceProtocolVersion": "4.3.1",
|
"deviceProtocolVersion": "4.4.0",
|
||||||
"userConfigVersion": "4.0.1",
|
"userConfigVersion": "4.0.1",
|
||||||
"hardwareConfigVersion": "1.0.0",
|
"hardwareConfigVersion": "1.0.0",
|
||||||
"description": "Agent is the configuration application of the Ultimate Hacking Keyboard.",
|
"description": "Agent is the configuration application of the Ultimate Hacking Keyboard.",
|
||||||
@@ -15,14 +15,14 @@
|
|||||||
},
|
},
|
||||||
"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",
|
||||||
"@types/electron-settings": "3.0.0",
|
"@types/electron-settings": "3.0.0",
|
||||||
"@types/fs-extra": "5.0.1",
|
"@types/fs-extra": "5.0.1",
|
||||||
"@types/jasmine": "2.6.0",
|
"@types/jasmine": "2.8.8",
|
||||||
"@types/jquery": "3.3.1",
|
"@types/jquery": "3.3.1",
|
||||||
"@types/jsonfile": "4.0.1",
|
"@types/jsonfile": "4.0.1",
|
||||||
"@types/lodash-es": "4.17.0",
|
"@types/lodash-es": "4.17.0",
|
||||||
@@ -38,37 +38,41 @@
|
|||||||
"core-js": "2.4.1",
|
"core-js": "2.4.1",
|
||||||
"cross-env": "5.0.5",
|
"cross-env": "5.0.5",
|
||||||
"decompress": "4.2.0",
|
"decompress": "4.2.0",
|
||||||
"decompress-tarbz2": "^4.1.1",
|
"decompress-tarbz2": "4.1.1",
|
||||||
"devtron": "1.4.0",
|
"devtron": "1.4.0",
|
||||||
"electron": "1.8.4",
|
"electron": "1.8.7",
|
||||||
"electron-builder": "20.8.1",
|
"electron-builder": "20.8.1",
|
||||||
"electron-debug": "1.5.0",
|
"electron-debug": "1.5.0",
|
||||||
"electron-devtools-installer": "2.2.3",
|
"electron-devtools-installer": "2.2.3",
|
||||||
"electron-log": "2.2.14",
|
"electron-log": "2.2.16",
|
||||||
"electron-rebuild": "1.7.3",
|
"electron-rebuild": "1.8.2",
|
||||||
"electron-settings": "3.1.4",
|
"electron-settings": "3.1.4",
|
||||||
"electron-updater": "2.21.4",
|
"electron-updater": "2.21.4",
|
||||||
"exports-loader": "0.6.3",
|
"exports-loader": "0.6.3",
|
||||||
"file-loader": "0.10.0",
|
"file-loader": "0.10.0",
|
||||||
"fs-extra": "5.0.0",
|
"fs-extra": "5.0.0",
|
||||||
"gh-pages": "1.1.0",
|
"gh-pages": "1.1.0",
|
||||||
|
"jasmine": "2.8.0",
|
||||||
|
"jasmine-core": "2.8.0",
|
||||||
|
"jasmine-node": "2.0.1",
|
||||||
|
"jasmine-ts": "0.2.1",
|
||||||
"jsonfile": "4.0.0",
|
"jsonfile": "4.0.0",
|
||||||
"lerna": "2.9.0",
|
"lerna": "3.1.4",
|
||||||
"lodash-es": "4.17.4",
|
"lodash-es": "4.17.4",
|
||||||
"mkdirp": "0.5.1",
|
"mkdirp": "0.5.1",
|
||||||
"node-hid": "0.5.7",
|
"node-hid": "0.5.7",
|
||||||
"npm-run-all": "4.0.2",
|
"npm-run-all": "4.0.2",
|
||||||
"pre-commit": "1.2.2",
|
"pre-commit": "1.2.2",
|
||||||
"request": "2.83.0",
|
"request": "2.88.0",
|
||||||
"rimraf": "2.6.1",
|
"rimraf": "2.6.1",
|
||||||
"standard-version": "4.2.0",
|
"standard-version": "4.2.0",
|
||||||
"stylelint": "7.13.0",
|
"stylelint": "9.5.0",
|
||||||
"svg-sprite": "1.3.7",
|
"svg-sprite": "1.4.0",
|
||||||
"ts-loader": "2.3.1",
|
"ts-loader": "2.3.1",
|
||||||
"ts-node": "3.0.4",
|
"ts-node": "7.0.1",
|
||||||
"tslint": "5.9.1",
|
"tslint": "5.9.1",
|
||||||
"typescript": "2.6.2",
|
"typescript": "2.6.2",
|
||||||
"webpack": "3.10.0"
|
"webpack": "3.12.0"
|
||||||
},
|
},
|
||||||
"pre-commit": [
|
"pre-commit": [
|
||||||
"precommit-msg"
|
"precommit-msg"
|
||||||
@@ -88,6 +92,7 @@
|
|||||||
"lint:ts:test-serializer": "tslint --project ./packages/test-serializer/tsconfig.json",
|
"lint:ts:test-serializer": "tslint --project ./packages/test-serializer/tsconfig.json",
|
||||||
"lint:ts:uhk-usb": "tslint --project ./packages/uhk-usb/tsconfig.json",
|
"lint:ts:uhk-usb": "tslint --project ./packages/uhk-usb/tsconfig.json",
|
||||||
"lint:style": "stylelint \"packages/uhk-agent/src/**/*.scss\" \"packages/uhk-web/src/**/*.scss\" --syntax scss",
|
"lint:style": "stylelint \"packages/uhk-agent/src/**/*.scss\" \"packages/uhk-web/src/**/*.scss\" --syntax scss",
|
||||||
|
"e2e": "lerna run e2e --scope uhk-web",
|
||||||
"prebuild": "check-node-version --package",
|
"prebuild": "check-node-version --package",
|
||||||
"build": "run-s build:common build:usb build:web build:electron",
|
"build": "run-s build:common build:usb build:web build:electron",
|
||||||
"build:web": "lerna exec --scope uhk-web npm run build",
|
"build:web": "lerna exec --scope uhk-web npm run build",
|
||||||
|
|||||||
146
packages/test-serializer/package-lock.json
generated
@@ -201,11 +201,11 @@
|
|||||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
|
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
|
||||||
},
|
},
|
||||||
"gaze": {
|
"gaze": {
|
||||||
"version": "0.5.2",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz",
|
||||||
"integrity": "sha1-QLcJU30k0dRXZ9takIaJ3+aaxE8=",
|
"integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"globule": "0.1.0"
|
"globule": "1.2.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"get-caller-file": {
|
"get-caller-file": {
|
||||||
@@ -219,41 +219,37 @@
|
|||||||
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
|
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
|
||||||
},
|
},
|
||||||
"glob": {
|
"glob": {
|
||||||
"version": "3.1.21",
|
"version": "7.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
|
||||||
"integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=",
|
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"graceful-fs": "1.2.3",
|
"fs.realpath": "1.0.0",
|
||||||
"inherits": "1.0.2",
|
"inflight": "1.0.6",
|
||||||
"minimatch": "0.2.14"
|
"inherits": "2.0.3",
|
||||||
},
|
"minimatch": "3.0.4",
|
||||||
"dependencies": {
|
"once": "1.4.0",
|
||||||
"inherits": {
|
"path-is-absolute": "1.0.1"
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz",
|
|
||||||
"integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js="
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"globule": {
|
"globule": {
|
||||||
"version": "0.1.0",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/globule/-/globule-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz",
|
||||||
"integrity": "sha1-2cjt3h2nnRJaFRt5UzuXhnY0auU=",
|
"integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"glob": "3.1.21",
|
"glob": "7.1.2",
|
||||||
"lodash": "1.0.2",
|
"lodash": "4.17.10",
|
||||||
"minimatch": "0.2.14"
|
"minimatch": "3.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"graceful-fs": {
|
|
||||||
"version": "1.2.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz",
|
|
||||||
"integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q="
|
|
||||||
},
|
|
||||||
"growl": {
|
"growl": {
|
||||||
"version": "1.7.0",
|
"version": "1.10.5",
|
||||||
"resolved": "https://registry.npmjs.org/growl/-/growl-1.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
|
||||||
"integrity": "sha1-3i1mE20ALhErpw8/EMMc98NQsto="
|
"integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA=="
|
||||||
|
},
|
||||||
|
"grunt-exec": {
|
||||||
|
"version": "0.4.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/grunt-exec/-/grunt-exec-0.4.7.tgz",
|
||||||
|
"integrity": "sha1-QAUf+k6wyWV+BTuV6I1ENSocLCU="
|
||||||
},
|
},
|
||||||
"has-flag": {
|
"has-flag": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
@@ -362,31 +358,34 @@
|
|||||||
"integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4="
|
"integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4="
|
||||||
},
|
},
|
||||||
"jasmine-growl-reporter": {
|
"jasmine-growl-reporter": {
|
||||||
"version": "0.2.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/jasmine-growl-reporter/-/jasmine-growl-reporter-0.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/jasmine-growl-reporter/-/jasmine-growl-reporter-1.0.1.tgz",
|
||||||
"integrity": "sha1-1fCje5L2qD/VxkgrgJSVyQqLVf4=",
|
"integrity": "sha512-dh7VjP3l0OLxL9+sw5vK6RrdH4gdHCNkTnUd9orViHDPr7Fe8LsXY+IObWauS2hX5khMFtjKRZCfTcDHKAjm/A==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"growl": "1.7.0"
|
"growl": "1.10.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"jasmine-node": {
|
"jasmine-node": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/jasmine-node/-/jasmine-node-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/jasmine-node/-/jasmine-node-2.0.1.tgz",
|
||||||
"integrity": "sha1-gXUacjJfVJdJCxQYGlUIfxsDcf8=",
|
"integrity": "sha512-1S5Z4Mof5yxwqLIApzyo2pV5WN2kRpTSgICvEo3+rJmKve9P94kolzC9eS0u5cyiT+gxBY2mwOQdxLbkhwKzoA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"coffee-script": "1.7.1",
|
"coffee-script": "1.7.1",
|
||||||
"gaze": "0.5.2",
|
"gaze": "1.1.3",
|
||||||
"jasmine-growl-reporter": "0.2.1",
|
"grunt-exec": "0.4.7",
|
||||||
"minimist": "0.0.8",
|
"jasmine-growl-reporter": "1.0.1",
|
||||||
|
"jasmine-reporters": "git://github.com/larrymyers/jasmine-reporters.git#2c7242dc11c15c2f156169bc704798568b8cb50d",
|
||||||
|
"minimist": "0.0.10",
|
||||||
"mkdirp": "0.3.5",
|
"mkdirp": "0.3.5",
|
||||||
"underscore": "1.6.0",
|
"underscore": "1.6.0",
|
||||||
"walkdir": "0.0.12"
|
"walkdir": "0.0.12",
|
||||||
|
"xml2js": "0.4.19"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "0.0.8",
|
"version": "0.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
|
||||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
|
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8="
|
||||||
},
|
},
|
||||||
"mkdirp": {
|
"mkdirp": {
|
||||||
"version": "0.3.5",
|
"version": "0.3.5",
|
||||||
@@ -395,6 +394,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"jasmine-reporters": {
|
||||||
|
"version": "git://github.com/larrymyers/jasmine-reporters.git#2c7242dc11c15c2f156169bc704798568b8cb50d",
|
||||||
|
"requires": {
|
||||||
|
"mkdirp": "0.3.5"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"mkdirp": {
|
||||||
|
"version": "0.3.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz",
|
||||||
|
"integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"jasmine-ts": {
|
"jasmine-ts": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/jasmine-ts/-/jasmine-ts-0.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/jasmine-ts/-/jasmine-ts-0.2.1.tgz",
|
||||||
@@ -442,14 +454,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "1.0.2",
|
"version": "4.17.10",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
|
||||||
"integrity": "sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE="
|
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg=="
|
||||||
},
|
|
||||||
"lru-cache": {
|
|
||||||
"version": "2.7.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz",
|
|
||||||
"integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI="
|
|
||||||
},
|
},
|
||||||
"make-error": {
|
"make-error": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
@@ -470,12 +477,11 @@
|
|||||||
"integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg="
|
"integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg="
|
||||||
},
|
},
|
||||||
"minimatch": {
|
"minimatch": {
|
||||||
"version": "0.2.14",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||||
"integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=",
|
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"lru-cache": "2.7.3",
|
"brace-expansion": "1.1.8"
|
||||||
"sigmund": "1.0.1"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minimist": {
|
"minimist": {
|
||||||
@@ -633,6 +639,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
|
||||||
"integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE="
|
"integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE="
|
||||||
},
|
},
|
||||||
|
"sax": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
||||||
|
},
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "5.4.1",
|
"version": "5.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
|
||||||
@@ -656,11 +667,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
|
||||||
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
|
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
|
||||||
},
|
},
|
||||||
"sigmund": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
|
|
||||||
"integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA="
|
|
||||||
},
|
|
||||||
"signal-exit": {
|
"signal-exit": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
|
||||||
@@ -854,6 +860,20 @@
|
|||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||||
},
|
},
|
||||||
|
"xml2js": {
|
||||||
|
"version": "0.4.19",
|
||||||
|
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz",
|
||||||
|
"integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==",
|
||||||
|
"requires": {
|
||||||
|
"sax": "1.2.4",
|
||||||
|
"xmlbuilder": "9.0.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"xmlbuilder": {
|
||||||
|
"version": "9.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
|
||||||
|
"integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0="
|
||||||
|
},
|
||||||
"y18n": {
|
"y18n": {
|
||||||
"version": "3.2.1",
|
"version": "3.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
|
||||||
|
|||||||
@@ -14,16 +14,9 @@
|
|||||||
"npm": ">=5.1.0 <6.0.0"
|
"npm": ">=5.1.0 <6.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"uhk-common": "1.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jasmine": "2.6.0",
|
|
||||||
"@types/node": "8.0.30",
|
|
||||||
"jasmine": "2.8.0",
|
|
||||||
"jasmine-core": "2.8.0",
|
|
||||||
"jasmine-node": "2.0.0",
|
|
||||||
"jasmine-ts": "0.2.1",
|
|
||||||
"ts-node": "3.3.0",
|
|
||||||
"uhk-common": "1.0.0"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "jasmine-ts --config=jasmine.json"
|
"test": "jasmine-ts --config=jasmine.json"
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
{
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es6",
|
"target": "es6",
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true
|
||||||
"typeRoots": [
|
|
||||||
"./node_modules/@types"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
255
packages/uhk-agent/package-lock.json
generated
@@ -87,6 +87,15 @@ export class DeviceService {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcMain.on(IpcEvents.device.enableUsbStackTest, (...args: any[]) => {
|
||||||
|
this.queueManager.add({
|
||||||
|
method: this.enableUsbStackTest,
|
||||||
|
bind: this,
|
||||||
|
params: args,
|
||||||
|
asynchronous: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
logService.debug('[DeviceService] init success');
|
logService.debug('[DeviceService] init success');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,6 +233,10 @@ export class DeviceService {
|
|||||||
event.sender.send(IpcEvents.device.updateFirmwareReply, response);
|
event.sender.send(IpcEvents.device.updateFirmwareReply, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async enableUsbStackTest(event: Electron.Event) {
|
||||||
|
await this.device.enableUsbStackTest();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HID API not support device attached and detached event.
|
* HID API not support device attached and detached event.
|
||||||
* This method check the keyboard is attached to the computer or not.
|
* This method check the keyboard is attached to the computer or not.
|
||||||
|
|||||||
@@ -19,16 +19,6 @@
|
|||||||
"coverage": "nyc jasmine-ts --config=jasmine.json"
|
"coverage": "nyc jasmine-ts --config=jasmine.json"
|
||||||
},
|
},
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"devDependencies": {
|
|
||||||
"@types/jasmine": "2.6.0",
|
|
||||||
"@types/node": "8.0.30",
|
|
||||||
"jasmine": "2.8.0",
|
|
||||||
"jasmine-core": "2.8.0",
|
|
||||||
"jasmine-node": "2.0.0",
|
|
||||||
"jasmine-ts": "0.2.1",
|
|
||||||
"nyc": "11.2.1",
|
|
||||||
"ts-node": "3.3.0"
|
|
||||||
},
|
|
||||||
"nyc": {
|
"nyc": {
|
||||||
"extension": [
|
"extension": [
|
||||||
".ts"
|
".ts"
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ export class Device {
|
|||||||
public static readonly updateFirmwareReply = 'device-update-firmware-reply';
|
public static readonly updateFirmwareReply = 'device-update-firmware-reply';
|
||||||
public static readonly startConnectionPoller = 'device-start-connection-poller';
|
public static readonly startConnectionPoller = 'device-start-connection-poller';
|
||||||
public static readonly recoveryDevice = 'device-recovery';
|
public static readonly recoveryDevice = 'device-recovery';
|
||||||
|
public static readonly enableUsbStackTest = 'enable-usb-stack-test';
|
||||||
}
|
}
|
||||||
|
|
||||||
export class IpcEvents {
|
export class IpcEvents {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
"compileOnSave": false,
|
"compileOnSave": false,
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
@@ -9,9 +10,6 @@
|
|||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"typeRoots": [
|
|
||||||
"node_modules/@types"
|
|
||||||
],
|
|
||||||
"lib": [
|
"lib": [
|
||||||
"es2015.iterable",
|
"es2015.iterable",
|
||||||
"dom",
|
"dom",
|
||||||
|
|||||||
149
packages/uhk-usb/package-lock.json
generated
@@ -1,11 +1,14 @@
|
|||||||
{
|
{
|
||||||
"requires": true,
|
"name": "uhk-usb",
|
||||||
|
"version": "1.0.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "8.0.28",
|
"version": "8.0.28",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.0.28.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.0.28.tgz",
|
||||||
"integrity": "sha512-HupkFXEv3O3KSzcr3Ylfajg0kaerBg1DyaZzRBBQfrU3NN1mTBRE7sCveqHwXLS5Yrjvww8qFzkzYQQakG9FuQ=="
|
"integrity": "sha512-HupkFXEv3O3KSzcr3Ylfajg0kaerBg1DyaZzRBBQfrU3NN1mTBRE7sCveqHwXLS5Yrjvww8qFzkzYQQakG9FuQ==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"ansi-regex": {
|
"ansi-regex": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
@@ -22,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": {
|
||||||
@@ -36,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": {
|
||||||
@@ -65,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": {
|
||||||
@@ -88,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": {
|
||||||
@@ -101,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": {
|
||||||
@@ -136,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": {
|
||||||
@@ -179,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": {
|
||||||
@@ -187,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": {
|
||||||
@@ -202,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": {
|
||||||
@@ -223,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": {
|
||||||
@@ -236,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": {
|
||||||
@@ -263,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": {
|
||||||
@@ -272,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": {
|
||||||
@@ -283,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": {
|
||||||
@@ -322,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": {
|
||||||
@@ -332,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": {
|
||||||
@@ -342,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": {
|
||||||
@@ -350,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": {
|
||||||
@@ -363,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": {
|
||||||
@@ -374,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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -385,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": {
|
||||||
@@ -396,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": {
|
||||||
@@ -414,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": {
|
||||||
|
|||||||
@@ -23,7 +23,12 @@ export enum UsbCommand {
|
|||||||
GetDebugBuffer = 0x0b,
|
GetDebugBuffer = 0x0b,
|
||||||
GetAdcValue = 0x0c,
|
GetAdcValue = 0x0c,
|
||||||
SetLedPwmBrightness = 0x0d,
|
SetLedPwmBrightness = 0x0d,
|
||||||
GetModuleProperty = 0x0e
|
GetModuleProperty = 0x0e,
|
||||||
|
GetSlaveI2cErrors = 0x0f,
|
||||||
|
SetI2cBaudRate = 0x10,
|
||||||
|
SwitchKeymap = 0x11,
|
||||||
|
GetVariable = 0x12,
|
||||||
|
SetVariable = 0x13
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum EepromOperation {
|
export enum EepromOperation {
|
||||||
@@ -86,3 +91,10 @@ export enum KbootCommands {
|
|||||||
export enum ModulePropertyId {
|
export enum ModulePropertyId {
|
||||||
protocolVersions = 0
|
protocolVersions = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum UsbVariables {
|
||||||
|
testSwitches = 0,
|
||||||
|
testUsbStack = 1,
|
||||||
|
debounceTimePress = 2,
|
||||||
|
debounceTimeRelease = 3
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ import {
|
|||||||
KbootCommands,
|
KbootCommands,
|
||||||
ModuleSlotToI2cAddress,
|
ModuleSlotToI2cAddress,
|
||||||
ModuleSlotToId,
|
ModuleSlotToId,
|
||||||
UsbCommand
|
UsbCommand,
|
||||||
|
UsbVariables
|
||||||
} from './constants';
|
} from './constants';
|
||||||
import { bufferToString, getTransferData, isUhkDevice, retry, snooze } from './util';
|
import { bufferToString, getTransferData, isUhkDevice, retry, snooze } from './util';
|
||||||
|
|
||||||
@@ -133,6 +134,11 @@ export class UhkHidDevice {
|
|||||||
await this.waitUntilKeyboardBusy();
|
await this.waitUntilKeyboardBusy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async enableUsbStackTest(): Promise<void> {
|
||||||
|
await this.write(new Buffer([UsbCommand.SetVariable, UsbVariables.testUsbStack, 1]));
|
||||||
|
await this.waitUntilKeyboardBusy();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close the communication chanel with UHK Device
|
* Close the communication chanel with UHK Device
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -59,8 +59,9 @@ export class UhkOperations {
|
|||||||
|
|
||||||
const leftModuleBricked = await this.waitForKbootIdle();
|
const leftModuleBricked = await this.waitForKbootIdle();
|
||||||
if (!leftModuleBricked) {
|
if (!leftModuleBricked) {
|
||||||
this.logService.error('[UhkOperations] Couldn\'t connect to the left keyboard half.');
|
const msg = '[UhkOperations] Couldn\'t connect to the left keyboard half.';
|
||||||
return;
|
this.logService.error(msg);
|
||||||
|
throw new Error(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.device.reenumerate(EnumerationModes.Buspal);
|
await this.device.reenumerate(EnumerationModes.Buspal);
|
||||||
|
|||||||
@@ -26,7 +26,6 @@
|
|||||||
],
|
],
|
||||||
"scripts": [
|
"scripts": [
|
||||||
"../node_modules/bootstrap/dist/js/bootstrap.js",
|
"../node_modules/bootstrap/dist/js/bootstrap.js",
|
||||||
"../node_modules/select2/dist/js/select2.full.js",
|
|
||||||
"../node_modules/nouislider/distribute/nouislider.js"
|
"../node_modules/nouislider/distribute/nouislider.js"
|
||||||
],
|
],
|
||||||
"environmentSource": "environments/environment.ts",
|
"environmentSource": "environments/environment.ts",
|
||||||
|
|||||||
1
packages/uhk-web/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
out-tsc/
|
||||||
@@ -7,8 +7,8 @@ describe('web App', () => {
|
|||||||
page = new WebPage();
|
page = new WebPage();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should display welcome message', () => {
|
it('should display default device name', () => {
|
||||||
page.navigateTo();
|
page.navigateTo();
|
||||||
expect(page.getParagraphText()).toEqual('Welcome to app!');
|
expect(page.getDeviceName()).toEqual('My UHK');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ export class WebPage {
|
|||||||
return browser.get('/');
|
return browser.get('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
getParagraphText() {
|
getDeviceName() {
|
||||||
return element(by.css('app-root h1')).getText();
|
return element(by.css('body > main-app > side-menu > ul > li:nth-child(1) > div > auto-grow-input > input'))
|
||||||
|
.getAttribute('value');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10979
packages/uhk-web/package-lock.json
generated
@@ -36,8 +36,8 @@
|
|||||||
"@types/electron-devtools-installer": "2.0.2",
|
"@types/electron-devtools-installer": "2.0.2",
|
||||||
"@types/electron-settings": "3.0.0",
|
"@types/electron-settings": "3.0.0",
|
||||||
"@types/file-saver": "0.0.1",
|
"@types/file-saver": "0.0.1",
|
||||||
"@types/jasmine": "2.5.53",
|
"@types/jasmine": "2.8.8",
|
||||||
"@types/jasminewd2": "2.0.2",
|
"@types/jasminewd2": "2.0.3",
|
||||||
"@types/jquery": "3.2.9",
|
"@types/jquery": "3.2.9",
|
||||||
"@types/usb": "1.1.3",
|
"@types/usb": "1.1.3",
|
||||||
"angular-confirmation-popover": "3.2.0",
|
"angular-confirmation-popover": "3.2.0",
|
||||||
@@ -50,26 +50,25 @@
|
|||||||
"dragula": "3.7.2",
|
"dragula": "3.7.2",
|
||||||
"font-awesome": "4.7.0",
|
"font-awesome": "4.7.0",
|
||||||
"html-webpack-plugin": "^2.29.0",
|
"html-webpack-plugin": "^2.29.0",
|
||||||
"jasmine-core": "2.6.2",
|
"jasmine-core": "3.2.1",
|
||||||
"jasmine-spec-reporter": "4.1.0",
|
"jasmine-spec-reporter": "4.2.1",
|
||||||
"jquery": "3.2.1",
|
"jquery": "3.2.1",
|
||||||
"jsonfile": "3.0.1",
|
"jsonfile": "3.0.1",
|
||||||
"karma": "1.7.0",
|
"karma": "3.0.0",
|
||||||
"karma-chrome-launcher": "2.1.1",
|
"karma-chrome-launcher": "2.2.0",
|
||||||
"karma-coverage-istanbul-reporter": "1.2.1",
|
"karma-coverage-istanbul-reporter": "2.0.1",
|
||||||
"karma-jasmine": "1.1.0",
|
"karma-jasmine": "1.1.2",
|
||||||
"karma-jasmine-html-reporter": "0.2.2",
|
"karma-jasmine-html-reporter": "1.3.1",
|
||||||
"ng2-dragula": "1.5.0",
|
"ng2-dragula": "1.5.0",
|
||||||
"ng2-nouislider": "^1.7.7",
|
"ng2-nouislider": "^1.7.7",
|
||||||
"ng2-select2": "1.0.0-beta.10",
|
|
||||||
"ngx-clipboard": "10.0.0",
|
"ngx-clipboard": "10.0.0",
|
||||||
|
"@ert78gb/ngx-select-ex": "3.7.2",
|
||||||
"ngrx-store-freeze": "0.1.9",
|
"ngrx-store-freeze": "0.1.9",
|
||||||
"nouislider": "^11.1.0",
|
"nouislider": "^11.1.0",
|
||||||
"postcss-url": "^7.1.2",
|
"postcss-url": "^7.1.2",
|
||||||
"protractor": "5.1.2",
|
"protractor": "5.4.0",
|
||||||
"reselect": "3.0.1",
|
"reselect": "3.0.1",
|
||||||
"rxjs": "5.5.8",
|
"rxjs": "5.5.8",
|
||||||
"select2": "4.0.3",
|
|
||||||
"typescript": "2.6.2",
|
"typescript": "2.6.2",
|
||||||
"uhk-common": "1.0.0",
|
"uhk-common": "1.0.0",
|
||||||
"xml-loader": "1.2.1",
|
"xml-loader": "1.2.1",
|
||||||
@@ -79,6 +78,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"classlist.js": "1.1.20150312",
|
"classlist.js": "1.1.20150312",
|
||||||
"file-saver": "1.3.3"
|
"file-saver": "1.3.3",
|
||||||
|
"spacing-bootstrap-3": "^1.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ exports.config = {
|
|||||||
'browserName': 'chrome'
|
'browserName': 'chrome'
|
||||||
},
|
},
|
||||||
directConnect: true,
|
directConnect: true,
|
||||||
baseUrl: 'http://localhost:4200/',
|
baseUrl: 'http://localhost:8080/',
|
||||||
framework: 'jasmine',
|
framework: 'jasmine',
|
||||||
jasmineNodeOpts: {
|
jasmineNodeOpts: {
|
||||||
showColors: true,
|
showColors: true,
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<notifier-container></notifier-container>
|
<notifier-container></notifier-container>
|
||||||
<progress-button class="save-to-keyboard-button"
|
<progress-button class="save-to-keyboard-button"
|
||||||
*ngIf="(saveToKeyboardState$ | async).showButton"
|
*ngIf="saveToKeyboardState.showButton"
|
||||||
[@showSaveToKeyboardButton]
|
[@showSaveToKeyboardButton]
|
||||||
[state]="saveToKeyboardState$ | async"
|
[state]="saveToKeyboardState"
|
||||||
(clicked)="clickedOnProgressButton($event)"></progress-button>
|
(clicked)="clickedOnProgressButton($event)"></progress-button>
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import { Component, ViewEncapsulation } from '@angular/core';
|
import { Component, HostListener, ViewEncapsulation, OnDestroy } from '@angular/core';
|
||||||
import { animate, style, transition, trigger } from '@angular/animations';
|
import { animate, style, transition, trigger } from '@angular/animations';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
import { Action, Store } from '@ngrx/store';
|
import { Action, Store } from '@ngrx/store';
|
||||||
|
|
||||||
import 'rxjs/add/operator/last';
|
import 'rxjs/add/operator/last';
|
||||||
|
|
||||||
import { DoNotUpdateAppAction, UpdateAppAction } from './store/actions/app-update.action';
|
import { DoNotUpdateAppAction, UpdateAppAction } from './store/actions/app-update.action';
|
||||||
|
import { EnableUsbStackTestAction } from './store/actions/device';
|
||||||
import {
|
import {
|
||||||
AppState,
|
AppState,
|
||||||
getShowAppUpdateAvailable,
|
getShowAppUpdateAvailable,
|
||||||
@@ -34,17 +36,44 @@ import { ProgressButtonState } from './store/reducers/progress-button-state';
|
|||||||
])
|
])
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class MainAppComponent {
|
export class MainAppComponent implements OnDestroy {
|
||||||
showUpdateAvailable$: Observable<boolean>;
|
showUpdateAvailable$: Observable<boolean>;
|
||||||
deviceConfigurationLoaded$: Observable<boolean>;
|
deviceConfigurationLoaded$: Observable<boolean>;
|
||||||
runningInElectron$: Observable<boolean>;
|
runningInElectron$: Observable<boolean>;
|
||||||
saveToKeyboardState$: Observable<ProgressButtonState>;
|
saveToKeyboardState: ProgressButtonState;
|
||||||
|
|
||||||
|
private saveToKeyboardStateSubscription: Subscription;
|
||||||
|
|
||||||
constructor(private store: Store<AppState>) {
|
constructor(private store: Store<AppState>) {
|
||||||
this.showUpdateAvailable$ = store.select(getShowAppUpdateAvailable);
|
this.showUpdateAvailable$ = store.select(getShowAppUpdateAvailable);
|
||||||
this.deviceConfigurationLoaded$ = store.select(deviceConfigurationLoaded);
|
this.deviceConfigurationLoaded$ = store.select(deviceConfigurationLoaded);
|
||||||
this.runningInElectron$ = store.select(runningInElectron);
|
this.runningInElectron$ = store.select(runningInElectron);
|
||||||
this.saveToKeyboardState$ = store.select(saveToKeyboardState);
|
this.saveToKeyboardStateSubscription = store.select(saveToKeyboardState)
|
||||||
|
.subscribe(data => this.saveToKeyboardState = data);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.saveToKeyboardStateSubscription.unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
@HostListener('document:keydown', ['$event'])
|
||||||
|
onKeyDown(event: KeyboardEvent) {
|
||||||
|
if (this.saveToKeyboardState.showButton &&
|
||||||
|
event.ctrlKey &&
|
||||||
|
event.key === 's' &&
|
||||||
|
!event.defaultPrevented) {
|
||||||
|
this.clickedOnProgressButton(this.saveToKeyboardState.action);
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.shiftKey &&
|
||||||
|
event.ctrlKey &&
|
||||||
|
event.metaKey &&
|
||||||
|
event.key === '|' &&
|
||||||
|
!event.defaultPrevented) {
|
||||||
|
this.enableUsbStackTest();
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateApp() {
|
updateApp() {
|
||||||
@@ -58,4 +87,8 @@ export class MainAppComponent {
|
|||||||
clickedOnProgressButton(action: Action) {
|
clickedOnProgressButton(action: Action) {
|
||||||
return this.store.dispatch(action);
|
return this.store.dispatch(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enableUsbStackTest() {
|
||||||
|
this.store.dispatch(new EnableUsbStackTestAction());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<span>About</span>
|
<span>About</span>
|
||||||
</h1>
|
</h1>
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<div class="agent-version">Agent version: <span class="text-bold">{{version}}</span></div>
|
<div class="agent-version">Agent version: <span class="text-bold">{{ version }}</span></div>
|
||||||
<div><a class="link-github" (click)="openAgentGitHubPage($event)">Agent on GitHub</a></div>
|
<div><a class="link-github" [href]="agentGithubUrl" externalUrl>Agent on GitHub</a></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { Store } from '@ngrx/store';
|
|
||||||
import { Constants } from 'uhk-common';
|
import { Constants } from 'uhk-common';
|
||||||
|
|
||||||
import { AppState } from '../../../store';
|
|
||||||
import { getVersions } from '../../../util';
|
import { getVersions } from '../../../util';
|
||||||
import { OpenUrlInNewWindowAction } from '../../../store/actions/app';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'about-page',
|
selector: 'about-page',
|
||||||
@@ -16,12 +13,5 @@ import { OpenUrlInNewWindowAction } from '../../../store/actions/app';
|
|||||||
})
|
})
|
||||||
export class AboutComponent {
|
export class AboutComponent {
|
||||||
version: string = getVersions().version;
|
version: string = getVersions().version;
|
||||||
|
agentGithubUrl = Constants.AGENT_GITHUB_URL;
|
||||||
constructor(private store: Store<AppState>) {
|
|
||||||
}
|
|
||||||
|
|
||||||
openAgentGitHubPage(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
this.store.dispatch(new OpenUrlInNewWindowAction(Constants.AGENT_GITHUB_URL));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,17 @@ import { Routes } from '@angular/router';
|
|||||||
|
|
||||||
import { SettingsComponent } from './settings/settings.component';
|
import { SettingsComponent } from './settings/settings.component';
|
||||||
import { AboutComponent } from './about/about.component';
|
import { AboutComponent } from './about/about.component';
|
||||||
|
import { HelpPageComponent } from './help-page/help-page.component';
|
||||||
|
|
||||||
export const agentRoutes: Routes = [
|
export const agentRoutes: Routes = [
|
||||||
{
|
{
|
||||||
path: 'settings',
|
path: 'settings',
|
||||||
component: SettingsComponent
|
component: SettingsComponent
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'help',
|
||||||
|
component: HelpPageComponent
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'about',
|
path: 'about',
|
||||||
component: AboutComponent
|
component: AboutComponent
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<div class="row">
|
||||||
|
<h1 class="col-xs-12 pane-title">
|
||||||
|
<i class="fa fa-question-circle"></i>
|
||||||
|
<span class="macro__name pane-title__name">Help</span>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
Frequently asked questions
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://ultimatehackingkeyboard.com/blog/2018/06/23/how-can-i-type-accented-characters-with-my-uhk" externalUrl>How can I type accented characters with my UHK?</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
Keyboard shortcuts
|
||||||
|
<ul>
|
||||||
|
<li><kbd>CTRL</kbd> + <kbd>Enter</kbd> = Remap key</li>
|
||||||
|
<li><kbd>CTRL</kbd> + <kbd>S</kbd> = Save to keyboard</li>
|
||||||
|
<li>Right click on a key = Capture key</li>
|
||||||
|
<li>Hold Shift while clicking on a key = Remap on all keymaps</li>
|
||||||
|
<li>Hold Alt while clicking on a key = Remap on all layers</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
:host {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'help-page',
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
templateUrl: './help-page.component.html',
|
||||||
|
styleUrls: ['./help-page.component.scss'],
|
||||||
|
host: {
|
||||||
|
'class': 'container-fluid'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
export class HelpPageComponent {
|
||||||
|
}
|
||||||
@@ -12,13 +12,10 @@
|
|||||||
Firmware {{ hardwareModules.rightModuleInfo.firmwareVersion }} is running on the right keyboard half.
|
Firmware {{ hardwareModules.rightModuleInfo.firmwareVersion }} is running on the right keyboard half.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p *ngIf="showUnsupportedOsToFirmwareUpgrade$ | async">Firmware update doesn't work on Windows 7, Windows Vista, and Windows XP. Use Windows 10, Windows 8, Linux, or OSX instead.</p>
|
<p *ngIf="runningOnNotSupportedWindows$ | async">Firmware update doesn't work on Windows 7, Windows Vista,
|
||||||
|
and Windows XP. Use Windows 10, Windows 8, Linux, or OSX instead.</p>
|
||||||
|
|
||||||
<p>If the update process fails, disconnect every USB device from your computer including USB hubs, KVM switches, and every USB device. Then connect only your UHK and retry.</p>
|
<p *ngIf="firmwareUpgradeAllowed$ | async">
|
||||||
|
|
||||||
<p>If you tried the above and the update still keeps failing, please <a class="link-github" (click)="openFirmwareGitHubIssuePage($event)">create a GitHub issue</a>, and attach the update log.</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<button class="btn btn-primary"
|
<button class="btn btn-primary"
|
||||||
[disabled]="flashFirmwareButtonDisbabled$ | async"
|
[disabled]="flashFirmwareButtonDisbabled$ | async"
|
||||||
(click)="onUpdateFirmware()">
|
(click)="onUpdateFirmware()">
|
||||||
@@ -29,9 +26,23 @@
|
|||||||
accept=".tar.bz2"
|
accept=".tar.bz2"
|
||||||
label="Choose firmware file and flash it"></file-upload>
|
label="Choose firmware file and flash it"></file-upload>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<div *ngIf="firmwareUpgradeFailed$ | async"
|
||||||
|
class="alert alert-danger"
|
||||||
|
role="alert">
|
||||||
|
<p>Firmware update failed. Disconnect every USB device from your computer (including USB hubs, KVM switches, USB dongles, and everything else), then connect only your UHK and retry.</p>
|
||||||
|
|
||||||
|
<p>If you've tried the above and the update still keeps failing, please <a class="link-github" (click)="openFirmwareGitHubIssuePage($event)">create a GitHub issue</a>, and attach the update log.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="firmwareUpgradeSuccess$ | async"
|
||||||
|
class="alert alert-success"
|
||||||
|
role="alert">
|
||||||
|
<p>Firmware update succeeded.</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex-grow">
|
<div class="flex-grow" *ngIf="firmwareUpgradeAllowed$ | async">
|
||||||
<xterm [logs]="xtermLog$ | async"></xterm>
|
<xterm [logs]="xtermLog$ | async"></xterm>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-footer">
|
<div class="flex-footer">
|
||||||
|
|||||||
@@ -7,10 +7,13 @@ import { Constants, HardwareModules, VersionInformation } from 'uhk-common';
|
|||||||
import { OpenUrlInNewWindowAction } from '../../../store/actions/app';
|
import { OpenUrlInNewWindowAction } from '../../../store/actions/app';
|
||||||
import {
|
import {
|
||||||
AppState,
|
AppState,
|
||||||
|
firmwareUpgradeAllowed,
|
||||||
|
firmwareUpgradeFailed,
|
||||||
|
firmwareUpgradeSuccess,
|
||||||
flashFirmwareButtonDisbabled,
|
flashFirmwareButtonDisbabled,
|
||||||
getAgentVersionInfo,
|
getAgentVersionInfo,
|
||||||
getHardwareModules,
|
getHardwareModules,
|
||||||
showUnsupportedOsToFirmwareUpgrade,
|
runningOnNotSupportedWindows,
|
||||||
xtermLog
|
xtermLog
|
||||||
} from '../../../store';
|
} from '../../../store';
|
||||||
import { UpdateFirmwareAction, UpdateFirmwareWithAction } from '../../../store/actions/device';
|
import { UpdateFirmwareAction, UpdateFirmwareWithAction } from '../../../store/actions/device';
|
||||||
@@ -31,7 +34,10 @@ export class DeviceFirmwareComponent implements OnDestroy {
|
|||||||
getAgentVersionInfo$: Observable<VersionInformation>;
|
getAgentVersionInfo$: Observable<VersionInformation>;
|
||||||
hardwareModulesSubscription: Subscription;
|
hardwareModulesSubscription: Subscription;
|
||||||
hardwareModules: HardwareModules;
|
hardwareModules: HardwareModules;
|
||||||
showUnsupportedOsToFirmwareUpgrade$: Observable<boolean>;
|
runningOnNotSupportedWindows$: Observable<boolean>;
|
||||||
|
firmwareUpgradeAllowed$: Observable<boolean>;
|
||||||
|
firmwareUpgradeFailed$: Observable<boolean>;
|
||||||
|
firmwareUpgradeSuccess$: Observable<boolean>;
|
||||||
|
|
||||||
constructor(private store: Store<AppState>) {
|
constructor(private store: Store<AppState>) {
|
||||||
this.flashFirmwareButtonDisbabled$ = store.select(flashFirmwareButtonDisbabled);
|
this.flashFirmwareButtonDisbabled$ = store.select(flashFirmwareButtonDisbabled);
|
||||||
@@ -40,7 +46,10 @@ export class DeviceFirmwareComponent implements OnDestroy {
|
|||||||
this.hardwareModulesSubscription = store.select(getHardwareModules).subscribe(data => {
|
this.hardwareModulesSubscription = store.select(getHardwareModules).subscribe(data => {
|
||||||
this.hardwareModules = data;
|
this.hardwareModules = data;
|
||||||
});
|
});
|
||||||
this.showUnsupportedOsToFirmwareUpgrade$ = store.select(showUnsupportedOsToFirmwareUpgrade);
|
this.runningOnNotSupportedWindows$ = store.select(runningOnNotSupportedWindows);
|
||||||
|
this.firmwareUpgradeAllowed$ = store.select(firmwareUpgradeAllowed);
|
||||||
|
this.firmwareUpgradeFailed$ = store.select(firmwareUpgradeFailed);
|
||||||
|
this.firmwareUpgradeSuccess$ = store.select(firmwareUpgradeSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
<div class="row led-setting">
|
<div class="row led-setting">
|
||||||
<div class="col-xs-12 col-md-6">
|
<div class="col-xs-12 col-md-6">
|
||||||
<slider-wrapper
|
<slider-wrapper
|
||||||
label="Key backlight brightness"
|
label="Key backlight brightness <span class='text-muted pl-1'>Please note that current UHK versions are not backlit.</span>"
|
||||||
[min]="0"
|
[min]="0"
|
||||||
[max]="255"
|
[max]="255"
|
||||||
[step]="1"
|
[step]="1"
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
:host {
|
:host {
|
||||||
overflow-y: auto;
|
|
||||||
display: block;
|
display: block;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
[keyboardLayout]="keyboardLayout"
|
[keyboardLayout]="keyboardLayout"
|
||||||
[description]="description"
|
[description]="description"
|
||||||
[showDescription]="true"
|
[showDescription]="true"
|
||||||
|
oncontextmenu="return false;"
|
||||||
(keyClick)="keyClick.emit($event)"
|
(keyClick)="keyClick.emit($event)"
|
||||||
(keyHover)="keyHover.emit($event)"
|
(keyHover)="keyHover.emit($event)"
|
||||||
(capture)="capture.emit($event)"
|
(capture)="capture.emit($event)"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 809 B After Width: | Height: | Size: 853 B |
@@ -3,6 +3,11 @@ import { animate, keyframes, state, style, transition, trigger } from '@angular/
|
|||||||
import { Layer } from 'uhk-common';
|
import { Layer } from 'uhk-common';
|
||||||
|
|
||||||
import { KeyboardLayout } from '../../../keyboard/keyboard-layout.enum';
|
import { KeyboardLayout } from '../../../keyboard/keyboard-layout.enum';
|
||||||
|
import {
|
||||||
|
SvgKeyboardCaptureEvent,
|
||||||
|
SvgKeyboardKeyClickEvent,
|
||||||
|
SvgKeyHoverEvent
|
||||||
|
} from '../../../models/svg-key-events';
|
||||||
|
|
||||||
type AnimationKeyboard =
|
type AnimationKeyboard =
|
||||||
'init' |
|
'init' |
|
||||||
@@ -82,9 +87,9 @@ export class KeyboardSliderComponent implements OnChanges {
|
|||||||
@Input() selectedKey: { layerId: number, moduleId: number, keyId: number };
|
@Input() selectedKey: { layerId: number, moduleId: number, keyId: number };
|
||||||
@Input() keyboardLayout = KeyboardLayout.ANSI;
|
@Input() keyboardLayout = KeyboardLayout.ANSI;
|
||||||
@Input() description: string;
|
@Input() description: string;
|
||||||
@Output() keyClick = new EventEmitter();
|
@Output() keyClick = new EventEmitter<SvgKeyboardKeyClickEvent>();
|
||||||
@Output() keyHover = new EventEmitter();
|
@Output() keyHover = new EventEmitter<SvgKeyHoverEvent>();
|
||||||
@Output() capture = new EventEmitter();
|
@Output() capture = new EventEmitter<SvgKeyboardCaptureEvent>();
|
||||||
@Output() descriptionChanged = new EventEmitter<string>();
|
@Output() descriptionChanged = new EventEmitter<string>();
|
||||||
|
|
||||||
layerAnimationState: AnimationKeyboard[];
|
layerAnimationState: AnimationKeyboard[];
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Component } from '@angular/core';
|
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { Keymap } from 'uhk-common';
|
import { Keymap } from 'uhk-common';
|
||||||
|
|
||||||
@@ -14,6 +14,7 @@ import { KeymapActions } from '../../../store/actions';
|
|||||||
selector: 'keymap-add',
|
selector: 'keymap-add',
|
||||||
templateUrl: './keymap-add.component.html',
|
templateUrl: './keymap-add.component.html',
|
||||||
styleUrls: ['./keymap-add.component.scss'],
|
styleUrls: ['./keymap-add.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
host: {
|
host: {
|
||||||
'class': 'container-fluid'
|
'class': 'container-fluid'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Component, HostListener } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, HostListener } from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { Keymap } from 'uhk-common';
|
import { Keymap } from 'uhk-common';
|
||||||
@@ -24,6 +24,7 @@ import { ChangeKeymapDescription } from '../../../models/ChangeKeymapDescription
|
|||||||
selector: 'keymap-edit',
|
selector: 'keymap-edit',
|
||||||
templateUrl: './keymap-edit.component.html',
|
templateUrl: './keymap-edit.component.html',
|
||||||
styleUrls: ['./keymap-edit.component.scss'],
|
styleUrls: ['./keymap-edit.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
host: {
|
host: {
|
||||||
'class': 'container-fluid'
|
'class': 'container-fluid'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,4 +43,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,10 +8,12 @@
|
|||||||
<icon *ngIf="deletable" name="trash" (click)="deleteAction()"></icon>
|
<icon *ngIf="deletable" name="trash" (click)="deleteAction()"></icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-group-item macro-action-editor__container"
|
<div class="list-group-item macro-action-editor__container"
|
||||||
[@toggler]="((editable && editing) || newItem) ? 'active' : 'inactive'">
|
[@toggler]="((editable && editing) || newItem) ? 'active' : 'inactive'"
|
||||||
<macro-action-editor
|
[style.overflow]="overflow">
|
||||||
[macroAction]="macroAction"
|
<macro-action-editor
|
||||||
(cancel)="cancelEdit()"
|
*ngIf="editable || newItem"
|
||||||
(save)="saveEditedAction($event)">
|
[macroAction]="macroAction"
|
||||||
</macro-action-editor>
|
(cancel)="cancelEdit()"
|
||||||
</div>
|
(save)="saveEditedAction($event)">
|
||||||
|
</macro-action-editor>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@import '../../../../styles/variables';
|
@import '../../../../styles/variables';
|
||||||
|
|
||||||
:host {
|
:host {
|
||||||
overflow: hidden;
|
overflow: visible;
|
||||||
display: block;
|
display: block;
|
||||||
|
|
||||||
&.macro-item:first-of-type {
|
&.macro-item:first-of-type {
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ export class MacroItemComponent implements OnInit, OnChanges {
|
|||||||
iconName: string;
|
iconName: string;
|
||||||
editing: boolean;
|
editing: boolean;
|
||||||
newItem: boolean = false;
|
newItem: boolean = false;
|
||||||
|
overflow = 'hidden';
|
||||||
|
|
||||||
constructor(private mapper: MapperService) { }
|
constructor(private mapper: MapperService) { }
|
||||||
|
|
||||||
@@ -53,6 +54,7 @@ export class MacroItemComponent implements OnInit, OnChanges {
|
|||||||
if (!this.macroAction) {
|
if (!this.macroAction) {
|
||||||
this.editing = true;
|
this.editing = true;
|
||||||
this.newItem = true;
|
this.newItem = true;
|
||||||
|
this.overflow = 'visible';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,6 +67,7 @@ export class MacroItemComponent implements OnInit, OnChanges {
|
|||||||
saveEditedAction(editedAction: MacroAction): void {
|
saveEditedAction(editedAction: MacroAction): void {
|
||||||
this.macroAction = editedAction;
|
this.macroAction = editedAction;
|
||||||
this.editing = false;
|
this.editing = false;
|
||||||
|
this.overflow = 'hidden';
|
||||||
this.updateView();
|
this.updateView();
|
||||||
this.save.emit(editedAction);
|
this.save.emit(editedAction);
|
||||||
}
|
}
|
||||||
@@ -77,10 +80,12 @@ export class MacroItemComponent implements OnInit, OnChanges {
|
|||||||
|
|
||||||
this.editing = true;
|
this.editing = true;
|
||||||
this.edit.emit();
|
this.edit.emit();
|
||||||
|
this.setOverflow('visible');
|
||||||
}
|
}
|
||||||
|
|
||||||
cancelEdit(): void {
|
cancelEdit(): void {
|
||||||
this.editing = false;
|
this.editing = false;
|
||||||
|
this.overflow = 'hidden';
|
||||||
this.cancel.emit();
|
this.cancel.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,7 +176,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) {
|
||||||
@@ -202,4 +207,12 @@ export class MacroItemComponent implements OnInit, OnChanges {
|
|||||||
});
|
});
|
||||||
this.title += selectedButtonLabels.join(', ');
|
this.title += selectedButtonLabels.join(', ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private setOverflow(value: string): void {
|
||||||
|
// tslint:disable: align
|
||||||
|
setTimeout(() => {
|
||||||
|
this.overflow = value;
|
||||||
|
}, 600);
|
||||||
|
// tslint:enable: align
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
@@ -81,14 +85,16 @@
|
|||||||
<label>
|
<label>
|
||||||
<input type="checkbox"
|
<input type="checkbox"
|
||||||
name="remapOnAllKeymap"
|
name="remapOnAllKeymap"
|
||||||
[(ngModel)]="remapOnAllKeymap"> Remap on all keymaps
|
[(ngModel)]="remapInfo.remapOnAllKeymap"> Remap on all keymaps
|
||||||
</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)]="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">
|
||||||
@@ -109,7 +115,7 @@
|
|||||||
<div class="d-inline-block pull-right">
|
<div class="d-inline-block pull-right">
|
||||||
<button class="btn btn-sm btn-default" type="button" (click)="onCancelClick()"> Cancel</button>
|
<button class="btn btn-sm btn-default" type="button" (click)="onCancelClick()"> Cancel</button>
|
||||||
<button class="btn btn-sm btn-primary" [class.disabled]="!keyActionValid" type="button"
|
<button class="btn btn-sm btn-primary" [class.disabled]="!keyActionValid" type="button"
|
||||||
(click)="onRemapKey()"> Remap Key
|
(click)="onRemapKey()"> Remap key
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -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%;
|
||||||
@@ -116,27 +120,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.select2-item {
|
|
||||||
position: relative;
|
|
||||||
font-size: 1.5rem;
|
|
||||||
|
|
||||||
&.keymap-name--wrapper {
|
|
||||||
padding-left: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layout-segment-code {
|
|
||||||
height: 2rem;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 50%;
|
|
||||||
margin-top: -1rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.popover-action-form {
|
.popover-action-form {
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
|
|
||||||
label {
|
label {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
color: #959595;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
ChangeDetectorRef,
|
||||||
Component,
|
Component,
|
||||||
ElementRef,
|
ElementRef,
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
@@ -23,6 +25,7 @@ import {
|
|||||||
KeystrokeAction,
|
KeystrokeAction,
|
||||||
MouseAction,
|
MouseAction,
|
||||||
PlayMacroAction,
|
PlayMacroAction,
|
||||||
|
SecondaryRoleAction,
|
||||||
SwitchKeymapAction,
|
SwitchKeymapAction,
|
||||||
SwitchLayerAction
|
SwitchLayerAction
|
||||||
} from 'uhk-common';
|
} from 'uhk-common';
|
||||||
@@ -32,6 +35,7 @@ import { Tab } from './tab';
|
|||||||
import { AppState } from '../../store';
|
import { AppState } from '../../store';
|
||||||
import { getKeymaps } from '../../store/reducers/user-configuration';
|
import { getKeymaps } from '../../store/reducers/user-configuration';
|
||||||
import { KeyActionRemap } from '../../models/key-action-remap';
|
import { KeyActionRemap } from '../../models/key-action-remap';
|
||||||
|
import { RemapInfo } from '../../models/remap-info';
|
||||||
|
|
||||||
enum TabName {
|
enum TabName {
|
||||||
Keypress,
|
Keypress,
|
||||||
@@ -46,6 +50,7 @@ enum TabName {
|
|||||||
selector: 'popover',
|
selector: 'popover',
|
||||||
templateUrl: './popover.component.html',
|
templateUrl: './popover.component.html',
|
||||||
styleUrls: ['./popover.component.scss'],
|
styleUrls: ['./popover.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
animations: [
|
animations: [
|
||||||
trigger('popover', [
|
trigger('popover', [
|
||||||
state('closed', style({
|
state('closed', style({
|
||||||
@@ -84,6 +89,7 @@ export class PopoverComponent implements OnChanges {
|
|||||||
@Input() wrapPosition: any;
|
@Input() wrapPosition: any;
|
||||||
@Input() visible: boolean;
|
@Input() visible: boolean;
|
||||||
@Input() allowLayerDoubleTap: boolean;
|
@Input() allowLayerDoubleTap: boolean;
|
||||||
|
@Input() remapInfo: RemapInfo;
|
||||||
|
|
||||||
@Output() cancel = new EventEmitter<any>();
|
@Output() cancel = new EventEmitter<any>();
|
||||||
@Output() remap = new EventEmitter<KeyActionRemap>();
|
@Output() remap = new EventEmitter<KeyActionRemap>();
|
||||||
@@ -100,13 +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;
|
||||||
remapOnAllKeymap: boolean;
|
disableRemapOnAllLayer = false;
|
||||||
remapOnAllLayer: boolean;
|
|
||||||
|
|
||||||
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$)
|
||||||
@@ -122,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;
|
||||||
@@ -143,8 +151,6 @@ export class PopoverComponent implements OnChanges {
|
|||||||
if (change['visible']) {
|
if (change['visible']) {
|
||||||
if (change['visible'].currentValue) {
|
if (change['visible'].currentValue) {
|
||||||
this.animationState = 'opened';
|
this.animationState = 'opened';
|
||||||
this.remapOnAllKeymap = false;
|
|
||||||
this.remapOnAllLayer = false;
|
|
||||||
} else {
|
} else {
|
||||||
this.animationState = 'closed';
|
this.animationState = 'closed';
|
||||||
}
|
}
|
||||||
@@ -163,8 +169,8 @@ export class PopoverComponent implements OnChanges {
|
|||||||
if (this.keyActionValid) {
|
if (this.keyActionValid) {
|
||||||
try {
|
try {
|
||||||
this.remap.emit({
|
this.remap.emit({
|
||||||
remapOnAllKeymap: this.remapOnAllKeymap,
|
remapOnAllKeymap: this.remapInfo.remapOnAllKeymap,
|
||||||
remapOnAllLayer: this.remapOnAllLayer,
|
remapOnAllLayer: this.remapInfo.remapOnAllLayer,
|
||||||
action: this.selectedTab.toKeyAction()
|
action: this.selectedTab.toKeyAction()
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -179,14 +185,49 @@ export class PopoverComponent implements OnChanges {
|
|||||||
this.cancel.emit();
|
this.cancel.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@HostListener('document:keydown.control.enter', ['$event'])
|
||||||
|
onKeyDown(event: KeyboardEvent) {
|
||||||
|
if (this.visible) {
|
||||||
|
this.onRemapKey();
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|||||||
@@ -4,12 +4,23 @@
|
|||||||
<ng-template [ngIf]="keymapOptions.length > 0">
|
<ng-template [ngIf]="keymapOptions.length > 0">
|
||||||
<div>
|
<div>
|
||||||
<b>Switch to keymap:</b>
|
<b>Switch to keymap:</b>
|
||||||
<select2
|
<ngx-select [items]="keymapOptions"
|
||||||
[data]="keymapOptions"
|
[ngModel]="selectedKeymap?.abbreviation || -1"
|
||||||
[value]="selectedKeymap?.abbreviation || -1"
|
[autoActiveOnMouseEnter]="false"
|
||||||
(valueChanged)="onChange($event)"
|
size="small"
|
||||||
[width]="'100%'"
|
optionValueField="id"
|
||||||
></select2>
|
optionTextField="text"
|
||||||
|
(select)="onChange($event)">
|
||||||
|
|
||||||
|
<ng-template ngx-select-option let-option>
|
||||||
|
<span [ngClass]="{'indent-dropdown-item':option.data.id !== '-1'}">
|
||||||
|
<span>{{ option.text }}</span>
|
||||||
|
<span class="scancode--searchterm">
|
||||||
|
{{ option.data.additional?.explanation}}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</ng-template>
|
||||||
|
</ngx-select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="empty" *ngIf="!selectedKeymap?.abbreviation">
|
<div class="empty" *ngIf="!selectedKeymap?.abbreviation">
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
margin-right: 7px;
|
margin-right: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
select2 {
|
ngx-select {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core';
|
||||||
import { Select2OptionData } from 'ng2-select2/ng2-select2';
|
|
||||||
import { Keymap, KeyAction, SwitchKeymapAction } from 'uhk-common';
|
import { Keymap, KeyAction, SwitchKeymapAction } from 'uhk-common';
|
||||||
|
|
||||||
import { Tab } from '../tab';
|
import { Tab } from '../tab';
|
||||||
|
import { SelectOptionData } from '../../../../models/select-option-data';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'keymap-tab',
|
selector: 'keymap-tab',
|
||||||
@@ -14,7 +14,7 @@ export class KeymapTabComponent extends Tab implements OnChanges {
|
|||||||
@Input() defaultKeyAction: KeyAction;
|
@Input() defaultKeyAction: KeyAction;
|
||||||
@Input() keymaps: Keymap[];
|
@Input() keymaps: Keymap[];
|
||||||
|
|
||||||
keymapOptions: Array<Select2OptionData>;
|
keymapOptions: Array<SelectOptionData>;
|
||||||
selectedKeymap: Keymap;
|
selectedKeymap: Keymap;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -25,7 +25,7 @@ export class KeymapTabComponent extends Tab implements OnChanges {
|
|||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
if (changes.keymaps) {
|
if (changes.keymaps) {
|
||||||
this.keymapOptions = this.keymaps
|
this.keymapOptions = this.keymaps
|
||||||
.map((keymap: Keymap): Select2OptionData => {
|
.map((keymap: Keymap): SelectOptionData => {
|
||||||
return {
|
return {
|
||||||
id: keymap.abbreviation,
|
id: keymap.abbreviation,
|
||||||
text: keymap.name
|
text: keymap.name
|
||||||
@@ -40,12 +40,11 @@ export class KeymapTabComponent extends Tab implements OnChanges {
|
|||||||
this.validAction.emit(true);
|
this.validAction.emit(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: change to the correct type when the wrapper has added it.
|
onChange(event: string) {
|
||||||
onChange(event: any) {
|
if (event === '-1') {
|
||||||
if (event.value === '-1') {
|
|
||||||
this.selectedKeymap = undefined;
|
this.selectedKeymap = undefined;
|
||||||
} else {
|
} else {
|
||||||
this.selectedKeymap = this.keymaps.find((keymap: Keymap) => keymap.abbreviation === event.value);
|
this.selectedKeymap = this.keymaps.find((keymap: Keymap) => keymap.abbreviation === event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,27 @@
|
|||||||
<div class="scancode-options">
|
<div class="scancode-options">
|
||||||
<b class="setting-label">Scancode:</b>
|
<b class="setting-label">Scancode:</b>
|
||||||
<select2
|
<div class="scancode-container">
|
||||||
[data]="scanCodeGroups"
|
<ngx-select [items]="scanCodeGroups"
|
||||||
[value]="selectedScancodeOption.id"
|
[ngModel]="selectedScancodeOption?.id"
|
||||||
(valueChanged)="onScancodeChange($event)"
|
[autoActiveOnMouseEnter]="false"
|
||||||
[width]="200"
|
size="small"
|
||||||
[options]="options"
|
optionValueField="id"
|
||||||
></select2>
|
optionTextField="text"
|
||||||
|
optGroupLabelField="text"
|
||||||
|
optGroupOptionsField="children"
|
||||||
|
(select)="onScancodeChange($event)">
|
||||||
|
|
||||||
|
<ng-template ngx-select-option let-option>
|
||||||
|
<span [ngClass]="{'indent-dropdown-item':option.data.id !== '0'}">
|
||||||
|
<span>{{ option.text }}</span>
|
||||||
|
<span class="scancode--searchterm">
|
||||||
|
{{ option.data.additional?.explanation}}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
</ngx-select>
|
||||||
|
</div>
|
||||||
<icon name="question-circle"
|
<icon name="question-circle"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip"
|
||||||
html="true"
|
html="true"
|
||||||
@@ -21,32 +36,48 @@
|
|||||||
<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>
|
||||||
</div>
|
</div>
|
||||||
<div class="long-press-container" *ngIf="secondaryRoleEnabled">
|
<div class="long-press-container" *ngIf="secondaryRoleEnabled">
|
||||||
<b class="setting-label">Secondary role:</b>
|
<b class="setting-label">Secondary role:</b>
|
||||||
<select2 #secondaryRoleSelect
|
<div class="secondary-role-groups-container">
|
||||||
[data]="secondaryRoleGroups"
|
<ngx-select [items]="secondaryRoleGroups"
|
||||||
[value]="selectedSecondaryRoleIndex.toString()"
|
[ngModel]="selectedSecondaryRoleIndex.toString()"
|
||||||
(valueChanged)="onSecondaryRoleChange($event)"
|
[autoActiveOnMouseEnter]="false"
|
||||||
[width]="140"
|
size="small"
|
||||||
></select2>
|
optionValueField="id"
|
||||||
|
optionTextField="text"
|
||||||
|
optGroupLabelField="text"
|
||||||
|
optGroupOptionsField="children"
|
||||||
|
(select)="onSecondaryRoleChange($event)">
|
||||||
|
|
||||||
|
<ng-template ngx-select-option let-option>
|
||||||
|
<span [ngClass]="{'indent-dropdown-item':option.data.id !== '-1'}">
|
||||||
|
<span>{{ option.text }}</span>
|
||||||
|
<span class="scancode--searchterm">
|
||||||
|
{{ option.data.additional?.explanation}}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
</ngx-select>
|
||||||
|
</div>
|
||||||
<icon name="question-circle"
|
<icon name="question-circle"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip"
|
||||||
html="true"
|
html="true"
|
||||||
@@ -57,10 +88,15 @@
|
|||||||
<li>Tap this key to trigger Escape. <i>(Primary role)</i></li>
|
<li>Tap this key to trigger Escape. <i>(Primary role)</i></li>
|
||||||
<li>Hold this key and press another key to activate the relevant key of the Mouse layer. <i>(Secondary role)</i></li>
|
<li>Hold this key and press another key to activate the relevant key of the Mouse layer. <i>(Secondary role)</i></li>
|
||||||
</ul>
|
</ul>
|
||||||
<p class='text-left pt-3'>The secondary role can be any layer or modifier.</p>"
|
<p class='text-left'>The secondary role can be any layer or modifier.</p>"
|
||||||
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.
|
||||||
|
|||||||
@@ -79,4 +79,21 @@
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.scancode-container {
|
||||||
|
display: inline-block;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.secondary-role-groups-container {
|
||||||
|
display: inline-block;
|
||||||
|
width: 140px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remap-warning {
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding-top: 5px;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,63 +1,78 @@
|
|||||||
import { Component, Input, OnChanges } from '@angular/core';
|
import {
|
||||||
import { Select2OptionData, Select2TemplateFunction } from 'ng2-select2';
|
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 { 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',
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
templateUrl: './keypress-tab.component.html',
|
templateUrl: './keypress-tab.component.html',
|
||||||
styleUrls: ['./keypress-tab.component.scss']
|
styleUrls: ['./keypress-tab.component.scss']
|
||||||
})
|
})
|
||||||
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<Select2OptionData>;
|
scanCodeGroups: Array<SelectOptionData>;
|
||||||
secondaryRoleGroups: Array<Select2OptionData>;
|
secondaryRoleGroups: Array<SelectOptionData> = [];
|
||||||
options: Select2Options;
|
|
||||||
|
|
||||||
selectedScancodeOption: Select2OptionData;
|
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;
|
||||||
this.options = {
|
|
||||||
templateResult: this.scanCodeTemplateResult,
|
|
||||||
matcher: (term: string, text: string, data: Select2OptionData) => {
|
|
||||||
let found = text.toUpperCase().indexOf(term.toUpperCase()) > -1;
|
|
||||||
|
|
||||||
if (!found && data.additional && data.additional.explanation) {
|
|
||||||
found = data.additional.explanation.toUpperCase().indexOf(term.toUpperCase()) > -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
@@ -68,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 {
|
||||||
@@ -88,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
|
||||||
@@ -119,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
|
||||||
@@ -134,50 +141,37 @@ export class KeypressTabComponent extends Tab implements OnChanges {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scanCodeTemplateResult: Select2TemplateFunction = (state: Select2OptionData): JQuery | string => {
|
toggleModifier(modifier: KeyModifierModel): void {
|
||||||
if (!state.id) {
|
modifier.checked = !modifier.checked;
|
||||||
return state.text;
|
this.keyActionChanged();
|
||||||
}
|
|
||||||
|
|
||||||
if (state.additional && state.additional.explanation) {
|
|
||||||
return jQuery(
|
|
||||||
'<span class="select2-item">'
|
|
||||||
+ '<span>' + state.text + '</span>'
|
|
||||||
+ '<span class="scancode--searchterm"> '
|
|
||||||
+ state.additional.explanation
|
|
||||||
+ '</span>' +
|
|
||||||
'</span>'
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return jQuery('<span class="select2-item">' + state.text + '</span>');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleModifier(right: boolean, index: number) {
|
onSecondaryRoleChange(id: string) {
|
||||||
const modifierSelects: boolean[] = right ? this.rightModifierSelects : this.leftModifierSelects;
|
this.selectedSecondaryRoleIndex = +id;
|
||||||
modifierSelects[index] = !modifierSelects[index];
|
this.keyActionChanged();
|
||||||
|
|
||||||
this.validAction.emit(this.keyActionValid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onSecondaryRoleChange(event: { value: string }) {
|
onScancodeChange(id: string) {
|
||||||
this.selectedSecondaryRoleIndex = +event.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
onScancodeChange(event: { value: string }) {
|
|
||||||
const id: string = event.value;
|
|
||||||
|
|
||||||
// ng2-select2 should provide the selectedOption in an upcoming release
|
|
||||||
// TODO: change this when it has become available
|
|
||||||
this.selectedScancodeOption = this.findScancodeOptionById(id);
|
this.selectedScancodeOption = this.findScancodeOptionById(id);
|
||||||
|
|
||||||
this.validAction.emit(this.keyActionValid());
|
this.keyActionChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private findScancodeOptionBy(predicate: (option: Select2OptionData) => boolean): Select2OptionData {
|
modifiersTrackBy(index: number, modifier: KeyModifierModel): string {
|
||||||
let selectedOption: Select2OptionData;
|
return `${modifier.value}${modifier.checked}`;
|
||||||
|
}
|
||||||
|
|
||||||
const scanCodeGroups: Select2OptionData[] = [...this.scanCodeGroups];
|
remapInfoChanged(remapInfo: RemapInfo): void {
|
||||||
|
this.remapInfo = remapInfo;
|
||||||
|
const keystrokeAction = this.toKeyAction();
|
||||||
|
this.calculateRemapOnAllLayerWarningVisibility(keystrokeAction);
|
||||||
|
this.cdRef.markForCheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
private findScancodeOptionBy(predicate: (option: SelectOptionData) => boolean): SelectOptionData {
|
||||||
|
let selectedOption: SelectOptionData;
|
||||||
|
|
||||||
|
const scanCodeGroups: SelectOptionData[] = [...this.scanCodeGroups];
|
||||||
while (scanCodeGroups.length > 0) {
|
while (scanCodeGroups.length > 0) {
|
||||||
const scanCodeGroup = scanCodeGroups.shift();
|
const scanCodeGroup = scanCodeGroups.shift();
|
||||||
if (predicate(scanCodeGroup)) {
|
if (predicate(scanCodeGroup)) {
|
||||||
@@ -192,14 +186,14 @@ export class KeypressTabComponent extends Tab implements OnChanges {
|
|||||||
return selectedOption;
|
return selectedOption;
|
||||||
}
|
}
|
||||||
|
|
||||||
private findScancodeOptionById(id: string): Select2OptionData {
|
private findScancodeOptionById(id: string): SelectOptionData {
|
||||||
return this.findScancodeOptionBy(option => option.id === id);
|
return this.findScancodeOptionBy(option => option.id === id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private findScancodeOptionByScancode(scancode: number, type: KeystrokeType): Select2OptionData {
|
private findScancodeOptionByScancode(scancode: number, type: KeystrokeType): SelectOptionData {
|
||||||
const typeToFind: string =
|
const typeToFind: string =
|
||||||
(type === KeystrokeType.shortMedia || type === KeystrokeType.longMedia) ? 'media' : KeystrokeType[type];
|
(type === KeystrokeType.shortMedia || type === KeystrokeType.longMedia) ? 'media' : KeystrokeType[type];
|
||||||
return this.findScancodeOptionBy((option: Select2OptionData) => {
|
return this.findScancodeOptionBy((option: SelectOptionData) => {
|
||||||
const additional = option.additional;
|
const additional = option.additional;
|
||||||
if (additional && additional.scancode === scancode && additional.type === typeToFind) {
|
if (additional && additional.scancode === scancode && additional.type === typeToFind) {
|
||||||
return true;
|
return true;
|
||||||
@@ -211,7 +205,11 @@ export class KeypressTabComponent extends Tab implements OnChanges {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private toScancodeTypePair(option: Select2OptionData): [number, string] {
|
private toScancodeTypePair(option: SelectOptionData): [number, string] {
|
||||||
|
if (!option) {
|
||||||
|
return [0, 'basic'];
|
||||||
|
}
|
||||||
|
|
||||||
let scanCode: number;
|
let scanCode: number;
|
||||||
let type: string;
|
let type: string;
|
||||||
if (option.additional) {
|
if (option.additional) {
|
||||||
@@ -227,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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Component, HostBinding, Input, OnChanges, SimpleChanges } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, HostBinding, Input, OnChanges, SimpleChanges } from '@angular/core';
|
||||||
import { KeyAction, LayerName, SwitchLayerAction, SwitchLayerMode } from 'uhk-common';
|
import { KeyAction, LayerName, SwitchLayerAction, SwitchLayerMode } from 'uhk-common';
|
||||||
|
|
||||||
import { Tab } from '../tab';
|
import { Tab } from '../tab';
|
||||||
@@ -7,6 +7,7 @@ export type toggleType = 'active' | 'toggle';
|
|||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'layer-tab',
|
selector: 'layer-tab',
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
templateUrl: './layer-tab.component.html',
|
templateUrl: './layer-tab.component.html',
|
||||||
styleUrls: ['./layer-tab.component.scss']
|
styleUrls: ['./layer-tab.component.scss']
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,7 +5,23 @@
|
|||||||
<p><i>Please note that macro playback is not implemented yet. You can bind macros, but they won't have any effect until firmware support is implemented. We're working on this.</i></p>
|
<p><i>Please note that macro playback is not implemented yet. You can bind macros, but they won't have any effect until firmware support is implemented. We're working on this.</i></p>
|
||||||
<div class="macro-selector">
|
<div class="macro-selector">
|
||||||
<b> Play macro: </b>
|
<b> Play macro: </b>
|
||||||
<select2 [data]="macroOptions" [value]="macroOptions[selectedMacroIndex].id" (valueChanged)="onChange($event)" [width]="'100%'"></select2>
|
<ngx-select [items]="macroOptions"
|
||||||
|
[ngModel]="macroOptions[selectedMacroIndex]?.id"
|
||||||
|
[autoActiveOnMouseEnter]="false"
|
||||||
|
size="small"
|
||||||
|
optionValueField="id"
|
||||||
|
optionTextField="text"
|
||||||
|
(select)="onChange($event)">
|
||||||
|
|
||||||
|
<ng-template ngx-select-option let-option>
|
||||||
|
<span [ngClass]="{'indent-dropdown-item':option.data.id !== '-1'}">
|
||||||
|
<span>{{ option.text }}</span>
|
||||||
|
<span class="scancode--searchterm">
|
||||||
|
{{ option.data.additional?.explanation}}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</ng-template>
|
||||||
|
</ngx-select>
|
||||||
</div>
|
</div>
|
||||||
<div class="macro-action-container">
|
<div class="macro-action-container">
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
@@ -14,4 +30,4 @@
|
|||||||
</macro-item>
|
</macro-item>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
margin-right: 7px;
|
margin-right: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
select2 {
|
ngx-select {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { Subscription } from 'rxjs/Subscription';
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
import { Select2OptionData } from 'ng2-select2/ng2-select2';
|
|
||||||
import { KeyAction, Macro, PlayMacroAction } from 'uhk-common';
|
import { KeyAction, Macro, PlayMacroAction } from 'uhk-common';
|
||||||
|
|
||||||
import { Tab } from '../tab';
|
import { Tab } from '../tab';
|
||||||
|
|
||||||
import { AppState } from '../../../../store/index';
|
import { AppState } from '../../../../store';
|
||||||
import { getMacros } from '../../../../store/reducers/user-configuration';
|
import { getMacros } from '../../../../store/reducers/user-configuration';
|
||||||
|
import { SelectOptionData } from '../../../../models/select-option-data';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'macro-tab',
|
selector: 'macro-tab',
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
templateUrl: './macro-tab.component.html',
|
templateUrl: './macro-tab.component.html',
|
||||||
styleUrls: ['./macro-tab.component.scss']
|
styleUrls: ['./macro-tab.component.scss']
|
||||||
})
|
})
|
||||||
@@ -18,7 +19,7 @@ export class MacroTabComponent extends Tab implements OnInit, OnChanges, OnDestr
|
|||||||
@Input() defaultKeyAction: KeyAction;
|
@Input() defaultKeyAction: KeyAction;
|
||||||
|
|
||||||
macros: Macro[];
|
macros: Macro[];
|
||||||
macroOptions: Array<Select2OptionData>;
|
macroOptions: Array<SelectOptionData>;
|
||||||
selectedMacroIndex: number;
|
selectedMacroIndex: number;
|
||||||
private subscription: Subscription;
|
private subscription: Subscription;
|
||||||
|
|
||||||
@@ -31,7 +32,7 @@ export class MacroTabComponent extends Tab implements OnInit, OnChanges, OnDestr
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.macroOptions = this.macros.map(function (macro: Macro, index: number): Select2OptionData {
|
this.macroOptions = this.macros.map(function (macro: Macro, index: number): SelectOptionData {
|
||||||
return {
|
return {
|
||||||
id: index.toString(),
|
id: index.toString(),
|
||||||
text: macro.name
|
text: macro.name
|
||||||
@@ -44,9 +45,8 @@ export class MacroTabComponent extends Tab implements OnInit, OnChanges, OnDestr
|
|||||||
this.validAction.emit(true);
|
this.validAction.emit(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: change to the correct type when the wrapper has added it.
|
onChange(id: string) {
|
||||||
onChange(event: any) {
|
this.selectedMacroIndex = +id;
|
||||||
this.selectedMacroIndex = +event.value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
keyActionValid(): boolean {
|
keyActionValid(): boolean {
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { Component, Input, OnChanges } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core';
|
||||||
import { KeyAction, MouseAction, MouseActionParam } from 'uhk-common';
|
import { KeyAction, MouseAction, MouseActionParam } from 'uhk-common';
|
||||||
|
|
||||||
import { Tab } from '../tab';
|
import { Tab } from '../tab';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mouse-tab',
|
selector: 'mouse-tab',
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
templateUrl: './mouse-tab.component.html',
|
templateUrl: './mouse-tab.component.html',
|
||||||
styleUrls: ['./mouse-tab.component.scss']
|
styleUrls: ['./mouse-tab.component.scss']
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
import { Tab } from '../tab';
|
import { Tab } from '../tab';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'none-tab',
|
selector: 'none-tab',
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
templateUrl: './none-tab.component.html',
|
templateUrl: './none-tab.component.html',
|
||||||
styleUrls: ['./none-tab.component.scss']
|
styleUrls: ['./none-tab.component.scss']
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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 {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import { Component, EventEmitter, HostListener, Output, Input } 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',
|
||||||
templateUrl: './capture-keystroke-button.component.html',
|
templateUrl: './capture-keystroke-button.component.html',
|
||||||
styleUrls: ['./capture-keystroke-button.component.scss']
|
styleUrls: ['./capture-keystroke-button.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class CaptureKeystrokeButtonComponent {
|
export class CaptureKeystrokeButtonComponent {
|
||||||
@Input() isLink = false;
|
@Input() isLink = false;
|
||||||
@@ -67,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,
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'icon',
|
selector: 'icon',
|
||||||
templateUrl: './icon.component.html',
|
templateUrl: './icon.component.html',
|
||||||
styleUrls: ['./icon.component.scss']
|
styleUrls: ['./icon.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class IconComponent implements OnInit {
|
export class IconComponent implements OnInit {
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -136,11 +136,17 @@
|
|||||||
(click)="toggleHide($event, 'agent')"></i>
|
(click)="toggleHide($event, 'agent')"></i>
|
||||||
</div>
|
</div>
|
||||||
<ul [@toggler]="animation['agent']">
|
<ul [@toggler]="animation['agent']">
|
||||||
<li class="sidebar__level-2--item">
|
<!--li class="sidebar__level-2--item">
|
||||||
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
||||||
<a [routerLink]="['/settings']"
|
<a [routerLink]="['/settings']"
|
||||||
[class.disabled]="state.updatingFirmware">Settings</a>
|
[class.disabled]="state.updatingFirmware">Settings</a>
|
||||||
</div>
|
</div>
|
||||||
|
</li-->
|
||||||
|
<li class="sidebar__level-2--item">
|
||||||
|
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
||||||
|
<a [routerLink]="['/help']"
|
||||||
|
[class.disabled]="state.updatingFirmware">Help</a>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li class="sidebar__level-2--item">
|
<li class="sidebar__level-2--item">
|
||||||
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<label *ngIf="label">
|
<label *ngIf="label">
|
||||||
<span>{{label}}</span>
|
<span [innerHtml]="label"></span>
|
||||||
<icon name="question-circle"
|
<icon name="question-circle"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip"
|
||||||
[title]="tooltip"
|
[title]="tooltip"
|
||||||
|
|||||||
1
packages/uhk-web/src/app/components/svg/constants.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export const SECONDARY_ROLE_BOTTOM_MARGIN = 1;
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
[selectedKey]="selectedKey"
|
[selectedKey]="selectedKey"
|
||||||
[@split]="moduleAnimationStates[i]"
|
[@split]="moduleAnimationStates[i]"
|
||||||
[selected]="selectedKey?.moduleId === i"
|
[selected]="selectedKey?.moduleId === i"
|
||||||
(keyClick)="onKeyClick(i, $event.index, $event.keyTarget)"
|
(keyClick)="onKeyClick(i, $event)"
|
||||||
(keyHover)="onKeyHover($event.index, $event.event, $event.over, i)"
|
(keyHover)="onKeyHover($event.index, $event.event, $event.over, i)"
|
||||||
(capture)="onCapture(i, $event.index, $event.captured)" />
|
(capture)="onCapture(i, $event)" />
|
||||||
|
|
||||||
<svg:path [@fadeSeparator]="separatorAnimation"
|
<svg:path [@fadeSeparator]="separatorAnimation"
|
||||||
[attr.d]="separator.d"
|
[attr.d]="separator.d"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
@@ -7,6 +7,12 @@ import { SvgModule } from '../module';
|
|||||||
import { SvgModuleProviderService } from '../../../services/svg-module-provider.service';
|
import { SvgModuleProviderService } from '../../../services/svg-module-provider.service';
|
||||||
import { KeyboardLayout } from '../../../keyboard/keyboard-layout.enum';
|
import { KeyboardLayout } from '../../../keyboard/keyboard-layout.enum';
|
||||||
import { SvgSeparator } from '../separator';
|
import { SvgSeparator } from '../separator';
|
||||||
|
import {
|
||||||
|
SvgKeyHoverEvent,
|
||||||
|
SvgKeyboardKeyClickEvent,
|
||||||
|
SvgKeyboardCaptureEvent,
|
||||||
|
SvgModuleKeyClickEvent
|
||||||
|
} from '../../../models/svg-key-events';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'svg-keyboard',
|
selector: 'svg-keyboard',
|
||||||
@@ -45,9 +51,9 @@ export class SvgKeyboardComponent implements OnInit {
|
|||||||
@Input() keyboardLayout = KeyboardLayout.ANSI;
|
@Input() keyboardLayout = KeyboardLayout.ANSI;
|
||||||
@Input() description: string;
|
@Input() description: string;
|
||||||
@Input() showDescription = false;
|
@Input() showDescription = false;
|
||||||
@Output() keyClick = new EventEmitter();
|
@Output() keyClick = new EventEmitter<SvgKeyboardKeyClickEvent>();
|
||||||
@Output() keyHover = new EventEmitter();
|
@Output() keyHover = new EventEmitter<SvgKeyHoverEvent>();
|
||||||
@Output() capture = new EventEmitter();
|
@Output() capture = new EventEmitter<SvgKeyboardCaptureEvent>();
|
||||||
@Output() descriptionChanged = new EventEmitter<string>();
|
@Output() descriptionChanged = new EventEmitter<string>();
|
||||||
|
|
||||||
modules: SvgModule[];
|
modules: SvgModule[];
|
||||||
@@ -79,19 +85,17 @@ export class SvgKeyboardComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeyClick(moduleId: number, keyId: number, keyTarget: HTMLElement): void {
|
onKeyClick(moduleId: number, event: SvgModuleKeyClickEvent): void {
|
||||||
this.keyClick.emit({
|
this.keyClick.emit({
|
||||||
moduleId,
|
...event,
|
||||||
keyId,
|
moduleId
|
||||||
keyTarget
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onCapture(moduleId: number, keyId: number, captured: { code: number, left: boolean[], right: boolean[] }): void {
|
onCapture(moduleId: number, event: SvgKeyboardCaptureEvent): void {
|
||||||
this.capture.emit({
|
this.capture.emit({
|
||||||
moduleId,
|
...event,
|
||||||
keyId,
|
moduleId
|
||||||
captured
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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 |
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 |
@@ -26,6 +26,9 @@ 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 { OperatingSystem } from '../../../../models/operating-system';
|
||||||
|
import { KeyModifierModel } from '../../../../models/key-modifier-model';
|
||||||
|
|
||||||
enum LabelTypes {
|
enum LabelTypes {
|
||||||
KeystrokeKey,
|
KeystrokeKey,
|
||||||
@@ -82,8 +85,8 @@ export class SvgKeyboardKeyComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
@Input() capturingEnabled: boolean;
|
@Input() capturingEnabled: boolean;
|
||||||
@Input() active: boolean;
|
@Input() active: boolean;
|
||||||
|
|
||||||
@Output() keyClick = new EventEmitter();
|
@Output() keyClick = new EventEmitter<SvgKeyClickEvent>();
|
||||||
@Output() capture = new EventEmitter();
|
@Output() capture = new EventEmitter<SvgKeyCaptureEvent>();
|
||||||
|
|
||||||
enumLabelTypes = LabelTypes;
|
enumLabelTypes = LabelTypes;
|
||||||
|
|
||||||
@@ -93,9 +96,14 @@ 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;
|
||||||
|
private pressedShiftLocation = -1;
|
||||||
|
private pressedAltLocation = -1;
|
||||||
|
private altPressed = false;
|
||||||
|
private shiftPressed = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private mapper: MapperService,
|
private mapper: MapperService,
|
||||||
@@ -112,15 +120,21 @@ 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.element.nativeElement);
|
this.keyClick.emit({
|
||||||
|
keyTarget: this.element.nativeElement,
|
||||||
|
shiftPressed: e.shiftKey,
|
||||||
|
altPressed: e.altKey
|
||||||
|
});
|
||||||
|
this.pressedShiftLocation = -1;
|
||||||
|
this.pressedAltLocation = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@HostListener('mousedown', ['$event'])
|
@HostListener('mousedown', ['$event'])
|
||||||
onMouseDown(e: MouseEvent) {
|
onMouseDown(e: MouseEvent) {
|
||||||
if ((e.which === 2 || e.button === 1) && this.capturingEnabled) {
|
if ((e.which === 2 || e.button === 2) && this.capturingEnabled) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.renderer.invokeElementMethod(this.element.nativeElement, 'focus');
|
this.renderer.invokeElementMethod(this.element.nativeElement, 'focus');
|
||||||
|
|
||||||
@@ -129,13 +143,23 @@ 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;
|
||||||
|
this.altPressed = e.altKey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@HostListener('keyup', ['$event'])
|
@HostListener('document:keyup', ['$event'])
|
||||||
onKeyUp(e: KeyboardEvent) {
|
onKeyUp(e: KeyboardEvent) {
|
||||||
if (this.scanCodePressed) {
|
if (e.keyCode === 18 && this.pressedAltLocation > -1) {
|
||||||
|
this.pressedAltLocation = -1;
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
else if (e.keyCode === 16 && this.pressedShiftLocation > -1) {
|
||||||
|
this.pressedShiftLocation = -1;
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
else if (this.scanCodePressed) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.scanCodePressed = false;
|
this.scanCodePressed = false;
|
||||||
} else if (this.recording) {
|
} else if (this.recording) {
|
||||||
@@ -144,7 +168,7 @@ export class SvgKeyboardKeyComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@HostListener('keydown', ['$event'])
|
@HostListener('document:keydown', ['$event'])
|
||||||
onKeyDown(e: KeyboardEvent) {
|
onKeyDown(e: KeyboardEvent) {
|
||||||
const code: number = e.keyCode;
|
const code: number = e.keyCode;
|
||||||
|
|
||||||
@@ -152,11 +176,29 @@ export class SvgKeyboardKeyComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if (this.captureService.hasMap(code)) {
|
if (this.captureService.hasMap(code)) {
|
||||||
|
// If the Alt or Shift key not released after start the capturing
|
||||||
|
// then add them as a modifier
|
||||||
|
if (this.pressedShiftLocation > -1) {
|
||||||
|
this.captureService.setModifier((this.pressedShiftLocation === 1), 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.pressedAltLocation > -1) {
|
||||||
|
this.captureService.setModifier((this.pressedAltLocation === 1), 18);
|
||||||
|
}
|
||||||
|
|
||||||
this.saveScanCode(this.captureService.getMap(code));
|
this.saveScanCode(this.captureService.getMap(code));
|
||||||
this.scanCodePressed = true;
|
this.scanCodePressed = true;
|
||||||
} else {
|
} else {
|
||||||
this.captureService.setModifier((e.location === 1), code);
|
this.captureService.setModifier((e.location === 1), code);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (e.keyCode === 16) {
|
||||||
|
this.pressedShiftLocation = e.location;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.keyCode === 18) {
|
||||||
|
this.pressedAltLocation = e.location;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,36 +240,40 @@ export class SvgKeyboardKeyComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
this.recording = false;
|
this.recording = false;
|
||||||
this.changeAnimation = 'inactive';
|
this.changeAnimation = 'inactive';
|
||||||
this.captureService.initModifiers();
|
this.captureService.initModifiers();
|
||||||
|
this.shiftPressed = false;
|
||||||
|
this.altPressed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private saveScanCode(code = 0) {
|
private saveScanCode(code = 0) {
|
||||||
this.recording = false;
|
const left: KeyModifierModel[] = this.captureService.getModifiers(true);
|
||||||
this.changeAnimation = 'inactive';
|
const right: KeyModifierModel[] = this.captureService.getModifiers(false);
|
||||||
|
|
||||||
const left: boolean[] = this.captureService.getModifiers(true);
|
|
||||||
const right: boolean[] = this.captureService.getModifiers(false);
|
|
||||||
|
|
||||||
this.capture.emit({
|
this.capture.emit({
|
||||||
code,
|
captured: {
|
||||||
left,
|
code,
|
||||||
right
|
left,
|
||||||
|
right
|
||||||
|
},
|
||||||
|
shiftPressed: this.shiftPressed,
|
||||||
|
altPressed: this.altPressed
|
||||||
});
|
});
|
||||||
|
|
||||||
this.captureService.initModifiers();
|
this.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
@@ -245,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;
|
||||||
|
|||||||
@@ -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 |
@@ -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);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 |
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from './svg-secondary-role.component';
|
||||||
@@ -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 |
@@ -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)`;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 |
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 |
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 |
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3
packages/uhk-web/src/app/components/svg/keys/util.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export const isRectangleAsSecondaryRoleKey = (width: number, height: number): boolean => {
|
||||||
|
return width > height * 2.4;
|
||||||
|
};
|
||||||
@@ -2,6 +2,12 @@ import { Component, EventEmitter, Input, Output, ChangeDetectionStrategy } from
|
|||||||
import { KeyAction } from 'uhk-common';
|
import { KeyAction } from 'uhk-common';
|
||||||
|
|
||||||
import { SvgKeyboardKey } from '../keys';
|
import { SvgKeyboardKey } from '../keys';
|
||||||
|
import {
|
||||||
|
SvgKeyCaptureEvent,
|
||||||
|
SvgKeyClickEvent,
|
||||||
|
SvgModuleCaptureEvent,
|
||||||
|
SvgModuleKeyClickEvent
|
||||||
|
} from '../../../models/svg-key-events';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'g[svg-module]',
|
selector: 'g[svg-module]',
|
||||||
@@ -17,18 +23,18 @@ export class SvgModuleComponent {
|
|||||||
@Input() selected: boolean;
|
@Input() selected: boolean;
|
||||||
@Input() keybindAnimationEnabled: boolean;
|
@Input() keybindAnimationEnabled: boolean;
|
||||||
@Input() capturingEnabled: boolean;
|
@Input() capturingEnabled: boolean;
|
||||||
@Output() keyClick = new EventEmitter();
|
@Output() keyClick = new EventEmitter<SvgModuleKeyClickEvent>();
|
||||||
@Output() keyHover = new EventEmitter();
|
@Output() keyHover = new EventEmitter();
|
||||||
@Output() capture = new EventEmitter();
|
@Output() capture = new EventEmitter<SvgModuleCaptureEvent>();
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.keyboardKeys = [];
|
this.keyboardKeys = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeyClick(index: number, keyTarget: HTMLElement): void {
|
onKeyClick(keyId: number, event: SvgKeyClickEvent): void {
|
||||||
this.keyClick.emit({
|
this.keyClick.emit({
|
||||||
index,
|
...event,
|
||||||
keyTarget
|
keyId
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,10 +46,10 @@ export class SvgModuleComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onCapture(index: number, captured: {code: number, left: boolean[], right: boolean[]}) {
|
onCapture(keyId: number, event: SvgKeyCaptureEvent) {
|
||||||
this.capture.emit({
|
this.capture.emit({
|
||||||
index,
|
...event,
|
||||||
captured
|
keyId
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,9 @@
|
|||||||
[halvesSplit]="halvesSplit"
|
[halvesSplit]="halvesSplit"
|
||||||
[keyboardLayout]="keyboardLayout"
|
[keyboardLayout]="keyboardLayout"
|
||||||
[description]="keymap.description"
|
[description]="keymap.description"
|
||||||
(keyClick)="onKeyClick($event.moduleId, $event.keyId, $event.keyTarget)"
|
(keyClick)="onKeyClick($event)"
|
||||||
(keyHover)="onKeyHover($event.moduleId, $event.event, $event.over, $event.keyId)"
|
(keyHover)="onKeyHover($event)"
|
||||||
(capture)="onCapture($event.moduleId, $event.keyId, $event.captured)"
|
(capture)="onCapture($event)"
|
||||||
(descriptionChanged)="onDescriptionChanged($event)"
|
(descriptionChanged)="onDescriptionChanged($event)"
|
||||||
></keyboard-slider>
|
></keyboard-slider>
|
||||||
|
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
[currentKeymap]="keymap"
|
[currentKeymap]="keymap"
|
||||||
[currentLayer]="currentLayer"
|
[currentLayer]="currentLayer"
|
||||||
[allowLayerDoubleTap]="allowLayerDoubleTap"
|
[allowLayerDoubleTap]="allowLayerDoubleTap"
|
||||||
|
[remapInfo]="remapInfo"
|
||||||
(cancel)="hidePopover()"
|
(cancel)="hidePopover()"
|
||||||
(remap)="onRemap($event)"></popover>
|
(remap)="onRemap($event)"></popover>
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,13 @@ import { PopoverComponent } from '../../popover';
|
|||||||
import { KeyboardLayout } from '../../../keyboard/keyboard-layout.enum';
|
import { KeyboardLayout } from '../../../keyboard/keyboard-layout.enum';
|
||||||
import { ChangeKeymapDescription } from '../../../models/ChangeKeymapDescription';
|
import { ChangeKeymapDescription } from '../../../models/ChangeKeymapDescription';
|
||||||
import { KeyActionRemap } from '../../../models/key-action-remap';
|
import { KeyActionRemap } from '../../../models/key-action-remap';
|
||||||
|
import {
|
||||||
|
SvgKeyboardCaptureEvent,
|
||||||
|
SvgKeyboardKeyClickEvent,
|
||||||
|
SvgKeyHoverEvent
|
||||||
|
} from '../../../models/svg-key-events';
|
||||||
|
import { RemapInfo } from '../../../models/remap-info';
|
||||||
|
import { mapLeftRigthModifierToKeyActionModifier } from '../../../util';
|
||||||
|
|
||||||
interface NameValuePair {
|
interface NameValuePair {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -65,7 +72,7 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges {
|
|||||||
|
|
||||||
@Output() descriptionChanged = new EventEmitter<ChangeKeymapDescription>();
|
@Output() descriptionChanged = new EventEmitter<ChangeKeymapDescription>();
|
||||||
|
|
||||||
@ViewChild(PopoverComponent, { read: ElementRef }) popover: ElementRef;
|
@ViewChild(PopoverComponent, {read: ElementRef}) popover: ElementRef;
|
||||||
|
|
||||||
popoverShown: boolean;
|
popoverShown: boolean;
|
||||||
keyEditConfig: { moduleId: number, keyId: number };
|
keyEditConfig: { moduleId: number, keyId: number };
|
||||||
@@ -82,6 +89,11 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges {
|
|||||||
layers: Layer[];
|
layers: Layer[];
|
||||||
keyPosition: ClientRect;
|
keyPosition: ClientRect;
|
||||||
wrapPosition: ClientRect;
|
wrapPosition: ClientRect;
|
||||||
|
remapInfo: RemapInfo = {
|
||||||
|
remapOnAllKeymap: false,
|
||||||
|
remapOnAllLayer: false
|
||||||
|
};
|
||||||
|
|
||||||
private wrapHost: HTMLElement;
|
private wrapHost: HTMLElement;
|
||||||
private keyElement: HTMLElement;
|
private keyElement: HTMLElement;
|
||||||
|
|
||||||
@@ -131,7 +143,6 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges {
|
|||||||
this.layers = this.keymap.layers;
|
this.layers = this.keymap.layers;
|
||||||
if (keymapChanges.isFirstChange() ||
|
if (keymapChanges.isFirstChange() ||
|
||||||
keymapChanges.previousValue.abbreviation !== keymapChanges.currentValue.abbreviation) {
|
keymapChanges.previousValue.abbreviation !== keymapChanges.currentValue.abbreviation) {
|
||||||
this.currentLayer = 0;
|
|
||||||
this.keybindAnimationEnabled = keymapChanges.isFirstChange();
|
this.keybindAnimationEnabled = keymapChanges.isFirstChange();
|
||||||
} else {
|
} else {
|
||||||
this.keybindAnimationEnabled = true;
|
this.keybindAnimationEnabled = true;
|
||||||
@@ -140,51 +151,50 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeyClick(moduleId: number, keyId: number, keyTarget: HTMLElement): void {
|
onKeyClick(event: SvgKeyboardKeyClickEvent): void {
|
||||||
if (!this.popoverShown && this.popoverEnabled) {
|
if (!this.popoverShown && this.popoverEnabled) {
|
||||||
this.keyEditConfig = {
|
this.keyEditConfig = {
|
||||||
moduleId,
|
moduleId: event.moduleId,
|
||||||
keyId
|
keyId: event.keyId
|
||||||
|
};
|
||||||
|
this.selectedKey = {layerId: this.currentLayer, moduleId: event.moduleId, keyId: event.keyId};
|
||||||
|
const keyActionToEdit: KeyAction = this.layers[this.currentLayer].modules[event.moduleId].keyActions[event.keyId];
|
||||||
|
this.keyElement = event.keyTarget;
|
||||||
|
this.remapInfo = {
|
||||||
|
remapOnAllKeymap: event.shiftPressed,
|
||||||
|
remapOnAllLayer: event.altPressed
|
||||||
};
|
};
|
||||||
this.selectedKey = { layerId: this.currentLayer, moduleId, keyId };
|
|
||||||
const keyActionToEdit: KeyAction = this.layers[this.currentLayer].modules[moduleId].keyActions[keyId];
|
|
||||||
this.keyElement = keyTarget;
|
|
||||||
this.showPopover(keyActionToEdit);
|
this.showPopover(keyActionToEdit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeyHover(moduleId: number, event: MouseEvent, over: boolean, keyId: number): void {
|
onKeyHover(event: SvgKeyHoverEvent): void {
|
||||||
if (this.tooltipEnabled) {
|
if (this.tooltipEnabled) {
|
||||||
const keyActionToEdit: KeyAction = this.layers[this.currentLayer].modules[moduleId].keyActions[keyId];
|
const keyActionToEdit: KeyAction = this.layers[this.currentLayer].modules[event.moduleId].keyActions[event.keyId];
|
||||||
|
|
||||||
if (over) {
|
if (event.over) {
|
||||||
this.showTooltip(keyActionToEdit, event);
|
this.showTooltip(keyActionToEdit, event.event);
|
||||||
} else {
|
} else {
|
||||||
this.hideTooltip();
|
this.hideTooltip();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onCapture(moduleId: number, keyId: number, captured: { code: number, left: boolean[], right: boolean[] }): void {
|
onCapture(event: SvgKeyboardCaptureEvent): void {
|
||||||
const keystrokeAction: KeystrokeAction = new KeystrokeAction();
|
const keystrokeAction: KeystrokeAction = new KeystrokeAction();
|
||||||
const modifiers = captured.left.concat(captured.right).map(x => x ? 1 : 0);
|
|
||||||
|
|
||||||
keystrokeAction.scancode = 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(
|
||||||
this.keymap,
|
this.keymap,
|
||||||
this.currentLayer,
|
this.currentLayer,
|
||||||
moduleId,
|
event.moduleId,
|
||||||
keyId,
|
event.keyId,
|
||||||
{
|
{
|
||||||
remapOnAllKeymap: false,
|
remapOnAllKeymap: event.shiftPressed,
|
||||||
remapOnAllLayer: false,
|
remapOnAllLayer: event.altPressed,
|
||||||
action: keystrokeAction
|
action: keystrokeAction
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { Directive, ElementRef, HostListener } from '@angular/core';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
|
||||||
|
import { AppState } from '../../store';
|
||||||
|
import { OpenUrlInNewWindowAction } from '../../store/actions/app';
|
||||||
|
|
||||||
|
@Directive({
|
||||||
|
selector: 'a[externalUrl]'
|
||||||
|
})
|
||||||
|
export class ExternalUrlDirective {
|
||||||
|
constructor(private el: ElementRef,
|
||||||
|
private store: Store<AppState>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@HostListener('click', ['$event'])
|
||||||
|
onClick($event: MouseEvent): void {
|
||||||
|
$event.preventDefault();
|
||||||
|
$event.stopPropagation();
|
||||||
|
|
||||||
|
const anchor = this.el.nativeElement as HTMLAnchorElement;
|
||||||
|
if (anchor.href) {
|
||||||
|
this.store.dispatch(new OpenUrlInNewWindowAction(anchor.href));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from './external-url.directive';
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
export * from './cancelable';
|
export * from './cancelable';
|
||||||
export * from './tooltip';
|
export * from './tooltip';
|
||||||
|
export * from './external-url';
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
///<reference path="../../../../node_modules/@types/jquery/index.d.ts"/>
|
||||||
import { AfterContentInit, Directive, ElementRef, HostBinding, Input, OnChanges, SimpleChanges } from '@angular/core';
|
import { AfterContentInit, Directive, ElementRef, HostBinding, Input, OnChanges, SimpleChanges } from '@angular/core';
|
||||||
import { DomSanitizer } from '@angular/platform-browser';
|
import { DomSanitizer } from '@angular/platform-browser';
|
||||||
|
|
||||||
|
|||||||
7
packages/uhk-web/src/app/models/key-modifier-model.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { KeyModifiers } from 'uhk-common';
|
||||||
|
|
||||||
|
export interface KeyModifierModel {
|
||||||
|
text: string;
|
||||||
|
value: KeyModifiers;
|
||||||
|
checked: boolean;
|
||||||
|
}
|
||||||
5
packages/uhk-web/src/app/models/operating-system.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export enum OperatingSystem {
|
||||||
|
Linux,
|
||||||
|
Mac,
|
||||||
|
Windows
|
||||||
|
}
|
||||||
4
packages/uhk-web/src/app/models/remap-info.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export interface RemapInfo {
|
||||||
|
remapOnAllKeymap: boolean;
|
||||||
|
remapOnAllLayer: boolean;
|
||||||
|
}
|
||||||
7
packages/uhk-web/src/app/models/select-option-data.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export interface SelectOptionData {
|
||||||
|
id: string;
|
||||||
|
text: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
children?: Array<SelectOptionData>;
|
||||||
|
additional?: any;
|
||||||
|
}
|
||||||
44
packages/uhk-web/src/app/models/svg-key-events.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import { KeyModifierModel } from './key-modifier-model';
|
||||||
|
|
||||||
|
export interface SvgKeyClickEvent {
|
||||||
|
keyTarget: HTMLElement;
|
||||||
|
shiftPressed?: boolean;
|
||||||
|
altPressed?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SvgModuleKeyClickEvent extends SvgKeyClickEvent {
|
||||||
|
keyId: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SvgKeyboardKeyClickEvent extends SvgModuleKeyClickEvent {
|
||||||
|
moduleId: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface KeyCaptureData {
|
||||||
|
code: number;
|
||||||
|
left: KeyModifierModel[];
|
||||||
|
right: KeyModifierModel[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SvgKeyCaptureEvent {
|
||||||
|
captured: KeyCaptureData;
|
||||||
|
shiftPressed?: boolean;
|
||||||
|
altPressed?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SvgModuleCaptureEvent extends SvgKeyCaptureEvent {
|
||||||
|
keyId: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SvgKeyboardCaptureEvent extends SvgModuleCaptureEvent {
|
||||||
|
moduleId: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SvgKeyHoverEvent {
|
||||||
|
keyId: number;
|
||||||
|
event: MouseEvent;
|
||||||
|
over: boolean;
|
||||||
|
moduleId: number;
|
||||||
|
shiftPressed?: boolean;
|
||||||
|
altPressed?: boolean;
|
||||||
|
}
|
||||||