Compare commits
132 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e294727ac5 | ||
|
|
f29d64c803 | ||
|
|
0385b0ce29 | ||
|
|
b526274cd7 | ||
|
|
88c16af4a9 | ||
|
|
05ac9a6832 | ||
|
|
04aa5236c2 | ||
|
|
ec98e4e1c6 | ||
|
|
bb9ece494c | ||
|
|
217e6776ac | ||
|
|
2286218980 | ||
|
|
3d9c83f9f4 | ||
|
|
14ed163238 | ||
|
|
c815de0718 | ||
|
|
6a46556d9e | ||
|
|
f8f820529f | ||
|
|
cac11155e7 | ||
|
|
d20870f11e | ||
|
|
10ceb6c79d | ||
|
|
b38b6fa294 | ||
|
|
94c1d35429 | ||
|
|
e33cef4e89 | ||
|
|
9b815ed9c1 | ||
|
|
1d4bb6113c | ||
|
|
136120b831 | ||
|
|
cd299c06d6 | ||
|
|
e152a36ad7 | ||
|
|
e90544db33 | ||
|
|
7ceca202b4 | ||
|
|
ddc65aa54b | ||
|
|
13ec617d58 | ||
|
|
00c5b69129 | ||
|
|
6ccf005750 | ||
|
|
6e1f0ded9e | ||
|
|
d58386ef4b | ||
|
|
179c982bfb | ||
|
|
a7d07dbf4c | ||
|
|
0ca922d24a | ||
|
|
a6f1aa15a5 | ||
|
|
fc2d025cc4 | ||
|
|
8b5ae106bd | ||
|
|
44639bbf53 | ||
|
|
9fcce9234a | ||
|
|
b26fecfc7a | ||
|
|
1b15911783 | ||
|
|
148dd8d361 | ||
|
|
0d9ac50999 | ||
|
|
e19e4bc5a4 | ||
|
|
bdd79a5a9a | ||
|
|
fb4e05fdc4 | ||
|
|
01fcf9053a | ||
|
|
533c2f13d2 | ||
|
|
b9c32b46a9 | ||
|
|
f9b7260be6 | ||
|
|
847694d590 | ||
|
|
58178a5c7b | ||
|
|
9b93b4dac5 | ||
|
|
478dac0621 | ||
|
|
f196fcdaa2 | ||
|
|
0b420ff516 | ||
|
|
7656af76e4 | ||
|
|
beed546ae4 | ||
|
|
bf94370f2f | ||
|
|
2476049681 | ||
|
|
f8d8b6d213 | ||
|
|
05bbce1d50 | ||
|
|
32494fa228 | ||
|
|
e0ce38988e | ||
|
|
5c660c549d | ||
|
|
510b914e26 | ||
|
|
cf64fc0c08 | ||
|
|
b25bc9d81d | ||
|
|
2f00a5eaf4 | ||
|
|
e8fe0f8d3e | ||
|
|
e84dbf2c15 | ||
|
|
990ff8e980 | ||
|
|
1ca8e67e52 | ||
|
|
23cb583bf7 | ||
|
|
d5cc735b85 | ||
|
|
1981311136 | ||
|
|
bbb5d4a35b | ||
|
|
58ef40fb02 | ||
|
|
b8f35df155 | ||
|
|
c3e712851c | ||
|
|
2eaa1e0634 | ||
|
|
6ee21bcd7a | ||
|
|
10ae68ad4b | ||
|
|
02044ae1d0 | ||
|
|
3f99d47bba | ||
|
|
9beadb4aac | ||
|
|
d9fb7a4b42 | ||
|
|
83912ec21f | ||
|
|
6c7232a5ba | ||
|
|
65fc8b5efb | ||
|
|
7a64191955 | ||
|
|
1a413c824e | ||
|
|
e545c9d67b | ||
|
|
8650fef7ae | ||
|
|
5c618869a2 | ||
|
|
1b8d6949e0 | ||
|
|
aabc0a8746 | ||
|
|
9589398834 | ||
|
|
933a715ea5 | ||
|
|
df14e2d569 | ||
|
|
4f8a0247d3 | ||
|
|
85ec5f6b6a | ||
|
|
739b830f47 | ||
|
|
482cff3d3b | ||
|
|
9284ae5032 | ||
|
|
cac6fdc190 | ||
|
|
ca9bf60a1b | ||
|
|
bb7edb8e4d | ||
|
|
0d9c976eb8 | ||
|
|
288d4f75b6 | ||
|
|
73e07eae2d | ||
|
|
8e620caac5 | ||
|
|
0d4e1acf76 | ||
|
|
88c42d58b1 | ||
|
|
5099e904fc | ||
|
|
5476f7c3a5 | ||
|
|
e0bb0bcca3 | ||
|
|
124c3ec29b | ||
|
|
2310320b8a | ||
|
|
67346b4cda | ||
|
|
662ca0152f | ||
|
|
6358528438 | ||
|
|
02f1053d46 | ||
|
|
a44a7dc5f8 | ||
|
|
02d57fdabf | ||
|
|
38f6688930 | ||
|
|
6ca12d0ccd | ||
|
|
acd17ac657 |
@@ -11,7 +11,7 @@ matrix:
|
|||||||
fast_finish: true
|
fast_finish: true
|
||||||
include:
|
include:
|
||||||
- os: osx
|
- os: osx
|
||||||
osx_image: xcode8.3
|
osx_image: xcode9.3beta
|
||||||
- os: linux
|
- os: linux
|
||||||
env: CC=clang CXX=clang++ npm_config_clang=1
|
env: CC=clang CXX=clang++ npm_config_clang=1
|
||||||
compiler: clang
|
compiler: clang
|
||||||
@@ -45,7 +45,6 @@ addons:
|
|||||||
|
|
||||||
install:
|
install:
|
||||||
- nvm install
|
- nvm install
|
||||||
- npm i -g npm@5.6.0
|
|
||||||
- npm install
|
- npm install
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
|
|||||||
70
CHANGELOG.md
@@ -4,9 +4,75 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
The format is loosely based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
|
The format is loosely based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
## [1.1.0] - 2017-01-15
|
Every Agent version includes the most recent firmware version. See the [firmware changelog](https://github.com/UltimateHackingKeyboard/firmware/blob/master/CHANGELOG.md).
|
||||||
|
|
||||||
Firmware: 8.**1**.0 [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.1.0)] | Device Protocol: 4.2.0 | User Config: 4.0.0 | Hardware Config: 1.0.0
|
## [1.2.1] - 2018-05-12
|
||||||
|
|
||||||
|
Firmware: 8.2.**2** [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.2.2)] | Device Protocol: 4.3.0| User Config: 4.0.**1** | Hardware Config: 1.0.0
|
||||||
|
|
||||||
|
- Match for the new USB usage page and usage number. This is critical for UHKs flashed with firmware >=8.2.2 to be recognized by Agent on OSX.
|
||||||
|
- Make the config serializer handle long media macro actions. `USERCONFIG:PATCH`
|
||||||
|
- Add note on the macro page explaining that the macro engine of the firmware is not ready yet.
|
||||||
|
- Add an example to the scancode tooltip to better explain users how to invoke non-US characters.
|
||||||
|
|
||||||
|
## [1.2.0] - 2018-04-20
|
||||||
|
|
||||||
|
Firmware: 8.**2.0** [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.2.0)] | Device Protocol: 4.**3.0** | User Config: 4.0.0 | Hardware Config: 1.0.0
|
||||||
|
|
||||||
|
- Tweak the default mouse speed. This was necessary because the last firmware version adjusted speed multipliers. The mouse speed can be reset via the "Reset speeds to default" button of the "Mouse speed" page.
|
||||||
|
- Make the newly added switch-keymap.js script utilize the new UsbCommandId_SwitchKeymap, allowing for programmatic keymap switching. `DEVICEPROTOCOL:MINOR`
|
||||||
|
|
||||||
|
## [1.1.5] - 2018-04-10
|
||||||
|
|
||||||
|
Firmware: 8.1.5 [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.1.5)] | Device Protocol: 4.2.0 | User Config: 4.0.0 | Hardware Config: 1.0.0
|
||||||
|
|
||||||
|
- Don't allow to run multiple instances of Agent at the same time, but rather focus the already existing Agent window.
|
||||||
|
|
||||||
|
## [1.1.4] - 2018-04-09
|
||||||
|
|
||||||
|
Firmware: 8.1.5 [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.1.5)] | Device Protocol: 4.2.0 | User Config: 4.0.0 | Hardware Config: 1.0.0
|
||||||
|
|
||||||
|
- Handle privilege escalation gracefully on Linux even without PolicyKit.
|
||||||
|
- Fix application icon path.
|
||||||
|
- Replace application icon with a diagonal gradient based icon that should look better on desktop.
|
||||||
|
- Make saving the configuration more robust, and add a configuration recovery screen.
|
||||||
|
- Reposition the ISO key in the scancode list.
|
||||||
|
|
||||||
|
## [1.1.3] - 2018-04-06
|
||||||
|
|
||||||
|
Firmware: 8.1.**5** [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.1.5)] | Device Protocol: 4.2.0 | User Config: 4.0.0 | Hardware Config: 1.0.0
|
||||||
|
|
||||||
|
- Show the firmware versions of the left and right keyboard halves on the firmware page.
|
||||||
|
- Fix menu scancode.
|
||||||
|
- Make the tooltip text regarding non-US characters easier to understand.
|
||||||
|
- On the Device Configuration page change terminology from download/upload to export/import for greater clarity.
|
||||||
|
|
||||||
|
## [1.1.2] - 2018-03-09
|
||||||
|
|
||||||
|
Firmware: 8.1.**4** [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.1.4)] | Device Protocol: 4.2.0 | User Config: 4.0.0 | Hardware Config: 1.0.0
|
||||||
|
|
||||||
|
- Fix the configuration serializer so that the correct key actions get serialized, and the save button always appears when needed.
|
||||||
|
- Add instructions to the firmware page to aid users.
|
||||||
|
- Fix code signing on OSX.
|
||||||
|
- Sign Agent on Windows.
|
||||||
|
|
||||||
|
## [1.1.1] - 2018-02-13
|
||||||
|
|
||||||
|
Firmware: 8.1.**2** [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.1.2)] | Device Protocol: 4.2.0 | User Config: 4.0.0 | Hardware Config: 1.0.0
|
||||||
|
|
||||||
|
- Sign Agent on OSX resulting in easier installation.
|
||||||
|
- Add per-keymap description field.
|
||||||
|
- Sort keymaps and macros alphabetically within the key action popover.
|
||||||
|
- Add tooltip regarding non-US scancodes.
|
||||||
|
- When deleting a macro, also delete the relevant play macro actions.
|
||||||
|
- Make the reset configuration button persist the reset configuration in Agent-web.
|
||||||
|
- Make Agent able to unbrick bricked modules.
|
||||||
|
- Assign "switch to test keymap" action on all keymaps in the default configuration.
|
||||||
|
- Add keymap descriptions in the default configuration.
|
||||||
|
|
||||||
|
## [1.1.0] - 2018-01-15
|
||||||
|
|
||||||
|
Firmware: 8.**1**.0 [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.1.0)] | Device Protocol: 4.**2.0** | User Config: 4.0.0 | Hardware Config: 1.0.0
|
||||||
|
|
||||||
- Only accept device, keymap, and macro names upon editing if their trimmed length is non-zero.
|
- Only accept device, keymap, and macro names upon editing if their trimmed length is non-zero.
|
||||||
- Add diagnostics USB scripts, most notably /packages/usb/{get-i2c-health,set-i2c-baud-rate}.js, some utilizing new device protocol commands and properties. `DEVICEPROTOCOL:MINOR`
|
- Add diagnostics USB scripts, most notably /packages/usb/{get-i2c-health,set-i2c-baud-rate}.js, some utilizing new device protocol commands and properties. `DEVICEPROTOCOL:MINOR`
|
||||||
|
|||||||
19
README.md
@@ -5,17 +5,8 @@
|
|||||||
|
|
||||||
Agent is the configuration application of the [Ultimate Hacking Keyboard](https://ultimatehackingkeyboard.com/).
|
Agent is the configuration application of the [Ultimate Hacking Keyboard](https://ultimatehackingkeyboard.com/).
|
||||||
|
|
||||||
[Give it a whirl!](http://ultimatehackingkeyboard.github.io/agent/)
|
* Try out the [web build of Agent](http://ultimatehackingkeyboard.github.io/agent/) in your browser. This is meant to be used for demonstration purposes.
|
||||||
|
* Download the [desktop build of Agent](https://github.com/UltimateHackingKeyboard/agent/releases) from our releases page. Use this if you have an actual UHK at hand, or else you won't get past the opening screen!
|
||||||
## Two builds to rule them all
|
|
||||||
|
|
||||||
It's worth mentioning that Agent has two builds.
|
|
||||||
|
|
||||||
The **electron build** is the desktop application which is meant to be used if you have an actual UHK at hand. It starts with an opening screen which detects your UHK. You cannot get past this screen without connecting a UHK via USB.
|
|
||||||
|
|
||||||
The **web build** is meant to be used for demonstration purposes, so people who don't yet own a UHK can get a feel of Agent and its capabilities in their browser. Eventually, WebUSB support will be added to the web build, making it able to communicate with the UHK. Given the sandboxed nature of browsers, the web build will always lack features that the electron build offers, so this won't make the electron build obsolete.
|
|
||||||
|
|
||||||
The two builds share code as much as possible.
|
|
||||||
|
|
||||||
## Building the electron application
|
## Building the electron application
|
||||||
|
|
||||||
@@ -33,9 +24,9 @@ For everyone else, use the appropriate package manager for your OS.
|
|||||||
```
|
```
|
||||||
git clone git@github.com:UltimateHackingKeyboard/agent.git
|
git clone git@github.com:UltimateHackingKeyboard/agent.git
|
||||||
cd agent
|
cd agent
|
||||||
npm install # to install Node dependencies
|
npm install
|
||||||
npm run build:electron # to build the agent
|
npm run build
|
||||||
npm run electron # to run the newly built agent
|
npm run electron
|
||||||
```
|
```
|
||||||
|
|
||||||
At this point, Agent should be running on your machine.
|
At this point, Agent should be running on your machine.
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
os: unstable
|
os: unstable
|
||||||
|
|
||||||
|
clone_folder: c:\projects\uhk-agent
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
GH_TOKEN:
|
GH_TOKEN:
|
||||||
secure: 3IebpEKmC39codi1wT6dXx8mql4/mCL1JzZ7lir7GQ5MWRnCxlED2OXbiKHHigDV
|
secure: 3IebpEKmC39codi1wT6dXx8mql4/mCL1JzZ7lir7GQ5MWRnCxlED2OXbiKHHigDV
|
||||||
|
CSC_LINK: c:\projects\uhk-agent\scripts\certs\windows-cert.p12
|
||||||
matrix:
|
matrix:
|
||||||
- nodejs_version: "8"
|
- nodejs_version: "8"
|
||||||
|
|
||||||
@@ -18,7 +21,6 @@ shallow_clone: true
|
|||||||
|
|
||||||
install:
|
install:
|
||||||
- ps: Install-Product node $env:nodejs_version
|
- ps: Install-Product node $env:nodejs_version
|
||||||
- npm i -g npm@5.6.0
|
|
||||||
- choco install chromium
|
- choco install chromium
|
||||||
- set CI=true
|
- set CI=true
|
||||||
- set PATH=%APPDATA%\npm;%PATH%
|
- set PATH=%APPDATA%\npm;%PATH%
|
||||||
|
|||||||
BIN
build/icon.icns
BIN
build/icon.ico
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 127 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 392 B After Width: | Height: | Size: 499 B |
|
Before Width: | Height: | Size: 546 B After Width: | Height: | Size: 735 B |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 660 B After Width: | Height: | Size: 913 B |
|
Before Width: | Height: | Size: 966 B After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.7 KiB |
4681
package-lock.json
generated
56
package.json
@@ -3,10 +3,10 @@
|
|||||||
"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.1.0",
|
"version": "1.2.1",
|
||||||
"firmwareVersion": "8.1.0",
|
"firmwareVersion": "8.2.2",
|
||||||
"deviceProtocolVersion": "4.2.0",
|
"deviceProtocolVersion": "4.3.0",
|
||||||
"userConfigVersion": "4.0.0",
|
"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.",
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -21,8 +21,9 @@
|
|||||||
"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": "4.0.5",
|
"@types/fs-extra": "5.0.1",
|
||||||
"@types/jasmine": "2.6.0",
|
"@types/jasmine": "2.6.0",
|
||||||
|
"@types/jquery": "3.3.1",
|
||||||
"@types/jsonfile": "4.0.1",
|
"@types/jsonfile": "4.0.1",
|
||||||
"@types/node": "8.0.53",
|
"@types/node": "8.0.53",
|
||||||
"@types/node-hid": "0.5.2",
|
"@types/node-hid": "0.5.2",
|
||||||
@@ -30,25 +31,30 @@
|
|||||||
"@types/usb": "1.1.3",
|
"@types/usb": "1.1.3",
|
||||||
"autoprefixer": "6.5.3",
|
"autoprefixer": "6.5.3",
|
||||||
"buffer": "5.0.6",
|
"buffer": "5.0.6",
|
||||||
|
"check-node-version": "^3.2.0",
|
||||||
"copy-webpack-plugin": "4.0.1",
|
"copy-webpack-plugin": "4.0.1",
|
||||||
|
"copyfiles": "^2.0.0",
|
||||||
"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.7.5",
|
"electron": "1.8.4",
|
||||||
"electron-builder": "19.45.5",
|
"electron-builder": "20.8.1",
|
||||||
"electron-debug": "1.4.0",
|
"electron-debug": "1.5.0",
|
||||||
"electron-devtools-installer": "2.2.0",
|
"electron-devtools-installer": "2.2.3",
|
||||||
"electron-log": "2.2.9",
|
"electron-log": "2.2.14",
|
||||||
"electron-rebuild": "1.6.0",
|
"electron-rebuild": "1.7.3",
|
||||||
"electron-settings": "3.1.2",
|
"electron-settings": "3.1.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": "4.0.2",
|
"fs-extra": "5.0.0",
|
||||||
|
"gh-pages": "1.1.0",
|
||||||
"jsonfile": "4.0.0",
|
"jsonfile": "4.0.0",
|
||||||
"lerna": "2.0.0",
|
"lerna": "2.9.0",
|
||||||
"mkdirp": "0.5.1",
|
"mkdirp": "0.5.1",
|
||||||
|
"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.83.0",
|
||||||
@@ -58,9 +64,9 @@
|
|||||||
"svg-sprite": "1.3.7",
|
"svg-sprite": "1.3.7",
|
||||||
"ts-loader": "2.3.1",
|
"ts-loader": "2.3.1",
|
||||||
"ts-node": "3.0.4",
|
"ts-node": "3.0.4",
|
||||||
"tslint": "5.5.0",
|
"tslint": "5.9.1",
|
||||||
"typescript": "2.5.2",
|
"typescript": "2.6.2",
|
||||||
"webpack": "2.4.1"
|
"webpack": "3.10.0"
|
||||||
},
|
},
|
||||||
"pre-commit": [
|
"pre-commit": [
|
||||||
"precommit-msg"
|
"precommit-msg"
|
||||||
@@ -74,12 +80,13 @@
|
|||||||
"test:uhk-web": "lerna exec --scope uhk-web npm test",
|
"test:uhk-web": "lerna exec --scope uhk-web npm test",
|
||||||
"lint": "run-s -scn lint:ts lint:style",
|
"lint": "run-s -scn lint:ts lint:style",
|
||||||
"lint:ts": "run-p -sn lint:ts:electron-main lint:ts:electron-renderer lint:ts:web lint:ts:test-serializer lint:ts:uhk-usb",
|
"lint:ts": "run-p -sn lint:ts:electron-main lint:ts:electron-renderer lint:ts:web lint:ts:test-serializer lint:ts:uhk-usb",
|
||||||
"lint:ts:electron-main": "tslint --type-check --project ./packages/uhk-agent/tsconfig.json",
|
"lint:ts:electron-main": "tslint --project ./packages/uhk-agent/tsconfig.json",
|
||||||
"lint:ts:electron-renderer": "tslint --type-check --project ./packages/uhk-web/src/tsconfig.renderer.json",
|
"lint:ts:electron-renderer": "tslint --project ./packages/uhk-web/src/tsconfig.renderer.json",
|
||||||
"lint:ts:web": "tslint --type-check --project ./packages/uhk-web/src/tsconfig.app.json",
|
"lint:ts:web": "tslint --project ./packages/uhk-web/src/tsconfig.app.json",
|
||||||
"lint:ts:test-serializer": "tslint --type-check --project ./packages/test-serializer/tsconfig.json",
|
"lint:ts:test-serializer": "tslint --project ./packages/test-serializer/tsconfig.json",
|
||||||
"lint:ts:uhk-usb": "tslint --type-check --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",
|
||||||
|
"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",
|
||||||
"build:electron": "cross-env AOT_BUILD=true run-s -sn build:electron:renderer build:electron:main",
|
"build:electron": "cross-env AOT_BUILD=true run-s -sn build:electron:renderer build:electron:main",
|
||||||
@@ -90,11 +97,14 @@
|
|||||||
"server:web": "lerna exec --scope uhk-web npm start",
|
"server:web": "lerna exec --scope uhk-web npm start",
|
||||||
"server:electron": "lerna exec --scope uhk-web npm run server:renderer",
|
"server:electron": "lerna exec --scope uhk-web npm run server:renderer",
|
||||||
"electron": "lerna exec --scope uhk-agent npm start",
|
"electron": "lerna exec --scope uhk-agent npm start",
|
||||||
|
"electron:spe": "lerna exec --scope uhk-agent npm run electron:spe",
|
||||||
"standard-version": "standard-version",
|
"standard-version": "standard-version",
|
||||||
"pack": "node ./scripts/release.js",
|
"pack": "node ./scripts/release.js",
|
||||||
"sprites": "node ./scripts/generate-svg-sprites",
|
"sprites": "node ./scripts/generate-svg-sprites",
|
||||||
"release": "node ./scripts/release.js",
|
"release": "node ./scripts/release.js",
|
||||||
"clean": "lerna exec rimraf ./node_modules ./dist"
|
"clean": "lerna exec rimraf ./node_modules ./dist && rimraf ./node_modules ./dist",
|
||||||
|
"predeploy-gh-pages": "run-s build:web",
|
||||||
|
"deploy-gh-pages": "gh-pages -d packages/uhk-web/dist"
|
||||||
},
|
},
|
||||||
"dependencies": {}
|
"dependencies": {}
|
||||||
}
|
}
|
||||||
|
|||||||
2585
packages/uhk-agent/package-lock.json
generated
@@ -17,13 +17,7 @@
|
|||||||
"command-line-args": "4.0.7",
|
"command-line-args": "4.0.7",
|
||||||
"decompress": "4.2.0",
|
"decompress": "4.2.0",
|
||||||
"decompress-bzip2": "4.0.0",
|
"decompress-bzip2": "4.0.0",
|
||||||
"electron": "1.7.9",
|
"node-hid": "0.5.7",
|
||||||
"electron-is-dev": "0.1.2",
|
|
||||||
"electron-log": "2.2.9",
|
|
||||||
"electron-rebuild": "1.6.0",
|
|
||||||
"electron-settings": "3.1.2",
|
|
||||||
"electron-updater": "2.15.0",
|
|
||||||
"node-hid": "0.5.4",
|
|
||||||
"sudo-prompt": "7.0.0",
|
"sudo-prompt": "7.0.0",
|
||||||
"tmp": "0.0.33",
|
"tmp": "0.0.33",
|
||||||
"uhk-common": "^1.0.0",
|
"uhk-common": "^1.0.0",
|
||||||
@@ -36,6 +30,7 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "electron ./dist/electron-main.js",
|
"start": "electron ./dist/electron-main.js",
|
||||||
|
"electron:spe": "electron ./dist/electron-main.js --spe",
|
||||||
"build": "webpack && npm run install:build-deps && npm run build:usb && npm run download-firmware && npm run copy-blhost",
|
"build": "webpack && npm run install:build-deps && npm run build:usb && npm run download-firmware && npm run copy-blhost",
|
||||||
"build:usb": "electron-rebuild -w node-hid -p -m ./dist",
|
"build:usb": "electron-rebuild -w node-hid -p -m ./dist",
|
||||||
"install:build-deps": "cd ./dist && npm i",
|
"install:build-deps": "cd ./dist && npm i",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
/// <reference path="./custom_types/command-line-args.d.ts"/>
|
/// <reference path="./custom_types/command-line-args.d.ts"/>
|
||||||
|
|
||||||
import './polyfills';
|
import './polyfills';
|
||||||
import { app, BrowserWindow, ipcMain } from 'electron';
|
import { app, BrowserWindow } from 'electron';
|
||||||
import { autoUpdater } from 'electron-updater';
|
import { autoUpdater } from 'electron-updater';
|
||||||
|
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
@@ -10,7 +10,7 @@ import * as url from 'url';
|
|||||||
import * as commandLineArgs from 'command-line-args';
|
import * as commandLineArgs from 'command-line-args';
|
||||||
import { UhkHidDevice, UhkOperations } from 'uhk-usb';
|
import { UhkHidDevice, UhkOperations } from 'uhk-usb';
|
||||||
// import { ElectronDataStorageRepositoryService } from './services/electron-datastorage-repository.service';
|
// import { ElectronDataStorageRepositoryService } from './services/electron-datastorage-repository.service';
|
||||||
import { LogRegExps } from 'uhk-common';
|
import { CommandLineArgs, LogRegExps } from 'uhk-common';
|
||||||
import { DeviceService } from './services/device.service';
|
import { DeviceService } from './services/device.service';
|
||||||
import { logger } from './services/logger.service';
|
import { logger } from './services/logger.service';
|
||||||
import { AppUpdateService } from './services/app-update.service';
|
import { AppUpdateService } from './services/app-update.service';
|
||||||
@@ -18,13 +18,13 @@ import { AppService } from './services/app.service';
|
|||||||
import { SudoService } from './services/sudo.service';
|
import { SudoService } from './services/sudo.service';
|
||||||
import { UhkBlhost } from '../../uhk-usb/src';
|
import { UhkBlhost } from '../../uhk-usb/src';
|
||||||
import * as isDev from 'electron-is-dev';
|
import * as isDev from 'electron-is-dev';
|
||||||
import { CommandLineInputs } from './models/command-line-inputs';
|
|
||||||
|
|
||||||
const optionDefinitions = [
|
const optionDefinitions = [
|
||||||
{name: 'addons', type: Boolean}
|
{name: 'addons', type: Boolean},
|
||||||
|
{name: 'spe', type: Boolean} // simulate privilege escalation error
|
||||||
];
|
];
|
||||||
|
|
||||||
const options: CommandLineInputs = commandLineArgs(optionDefinitions);
|
const options: CommandLineArgs = commandLineArgs(optionDefinitions);
|
||||||
|
|
||||||
// import './dev-extension';
|
// import './dev-extension';
|
||||||
// require('electron-debug')({ showDevTools: true, enabled: true });
|
// require('electron-debug')({ showDevTools: true, enabled: true });
|
||||||
@@ -60,7 +60,25 @@ if (console.debug) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isSecondInstance = app.makeSingleInstance(function (commandLine, workingDirectory) {
|
||||||
|
// Someone tried to run a second instance, we should focus our window.
|
||||||
|
if (win) {
|
||||||
|
if (win.isMinimized()) {
|
||||||
|
win.restore();
|
||||||
|
}
|
||||||
|
win.focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isSecondInstance) {
|
||||||
|
app.quit();
|
||||||
|
}
|
||||||
|
|
||||||
function createWindow() {
|
function createWindow() {
|
||||||
|
if (isSecondInstance) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
logger.info('[Electron Main] Create new window.');
|
logger.info('[Electron Main] Create new window.');
|
||||||
let packagesDir;
|
let packagesDir;
|
||||||
if (isDev) {
|
if (isDev) {
|
||||||
@@ -79,17 +97,17 @@ function createWindow() {
|
|||||||
webPreferences: {
|
webPreferences: {
|
||||||
nodeIntegration: true
|
nodeIntegration: true
|
||||||
},
|
},
|
||||||
icon: 'assets/images/agent-icon.png'
|
icon: path.join(__dirname, 'renderer/assets/images/agent-app-icon.png')
|
||||||
});
|
});
|
||||||
win.setMenuBarVisibility(false);
|
win.setMenuBarVisibility(false);
|
||||||
win.maximize();
|
win.maximize();
|
||||||
uhkHidDeviceService = new UhkHidDevice(logger);
|
uhkHidDeviceService = new UhkHidDevice(logger, options);
|
||||||
uhkBlhost = new UhkBlhost(logger, packagesDir);
|
uhkBlhost = new UhkBlhost(logger, packagesDir);
|
||||||
uhkOperations = new UhkOperations(logger, uhkBlhost, uhkHidDeviceService, packagesDir);
|
uhkOperations = new UhkOperations(logger, uhkBlhost, uhkHidDeviceService, packagesDir);
|
||||||
deviceService = new DeviceService(logger, win, uhkHidDeviceService, uhkOperations);
|
deviceService = new DeviceService(logger, win, uhkHidDeviceService, uhkOperations);
|
||||||
appUpdateService = new AppUpdateService(logger, win, app);
|
appUpdateService = new AppUpdateService(logger, win, app);
|
||||||
appService = new AppService(logger, win, deviceService, options, uhkHidDeviceService);
|
appService = new AppService(logger, win, deviceService, options, uhkHidDeviceService);
|
||||||
sudoService = new SudoService(logger);
|
sudoService = new SudoService(logger, options);
|
||||||
// and load the index.html of the app.
|
// and load the index.html of the app.
|
||||||
|
|
||||||
win.loadURL(url.format({
|
win.loadURL(url.format({
|
||||||
@@ -133,13 +151,13 @@ app.on('ready', createWindow);
|
|||||||
|
|
||||||
// Quit when all windows are closed.
|
// Quit when all windows are closed.
|
||||||
app.on('window-all-closed', () => {
|
app.on('window-all-closed', () => {
|
||||||
app.quit();
|
|
||||||
});
|
|
||||||
|
|
||||||
app.on('will-quit', () => {
|
|
||||||
if (appUpdateService) {
|
if (appUpdateService) {
|
||||||
appUpdateService.saveFirtsRun();
|
appUpdateService.saveFirtsRun();
|
||||||
}
|
}
|
||||||
|
app.exit();
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on('will-quit', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
app.on('activate', () => {
|
app.on('activate', () => {
|
||||||
|
|||||||
@@ -1,3 +1,10 @@
|
|||||||
export interface CommandLineInputs {
|
export interface CommandLineInputs {
|
||||||
|
/**
|
||||||
|
* addons menu visible or not
|
||||||
|
*/
|
||||||
addons?: boolean;
|
addons?: boolean;
|
||||||
|
/**
|
||||||
|
* simulate privilege escalation error
|
||||||
|
*/
|
||||||
|
spe?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
import { ipcMain } from 'electron';
|
import { ipcMain } from 'electron';
|
||||||
import { ConfigurationReply, DeviceConnectionState, IpcEvents, IpcResponse, LogService } from 'uhk-common';
|
import {
|
||||||
|
ConfigurationReply,
|
||||||
|
DeviceConnectionState,
|
||||||
|
getHardwareConfigFromDeviceResponse,
|
||||||
|
HardwareModules,
|
||||||
|
IpcEvents,
|
||||||
|
IpcResponse,
|
||||||
|
LogService,
|
||||||
|
mapObjectToUserConfigBinaryBuffer,
|
||||||
|
SaveUserConfigurationData
|
||||||
|
} from 'uhk-common';
|
||||||
import { snooze, UhkHidDevice, UhkOperations } from 'uhk-usb';
|
import { snooze, UhkHidDevice, UhkOperations } from 'uhk-usb';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { Subscription } from 'rxjs/Subscription';
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
@@ -14,6 +24,7 @@ import 'rxjs/add/operator/distinctUntilChanged';
|
|||||||
import { saveTmpFirmware } from '../util/save-extract-firmware';
|
import { saveTmpFirmware } from '../util/save-extract-firmware';
|
||||||
import { TmpFirmware } from '../models/tmp-firmware';
|
import { TmpFirmware } from '../models/tmp-firmware';
|
||||||
import { QueueManager } from './queue-manager';
|
import { QueueManager } from './queue-manager';
|
||||||
|
import { backupUserConfiguration, getBackupUserConfigurationContent } from '../util/backup-user-confoguration';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IpcMain pair of the UHK Communication
|
* IpcMain pair of the UHK Communication
|
||||||
@@ -73,10 +84,19 @@ export class DeviceService {
|
|||||||
try {
|
try {
|
||||||
await this.device.waitUntilKeyboardBusy();
|
await this.device.waitUntilKeyboardBusy();
|
||||||
const result = await this.operations.loadConfigurations();
|
const result = await this.operations.loadConfigurations();
|
||||||
|
const modules: HardwareModules = {
|
||||||
|
leftModuleInfo: await this.operations.getLeftModuleVersionInfo(),
|
||||||
|
rightModuleInfo: await this.operations.getRightModuleVersionInfo()
|
||||||
|
};
|
||||||
|
|
||||||
|
const hardwareConfig = getHardwareConfigFromDeviceResponse(result.hardwareConfiguration);
|
||||||
|
const uniqueId = hardwareConfig.uniqueId;
|
||||||
|
|
||||||
response = {
|
response = {
|
||||||
success: true,
|
success: true,
|
||||||
...result
|
...result,
|
||||||
|
modules,
|
||||||
|
backupConfiguration: await getBackupUserConfigurationContent(this.logService, uniqueId)
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
response = {
|
response = {
|
||||||
@@ -157,10 +177,13 @@ export class DeviceService {
|
|||||||
|
|
||||||
private async saveUserConfiguration(event: Electron.Event, args: Array<string>): Promise<void> {
|
private async saveUserConfiguration(event: Electron.Event, args: Array<string>): Promise<void> {
|
||||||
const response = new IpcResponse();
|
const response = new IpcResponse();
|
||||||
const json = args[0];
|
const data: SaveUserConfigurationData = JSON.parse(args[0]);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.operations.saveUserConfiguration(json);
|
await backupUserConfiguration(data);
|
||||||
|
|
||||||
|
const buffer = mapObjectToUserConfigBinaryBuffer(data.configuration);
|
||||||
|
await this.operations.saveUserConfiguration(buffer);
|
||||||
|
|
||||||
response.success = true;
|
response.success = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,13 @@ import * as sudo from 'sudo-prompt';
|
|||||||
import { dirSync } from 'tmp';
|
import { dirSync } from 'tmp';
|
||||||
import { emptyDir, copy } from 'fs-extra';
|
import { emptyDir, copy } from 'fs-extra';
|
||||||
|
|
||||||
import { IpcEvents, LogService, IpcResponse } from 'uhk-common';
|
import { CommandLineArgs, IpcEvents, LogService, IpcResponse } from 'uhk-common';
|
||||||
|
|
||||||
export class SudoService {
|
export class SudoService {
|
||||||
private rootDir: string;
|
private rootDir: string;
|
||||||
|
|
||||||
constructor(private logService: LogService) {
|
constructor(private logService: LogService,
|
||||||
|
private options: CommandLineArgs) {
|
||||||
if (isDev) {
|
if (isDev) {
|
||||||
this.rootDir = path.join(path.join(process.cwd(), process.argv[1]), '../../../../');
|
this.rootDir = path.join(path.join(process.cwd(), process.argv[1]), '../../../../');
|
||||||
} else {
|
} else {
|
||||||
@@ -21,6 +22,19 @@ export class SudoService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async setPrivilege(event: Electron.Event) {
|
private async setPrivilege(event: Electron.Event) {
|
||||||
|
if (this.options.spe) {
|
||||||
|
const error = new Error('No polkit authentication agent found.');
|
||||||
|
this.logService.error('[SudoService] Simulate privilege escalation error ', error);
|
||||||
|
|
||||||
|
const response = new IpcResponse();
|
||||||
|
response.success = false;
|
||||||
|
response.error = {message: error.message};
|
||||||
|
|
||||||
|
event.sender.send(IpcEvents.device.setPrivilegeOnLinuxReply, response);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (process.platform) {
|
switch (process.platform) {
|
||||||
case 'linux':
|
case 'linux':
|
||||||
await this.setPrivilegeOnLinux(event);
|
await this.setPrivilegeOnLinux(event);
|
||||||
@@ -28,7 +42,7 @@ export class SudoService {
|
|||||||
default:
|
default:
|
||||||
const response: IpcResponse = {
|
const response: IpcResponse = {
|
||||||
success: false,
|
success: false,
|
||||||
error: { message: 'Permissions couldn\'t be set. Invalid platform: ' + process.platform }
|
error: {message: 'Permissions couldn\'t be set. Invalid platform: ' + process.platform}
|
||||||
};
|
};
|
||||||
|
|
||||||
event.sender.send(IpcEvents.device.setPrivilegeOnLinuxReply, response);
|
event.sender.send(IpcEvents.device.setPrivilegeOnLinuxReply, response);
|
||||||
@@ -39,7 +53,7 @@ export class SudoService {
|
|||||||
private async setPrivilegeOnLinux(event: Electron.Event) {
|
private async setPrivilegeOnLinux(event: Electron.Event) {
|
||||||
const tmpDirectory = dirSync();
|
const tmpDirectory = dirSync();
|
||||||
const rulesDir = path.join(this.rootDir, 'rules');
|
const rulesDir = path.join(this.rootDir, 'rules');
|
||||||
this.logService.debug('[SudoService] Copy rules dir', { src: rulesDir, dst: tmpDirectory.name });
|
this.logService.debug('[SudoService] Copy rules dir', {src: rulesDir, dst: tmpDirectory.name});
|
||||||
await copy(rulesDir, tmpDirectory.name);
|
await copy(rulesDir, tmpDirectory.name);
|
||||||
|
|
||||||
const scriptPath = path.join(tmpDirectory.name, 'setup-rules.sh');
|
const scriptPath = path.join(tmpDirectory.name, 'setup-rules.sh');
|
||||||
@@ -55,7 +69,7 @@ export class SudoService {
|
|||||||
if (error) {
|
if (error) {
|
||||||
this.logService.error('[SudoService] Error when set privilege: ', error);
|
this.logService.error('[SudoService] Error when set privilege: ', error);
|
||||||
response.success = false;
|
response.success = false;
|
||||||
response.error = error;
|
response.error = {message: error.message};
|
||||||
} else {
|
} else {
|
||||||
response.success = true;
|
response.success = true;
|
||||||
}
|
}
|
||||||
|
|||||||
32
packages/uhk-agent/src/util/backup-user-confoguration.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { app } from 'electron';
|
||||||
|
import { LogService, UserConfiguration, SaveUserConfigurationData } from 'uhk-common';
|
||||||
|
import * as path from 'path';
|
||||||
|
import * as fs from 'fs-extra';
|
||||||
|
|
||||||
|
export const getBackupUserConfigurationPath = (uniqueId: number): string => {
|
||||||
|
const appDataDir = app.getPath('userData');
|
||||||
|
|
||||||
|
return path.join(appDataDir, `${uniqueId}.json`);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const backupUserConfiguration = (data: SaveUserConfigurationData): Promise<void> => {
|
||||||
|
const backupFilePath = getBackupUserConfigurationPath(data.uniqueId);
|
||||||
|
return fs.writeJSON(backupFilePath, data.configuration, {spaces: 2});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getBackupUserConfigurationContent = async (logService: LogService, uniqueId: number): Promise<UserConfiguration> => {
|
||||||
|
try {
|
||||||
|
const backupFilePath = getBackupUserConfigurationPath(uniqueId);
|
||||||
|
|
||||||
|
if (await fs.pathExists(backupFilePath)) {
|
||||||
|
const json = await fs.readJSON(backupFilePath);
|
||||||
|
new UserConfiguration().fromJsonObject(json);
|
||||||
|
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
} catch (error) {
|
||||||
|
logService.error('Can not load backup user configuration for device', {uniqueId, error});
|
||||||
|
}
|
||||||
|
};
|
||||||
170
packages/uhk-common/package-lock.json
generated
@@ -18,11 +18,11 @@
|
|||||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
|
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
|
||||||
},
|
},
|
||||||
"ansi-styles": {
|
"ansi-styles": {
|
||||||
"version": "3.2.0",
|
"version": "3.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||||
"integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
|
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"color-convert": "1.9.0"
|
"color-convert": "1.9.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"arrify": {
|
"arrify": {
|
||||||
@@ -36,9 +36,9 @@
|
|||||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
||||||
},
|
},
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.8",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
"integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
|
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"balanced-match": "1.0.0",
|
"balanced-match": "1.0.0",
|
||||||
"concat-map": "0.0.1"
|
"concat-map": "0.0.1"
|
||||||
@@ -55,13 +55,13 @@
|
|||||||
"integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0="
|
"integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0="
|
||||||
},
|
},
|
||||||
"chalk": {
|
"chalk": {
|
||||||
"version": "2.1.0",
|
"version": "2.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz",
|
||||||
"integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==",
|
"integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"ansi-styles": "3.2.0",
|
"ansi-styles": "3.2.1",
|
||||||
"escape-string-regexp": "1.0.5",
|
"escape-string-regexp": "1.0.5",
|
||||||
"supports-color": "4.4.0"
|
"supports-color": "5.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"cliui": {
|
"cliui": {
|
||||||
@@ -100,9 +100,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"color-convert": {
|
"color-convert": {
|
||||||
"version": "1.9.0",
|
"version": "1.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz",
|
||||||
"integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=",
|
"integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"color-name": "1.1.3"
|
"color-name": "1.1.3"
|
||||||
}
|
}
|
||||||
@@ -122,15 +122,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
|
||||||
"integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
|
"integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"lru-cache": "4.1.1",
|
"lru-cache": "4.1.2",
|
||||||
"shebang-command": "1.2.0",
|
"shebang-command": "1.2.0",
|
||||||
"which": "1.3.0"
|
"which": "1.3.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lru-cache": {
|
"lru-cache": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.2.tgz",
|
||||||
"integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==",
|
"integrity": "sha512-wgeVXhrDwAWnIF/yZARsFnMBtdFXOg1b8RIrhilp+0iDYN4mdQcNZElDZ0e4B64BhaxeQ5zN7PMyvu7we1kPeQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"pseudomap": "1.0.2",
|
"pseudomap": "1.0.2",
|
||||||
"yallist": "2.1.2"
|
"yallist": "2.1.2"
|
||||||
@@ -144,9 +144,9 @@
|
|||||||
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
|
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
|
||||||
},
|
},
|
||||||
"diff": {
|
"diff": {
|
||||||
"version": "3.4.0",
|
"version": "3.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/diff/-/diff-3.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
|
||||||
"integrity": "sha512-QpVuMTEoJMF7cKzi6bvWhRulU1fZqZnvyVQgNhPaxxuTYwyjn/j1v9falseQ/uXWwPnO56RBfwtg4h/EQXmucA=="
|
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA=="
|
||||||
},
|
},
|
||||||
"error-ex": {
|
"error-ex": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.1",
|
||||||
@@ -271,9 +271,9 @@
|
|||||||
"integrity": "sha1-3i1mE20ALhErpw8/EMMc98NQsto="
|
"integrity": "sha1-3i1mE20ALhErpw8/EMMc98NQsto="
|
||||||
},
|
},
|
||||||
"has-flag": {
|
"has-flag": {
|
||||||
"version": "2.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||||
"integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE="
|
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
|
||||||
},
|
},
|
||||||
"homedir-polyfill": {
|
"homedir-polyfill": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
@@ -284,9 +284,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"hosted-git-info": {
|
"hosted-git-info": {
|
||||||
"version": "2.5.0",
|
"version": "2.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz",
|
||||||
"integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg=="
|
"integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw=="
|
||||||
},
|
},
|
||||||
"inflight": {
|
"inflight": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
@@ -382,7 +382,7 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"jasmine": "2.8.0",
|
"jasmine": "2.8.0",
|
||||||
"ts-node": "3.3.0",
|
"ts-node": "3.3.0",
|
||||||
"typescript": "2.5.3",
|
"typescript": "2.8.1",
|
||||||
"yargs": "8.0.2"
|
"yargs": "8.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -432,29 +432,29 @@
|
|||||||
"integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI="
|
"integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI="
|
||||||
},
|
},
|
||||||
"make-error": {
|
"make-error": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.4.tgz",
|
||||||
"integrity": "sha1-Uq06M5zPEM5itAQLcI/nByRLi5Y="
|
"integrity": "sha512-0Dab5btKVPhibSalc9QGXb559ED7G7iLjFXBaj9Wq8O3vorueR5K5jaE3hkG6ZQINyhA/JgG6Qk4qdFQjsYV6g=="
|
||||||
},
|
},
|
||||||
"mem": {
|
"mem": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz",
|
||||||
"integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=",
|
"integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"mimic-fn": "1.1.0"
|
"mimic-fn": "1.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mimic-fn": {
|
"mimic-fn": {
|
||||||
"version": "1.1.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
|
||||||
"integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg="
|
"integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="
|
||||||
},
|
},
|
||||||
"minimatch": {
|
"minimatch": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"brace-expansion": "1.1.8"
|
"brace-expansion": "1.1.11"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minimist": {
|
"minimist": {
|
||||||
@@ -472,10 +472,10 @@
|
|||||||
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
|
||||||
"integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
|
"integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"hosted-git-info": "2.5.0",
|
"hosted-git-info": "2.6.0",
|
||||||
"is-builtin-module": "1.0.0",
|
"is-builtin-module": "1.0.0",
|
||||||
"semver": "5.4.1",
|
"semver": "5.5.0",
|
||||||
"validate-npm-package-license": "3.0.1"
|
"validate-npm-package-license": "3.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"npm-run-path": {
|
"npm-run-path": {
|
||||||
@@ -1942,18 +1942,26 @@
|
|||||||
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
|
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
|
||||||
},
|
},
|
||||||
"p-limit": {
|
"p-limit": {
|
||||||
"version": "1.1.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz",
|
||||||
"integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw="
|
"integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==",
|
||||||
|
"requires": {
|
||||||
|
"p-try": "1.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"p-locate": {
|
"p-locate": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
|
||||||
"integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
|
"integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"p-limit": "1.1.0"
|
"p-limit": "1.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"p-try": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M="
|
||||||
|
},
|
||||||
"parse-json": {
|
"parse-json": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
|
||||||
@@ -2030,9 +2038,9 @@
|
|||||||
"integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE="
|
"integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE="
|
||||||
},
|
},
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "5.4.1",
|
"version": "5.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
|
||||||
"integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg=="
|
"integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA=="
|
||||||
},
|
},
|
||||||
"set-blocking": {
|
"set-blocking": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
@@ -2076,22 +2084,32 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"spdx-correct": {
|
"spdx-correct": {
|
||||||
"version": "1.0.2",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz",
|
||||||
"integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=",
|
"integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"spdx-license-ids": "1.2.2"
|
"spdx-expression-parse": "3.0.0",
|
||||||
|
"spdx-license-ids": "3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"spdx-exceptions": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg=="
|
||||||
|
},
|
||||||
"spdx-expression-parse": {
|
"spdx-expression-parse": {
|
||||||
"version": "1.0.4",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
|
||||||
"integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw="
|
"integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
|
||||||
|
"requires": {
|
||||||
|
"spdx-exceptions": "2.1.0",
|
||||||
|
"spdx-license-ids": "3.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"spdx-license-ids": {
|
"spdx-license-ids": {
|
||||||
"version": "1.2.2",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz",
|
||||||
"integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc="
|
"integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA=="
|
||||||
},
|
},
|
||||||
"string-width": {
|
"string-width": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
@@ -2146,11 +2164,11 @@
|
|||||||
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
|
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
|
||||||
},
|
},
|
||||||
"supports-color": {
|
"supports-color": {
|
||||||
"version": "4.4.0",
|
"version": "5.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz",
|
||||||
"integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==",
|
"integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"has-flag": "2.0.0"
|
"has-flag": "3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ts-node": {
|
"ts-node": {
|
||||||
@@ -2159,14 +2177,14 @@
|
|||||||
"integrity": "sha1-wTxqMCTjC+EYDdUwOPwgkonUv2k=",
|
"integrity": "sha1-wTxqMCTjC+EYDdUwOPwgkonUv2k=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"arrify": "1.0.1",
|
"arrify": "1.0.1",
|
||||||
"chalk": "2.1.0",
|
"chalk": "2.3.2",
|
||||||
"diff": "3.4.0",
|
"diff": "3.5.0",
|
||||||
"make-error": "1.3.0",
|
"make-error": "1.3.4",
|
||||||
"minimist": "1.2.0",
|
"minimist": "1.2.0",
|
||||||
"mkdirp": "0.5.1",
|
"mkdirp": "0.5.1",
|
||||||
"source-map-support": "0.4.18",
|
"source-map-support": "0.4.18",
|
||||||
"tsconfig": "6.0.0",
|
"tsconfig": "6.0.0",
|
||||||
"v8flags": "3.0.1",
|
"v8flags": "3.0.2",
|
||||||
"yn": "2.0.0"
|
"yn": "2.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -2202,9 +2220,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "2.5.3",
|
"version": "2.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.8.1.tgz",
|
||||||
"integrity": "sha512-ptLSQs2S4QuS6/OD1eAKG+S5G8QQtrU5RT32JULdZQtM1L3WTi34Wsu48Yndzi8xsObRAB9RPt/KhA9wlpEF6w=="
|
"integrity": "sha512-Ao/f6d/4EPLq0YwzsQz8iXflezpTkQzqAyenTiw4kCUGr1uPiFLC3+fZ+gMZz6eeI/qdRUqvC+HxIJzUAzEFdg=="
|
||||||
},
|
},
|
||||||
"underscore": {
|
"underscore": {
|
||||||
"version": "1.6.0",
|
"version": "1.6.0",
|
||||||
@@ -2212,20 +2230,20 @@
|
|||||||
"integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag="
|
"integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag="
|
||||||
},
|
},
|
||||||
"v8flags": {
|
"v8flags": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.0.2.tgz",
|
||||||
"integrity": "sha1-3Oj8N5wX2fLJ6e142JzgAFKxt2s=",
|
"integrity": "sha512-6sgSKoFw1UpUPd3cFdF7QGnrH6tDeBgW1F3v9gy8gLY0mlbiBXq8soy8aQpY6xeeCjH5K+JvC62Acp7gtl7wWA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"homedir-polyfill": "1.0.1"
|
"homedir-polyfill": "1.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"validate-npm-package-license": {
|
"validate-npm-package-license": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz",
|
||||||
"integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=",
|
"integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"spdx-correct": "1.0.2",
|
"spdx-correct": "3.0.0",
|
||||||
"spdx-expression-parse": "1.0.4"
|
"spdx-expression-parse": "3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"walkdir": {
|
"walkdir": {
|
||||||
|
|||||||
@@ -3,14 +3,18 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "Common Library contains the common code for uhk-agent (electron-main) and web (electron-renderer) modules",
|
"description": "Common Library contains the common code for uhk-agent (electron-main) and web (electron-renderer) modules",
|
||||||
"main": "dist/index.js",
|
"main": "dist/src/index.js",
|
||||||
|
"types": "dist/src/index.d.ts",
|
||||||
"author": "Ultimate Gadget Laboratories",
|
"author": "Ultimate Gadget Laboratories",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git@github.com:UltimateHackingKeyboard/agent.git"
|
"url": "git@github.com:UltimateHackingKeyboard/agent.git"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "run-s tsc copy:*",
|
||||||
|
"tsc": "tsc",
|
||||||
|
"copy:scancodes": "copyfiles ./src/config-serializer/config-items/scancodes.json dist",
|
||||||
|
"copy:secondary-roles": "copyfiles ./src/config-serializer/config-items/secondaryRole.json dist",
|
||||||
"test": "jasmine-ts --config=jasmine.json",
|
"test": "jasmine-ts --config=jasmine.json",
|
||||||
"coverage": "nyc jasmine-ts --config=jasmine.json"
|
"coverage": "nyc jasmine-ts --config=jasmine.json"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -9,3 +9,6 @@ export * from './macro';
|
|||||||
export * from './module';
|
export * from './module';
|
||||||
export * from './module-configuration';
|
export * from './module-configuration';
|
||||||
export * from './user-configuration';
|
export * from './user-configuration';
|
||||||
|
|
||||||
|
export const SCANCODES = require('./scancodes.json');
|
||||||
|
export const SECONDARY_ROLES = require('./secondaryRole.json');
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import { SwitchLayerAction } from './switch-layer-action';
|
|||||||
import { SwitchKeymapAction, UnresolvedSwitchKeymapAction } from './switch-keymap-action';
|
import { SwitchKeymapAction, UnresolvedSwitchKeymapAction } from './switch-keymap-action';
|
||||||
import { MouseAction } from './mouse-action';
|
import { MouseAction } from './mouse-action';
|
||||||
import { PlayMacroAction } from './play-macro-action';
|
import { PlayMacroAction } from './play-macro-action';
|
||||||
|
import { NoneAction } from './none-action';
|
||||||
|
import { isScancodeExists } from '../scancode-checker';
|
||||||
|
|
||||||
export class Helper {
|
export class Helper {
|
||||||
|
|
||||||
@@ -25,7 +27,12 @@ export class Helper {
|
|||||||
buffer.backtrack();
|
buffer.backtrack();
|
||||||
|
|
||||||
if (keyActionFirstByte >= KeyActionId.KeystrokeAction && keyActionFirstByte < KeyActionId.LastKeystrokeAction) {
|
if (keyActionFirstByte >= KeyActionId.KeystrokeAction && keyActionFirstByte < KeyActionId.LastKeystrokeAction) {
|
||||||
return new KeystrokeAction().fromBinary(buffer);
|
const keystrokeAction = new KeystrokeAction().fromBinary(buffer);
|
||||||
|
if (isValidKeystrokeAction(keystrokeAction)) {
|
||||||
|
return keystrokeAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new NoneAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (keyActionFirstByte) {
|
switch (keyActionFirstByte) {
|
||||||
@@ -67,8 +74,14 @@ export class Helper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (keyAction.keyActionType) {
|
switch (keyAction.keyActionType) {
|
||||||
case keyActionType.KeystrokeAction:
|
case keyActionType.KeystrokeAction: {
|
||||||
return new KeystrokeAction().fromJsonObject(keyAction);
|
const keystrokeAction = new KeystrokeAction().fromJsonObject(keyAction);
|
||||||
|
if (isValidKeystrokeAction(keystrokeAction)) {
|
||||||
|
return keystrokeAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new NoneAction();
|
||||||
|
}
|
||||||
case keyActionType.SwitchLayerAction:
|
case keyActionType.SwitchLayerAction:
|
||||||
return new SwitchLayerAction().fromJsonObject(keyAction);
|
return new SwitchLayerAction().fromJsonObject(keyAction);
|
||||||
case keyActionType.SwitchKeymapAction:
|
case keyActionType.SwitchKeymapAction:
|
||||||
@@ -77,8 +90,16 @@ export class Helper {
|
|||||||
return new MouseAction().fromJsonObject(keyAction);
|
return new MouseAction().fromJsonObject(keyAction);
|
||||||
case keyActionType.PlayMacroAction:
|
case keyActionType.PlayMacroAction:
|
||||||
return new PlayMacroAction().fromJsonObject(keyAction, macros);
|
return new PlayMacroAction().fromJsonObject(keyAction, macros);
|
||||||
|
case keyActionType.NoneAction:
|
||||||
|
return new NoneAction();
|
||||||
default:
|
default:
|
||||||
throw `Invalid KeyAction.keyActionType: "${keyAction.keyActionType}"`;
|
throw `Invalid KeyAction.keyActionType: "${keyAction.keyActionType}"`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isValidKeystrokeAction(keystrokeAction: KeystrokeAction): boolean {
|
||||||
|
return keystrokeAction.hasSecondaryRoleAction() ||
|
||||||
|
keystrokeAction.hasActiveModifier() ||
|
||||||
|
keystrokeAction.hasScancode() && isScancodeExists(keystrokeAction.scancode);
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export enum KeystrokeActionFlag {
|
|||||||
|
|
||||||
const KEYSTROKE_ACTION_FLAG_LENGTH = 3;
|
const KEYSTROKE_ACTION_FLAG_LENGTH = 3;
|
||||||
|
|
||||||
interface JsonObjectKeystrokeAction {
|
export interface JsonObjectKeystrokeAction {
|
||||||
keyActionType: string;
|
keyActionType: string;
|
||||||
scancode?: number;
|
scancode?: number;
|
||||||
modifierMask?: number;
|
modifierMask?: number;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { assertEnum, assertUInt8 } from '../../assert';
|
import { assertEnum, assertUInt8, assertUInt16 } from '../../assert';
|
||||||
import { UhkBuffer } from '../../uhk-buffer';
|
import { UhkBuffer } from '../../uhk-buffer';
|
||||||
import { KeyModifiers } from '../key-modifiers';
|
import { KeyModifiers } from '../key-modifiers';
|
||||||
import { MacroAction, MacroActionId, MacroKeySubAction, macroActionType } from './macro-action';
|
import { MacroAction, MacroActionId, MacroKeySubAction, macroActionType } from './macro-action';
|
||||||
import { KeystrokeType } from '../key-action';
|
import { KeystrokeType } from '../key-action';
|
||||||
|
|
||||||
interface JsObjectKeyMacroAction {
|
export interface JsObjectKeyMacroAction {
|
||||||
macroActionType: string;
|
macroActionType: string;
|
||||||
action: string;
|
action: string;
|
||||||
type?: string;
|
type?: string;
|
||||||
@@ -20,12 +20,24 @@ export class KeyMacroAction extends MacroAction {
|
|||||||
@assertEnum(KeystrokeType)
|
@assertEnum(KeystrokeType)
|
||||||
type: KeystrokeType;
|
type: KeystrokeType;
|
||||||
|
|
||||||
@assertUInt8
|
|
||||||
scancode: number;
|
|
||||||
|
|
||||||
@assertUInt8
|
@assertUInt8
|
||||||
modifierMask: number;
|
modifierMask: number;
|
||||||
|
|
||||||
|
@assertUInt16
|
||||||
|
private _scancode: number;
|
||||||
|
|
||||||
|
set scancode(scancode: number) {
|
||||||
|
this._scancode = scancode;
|
||||||
|
if (this.type !== KeystrokeType.shortMedia && this.type !== KeystrokeType.longMedia) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.type = scancode < 256 ? KeystrokeType.shortMedia : KeystrokeType.longMedia;
|
||||||
|
}
|
||||||
|
|
||||||
|
get scancode() {
|
||||||
|
return this._scancode;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(other?: KeyMacroAction) {
|
constructor(other?: KeyMacroAction) {
|
||||||
super();
|
super();
|
||||||
if (!other) {
|
if (!other) {
|
||||||
@@ -33,7 +45,7 @@ export class KeyMacroAction extends MacroAction {
|
|||||||
}
|
}
|
||||||
this.action = other.action;
|
this.action = other.action;
|
||||||
this.type = other.type;
|
this.type = other.type;
|
||||||
this.scancode = other.scancode;
|
this._scancode = other._scancode;
|
||||||
this.modifierMask = other.modifierMask;
|
this.modifierMask = other.modifierMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +57,7 @@ export class KeyMacroAction extends MacroAction {
|
|||||||
} else {
|
} else {
|
||||||
this.type = KeystrokeType[jsObject.type];
|
this.type = KeystrokeType[jsObject.type];
|
||||||
}
|
}
|
||||||
this.scancode = jsObject.scancode;
|
this._scancode = jsObject.scancode;
|
||||||
this.modifierMask = jsObject.modifierMask;
|
this.modifierMask = jsObject.modifierMask;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -58,7 +70,7 @@ export class KeyMacroAction extends MacroAction {
|
|||||||
this.type = keyMacroType & 0b11;
|
this.type = keyMacroType & 0b11;
|
||||||
keyMacroType >>= 2;
|
keyMacroType >>= 2;
|
||||||
if (keyMacroType & 0b10) {
|
if (keyMacroType & 0b10) {
|
||||||
this.scancode = buffer.readUInt8();
|
this._scancode = this.type === KeystrokeType.longMedia ? buffer.readUInt16() : buffer.readUInt8();
|
||||||
}
|
}
|
||||||
if (keyMacroType & 0b01) {
|
if (keyMacroType & 0b01) {
|
||||||
this.modifierMask = buffer.readUInt8();
|
this.modifierMask = buffer.readUInt8();
|
||||||
@@ -78,7 +90,7 @@ export class KeyMacroAction extends MacroAction {
|
|||||||
} else {
|
} else {
|
||||||
jsObject.type = KeystrokeType[this.type];
|
jsObject.type = KeystrokeType[this.type];
|
||||||
}
|
}
|
||||||
jsObject.scancode = this.scancode;
|
jsObject.scancode = this._scancode;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.hasModifiers()) {
|
if (this.hasModifiers()) {
|
||||||
@@ -98,7 +110,11 @@ export class KeyMacroAction extends MacroAction {
|
|||||||
|
|
||||||
buffer.writeUInt8(keyMacroType);
|
buffer.writeUInt8(keyMacroType);
|
||||||
if (this.hasScancode()) {
|
if (this.hasScancode()) {
|
||||||
buffer.writeUInt8(this.scancode);
|
if (this.type === KeystrokeType.longMedia) {
|
||||||
|
buffer.writeUInt16(this.scancode);
|
||||||
|
} else {
|
||||||
|
buffer.writeUInt8(this.scancode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (this.hasModifiers()) {
|
if (this.hasModifiers()) {
|
||||||
buffer.writeUInt8(this.modifierMask);
|
buffer.writeUInt8(this.modifierMask);
|
||||||
@@ -106,7 +122,7 @@ export class KeyMacroAction extends MacroAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toString(): string {
|
toString(): string {
|
||||||
return `<KeyMacroAction action="${this.action}" scancode="${this.scancode}" modifierMask="${this.modifierMask}">`;
|
return `<KeyMacroAction action="${this.action}" scancode="${this._scancode}" modifierMask="${this.modifierMask}">`;
|
||||||
}
|
}
|
||||||
|
|
||||||
isModifierActive(modifier: KeyModifiers): boolean {
|
isModifierActive(modifier: KeyModifiers): boolean {
|
||||||
@@ -114,7 +130,7 @@ export class KeyMacroAction extends MacroAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hasScancode(): boolean {
|
hasScancode(): boolean {
|
||||||
return !!this.scancode;
|
return !!this._scancode;
|
||||||
}
|
}
|
||||||
|
|
||||||
hasModifiers(): boolean {
|
hasModifiers(): boolean {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export enum MouseButtons {
|
|||||||
Right = 1 << 2
|
Right = 1 << 2
|
||||||
}
|
}
|
||||||
|
|
||||||
interface JsObjectMouseButtonMacroAction {
|
export interface JsObjectMouseButtonMacroAction {
|
||||||
macroActionType: string;
|
macroActionType: string;
|
||||||
action: string;
|
action: string;
|
||||||
mouseButtonsMask?: number;
|
mouseButtonsMask?: number;
|
||||||
|
|||||||
@@ -54,15 +54,12 @@ export class Module {
|
|||||||
|
|
||||||
const noneAction = new NoneAction();
|
const noneAction = new NoneAction();
|
||||||
|
|
||||||
const keyActions: KeyAction[] = this.keyActions.map(keyAction => {
|
buffer.writeArray(this.keyActions, (uhkBuffer: UhkBuffer, keyAction: KeyAction) => {
|
||||||
if (keyAction) {
|
if (keyAction) {
|
||||||
return keyAction;
|
keyAction.toBinary(uhkBuffer, userConfiguration);
|
||||||
|
} else {
|
||||||
|
noneAction.toBinary(uhkBuffer);
|
||||||
}
|
}
|
||||||
return noneAction;
|
|
||||||
});
|
|
||||||
|
|
||||||
buffer.writeArray(keyActions, (uhkBuffer: UhkBuffer, keyAction: KeyAction) => {
|
|
||||||
keyAction.toBinary(uhkBuffer, userConfiguration);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { SCANCODES } from './';
|
||||||
|
|
||||||
|
let scancodeMap: Map<number, any>;
|
||||||
|
|
||||||
|
export function isScancodeExists(scancode: number): boolean {
|
||||||
|
if (!scancodeMap) {
|
||||||
|
fillScancodeMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
return scancodeMap.has(scancode);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fillScancodeMap(): void {
|
||||||
|
scancodeMap = new Map<number, any>();
|
||||||
|
|
||||||
|
for (const scanGroup of SCANCODES) {
|
||||||
|
for (const child of scanGroup.children) {
|
||||||
|
if (child.additional && child.additional.scancode) {
|
||||||
|
scancodeMap.set(child.additional.scancode, child);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
scancodeMap.set(Number.parseInt(child.id), child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -105,6 +105,10 @@
|
|||||||
{
|
{
|
||||||
"id": "29",
|
"id": "29",
|
||||||
"text": "Z"
|
"text": "Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "100",
|
||||||
|
"text": "| ISO"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -242,7 +246,7 @@
|
|||||||
"text": "Delete"
|
"text": "Delete"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "118",
|
"id": "101",
|
||||||
"text": "Menu"
|
"text": "Menu"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -314,10 +318,6 @@
|
|||||||
"id": "69",
|
"id": "69",
|
||||||
"text": "F12"
|
"text": "F12"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "100",
|
|
||||||
"text": "| ISO"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "104",
|
"id": "104",
|
||||||
"text": "F13"
|
"text": "F13"
|
||||||
@@ -1,3 +1,10 @@
|
|||||||
export interface CommandLineArgs {
|
export interface CommandLineArgs {
|
||||||
addons: boolean;
|
/**
|
||||||
|
* addons menu visible or not
|
||||||
|
*/
|
||||||
|
addons?: boolean;
|
||||||
|
/**
|
||||||
|
* simulate privilege escalation error
|
||||||
|
*/
|
||||||
|
spe?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
|
import { HardwareModules } from './hardware-modules';
|
||||||
|
import { UserConfiguration } from '../config-serializer/config-items';
|
||||||
|
|
||||||
export interface ConfigurationReply {
|
export interface ConfigurationReply {
|
||||||
success: boolean;
|
success: boolean;
|
||||||
userConfiguration?: string;
|
userConfiguration?: string;
|
||||||
hardwareConfiguration?: string;
|
hardwareConfiguration?: string;
|
||||||
|
modules?: HardwareModules;
|
||||||
error?: string;
|
error?: string;
|
||||||
|
backupConfiguration?: UserConfiguration;
|
||||||
}
|
}
|
||||||
|
|||||||
4
packages/uhk-common/src/models/hardware-module-info.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export interface HardwareModuleInfo {
|
||||||
|
firmwareVersion?: string;
|
||||||
|
moduleProtocolVersion?: string;
|
||||||
|
}
|
||||||
6
packages/uhk-common/src/models/hardware-modules.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { HardwareModuleInfo } from './hardware-module-info';
|
||||||
|
|
||||||
|
export interface HardwareModules {
|
||||||
|
leftModuleInfo?: HardwareModuleInfo;
|
||||||
|
rightModuleInfo?: HardwareModuleInfo;
|
||||||
|
}
|
||||||
@@ -5,3 +5,6 @@ export * from './app-start-info';
|
|||||||
export * from './configuration-reply';
|
export * from './configuration-reply';
|
||||||
export * from './version-information';
|
export * from './version-information';
|
||||||
export * from './device-connection-state';
|
export * from './device-connection-state';
|
||||||
|
export * from './hardware-modules';
|
||||||
|
export * from './hardware-module-info';
|
||||||
|
export * from './save-user-configuration-data';
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export interface SaveUserConfigurationData {
|
||||||
|
uniqueId: number;
|
||||||
|
configuration: string;
|
||||||
|
}
|
||||||
33
packages/uhk-common/src/util/helpers.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { HardwareConfiguration, UhkBuffer, UserConfiguration } from '../config-serializer';
|
||||||
|
|
||||||
|
export const getHardwareConfigFromDeviceResponse = (json: string): HardwareConfiguration => {
|
||||||
|
const data = JSON.parse(json);
|
||||||
|
const hardwareConfig = new HardwareConfiguration();
|
||||||
|
hardwareConfig.fromBinary(UhkBuffer.fromArray(data));
|
||||||
|
|
||||||
|
if (hardwareConfig.uniqueId > 0) {
|
||||||
|
return hardwareConfig;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getUserConfigFromDeviceResponse = (json: string): UserConfiguration => {
|
||||||
|
const data = JSON.parse(json);
|
||||||
|
const userConfig = new UserConfiguration();
|
||||||
|
userConfig.fromBinary(UhkBuffer.fromArray(data));
|
||||||
|
|
||||||
|
if (userConfig.userConfigMajorVersion > 0) {
|
||||||
|
return userConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Error('Invalid user configuration');
|
||||||
|
};
|
||||||
|
|
||||||
|
export const mapObjectToUserConfigBinaryBuffer = (obj: any): Buffer => {
|
||||||
|
const configuration = new UserConfiguration();
|
||||||
|
configuration.fromJsonObject(obj);
|
||||||
|
const buffer = new UhkBuffer();
|
||||||
|
configuration.toBinary(buffer);
|
||||||
|
|
||||||
|
return buffer.getBufferContent();
|
||||||
|
};
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
export { IpcEvents } from './ipcEvents';
|
export { IpcEvents } from './ipcEvents';
|
||||||
export * from './log';
|
export * from './log';
|
||||||
export * from './constants';
|
export * from './constants';
|
||||||
|
export * from './helpers';
|
||||||
|
|
||||||
// Source: http://stackoverflow.com/questions/13720256/javascript-regex-camelcase-to-sentence
|
// Source: http://stackoverflow.com/questions/13720256/javascript-regex-camelcase-to-sentence
|
||||||
export function camelCaseToSentence(camelCasedText: string): string {
|
export function camelCaseToSentence(camelCasedText: string): string {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
class App {
|
export class App {
|
||||||
public static readonly appStarted = 'app-started';
|
public static readonly appStarted = 'app-started';
|
||||||
public static readonly getAppStartInfo = 'app-get-start-info';
|
public static readonly getAppStartInfo = 'app-get-start-info';
|
||||||
public static readonly getAppStartInfoReply = 'app-get-start-info-reply';
|
public static readonly getAppStartInfoReply = 'app-get-start-info-reply';
|
||||||
@@ -6,7 +6,7 @@ class App {
|
|||||||
public static readonly openUrl = 'open-url';
|
public static readonly openUrl = 'open-url';
|
||||||
}
|
}
|
||||||
|
|
||||||
class AutoUpdate {
|
export class AutoUpdate {
|
||||||
public static readonly checkingForUpdate = 'checking-for-update';
|
public static readonly checkingForUpdate = 'checking-for-update';
|
||||||
public static readonly updateAvailable = 'update-available';
|
public static readonly updateAvailable = 'update-available';
|
||||||
public static readonly updateNotAvailable = 'update-not-available';
|
public static readonly updateNotAvailable = 'update-not-available';
|
||||||
@@ -18,7 +18,7 @@ class AutoUpdate {
|
|||||||
public static readonly checkForUpdateNotAvailable = 'check-for-update-not-available';
|
public static readonly checkForUpdateNotAvailable = 'check-for-update-not-available';
|
||||||
}
|
}
|
||||||
|
|
||||||
class Device {
|
export class Device {
|
||||||
public static readonly setPrivilegeOnLinux = 'set-privilege-on-linux';
|
public static readonly setPrivilegeOnLinux = 'set-privilege-on-linux';
|
||||||
public static readonly setPrivilegeOnLinuxReply = 'set-privilege-on-linux-reply';
|
public static readonly setPrivilegeOnLinuxReply = 'set-privilege-on-linux-reply';
|
||||||
public static readonly deviceConnectionStateChanged = 'device-connection-state-changed';
|
public static readonly deviceConnectionStateChanged = 'device-connection-state-changed';
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"outDir": "./dist",
|
"outDir": "./dist",
|
||||||
"declaration": false,
|
"declaration": true,
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
|
|||||||
184
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",
|
||||||
@@ -23,7 +26,7 @@
|
|||||||
"integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=",
|
"integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"delegates": "1.0.0",
|
"delegates": "1.0.0",
|
||||||
"readable-stream": "2.3.3"
|
"readable-stream": "2.3.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"bindings": {
|
"bindings": {
|
||||||
@@ -32,11 +35,12 @@
|
|||||||
"integrity": "sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw=="
|
"integrity": "sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw=="
|
||||||
},
|
},
|
||||||
"bl": {
|
"bl": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/bl/-/bl-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
|
||||||
"integrity": "sha1-ysMo977kVzDUBLaSID/LWQ4XLV4=",
|
"integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"readable-stream": "2.3.3"
|
"readable-stream": "2.3.6",
|
||||||
|
"safe-buffer": "5.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"chownr": {
|
"chownr": {
|
||||||
@@ -59,6 +63,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
||||||
},
|
},
|
||||||
|
"decompress-response": {
|
||||||
|
"version": "3.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz",
|
||||||
|
"integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=",
|
||||||
|
"requires": {
|
||||||
|
"mimic-response": "1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"deep-extend": {
|
"deep-extend": {
|
||||||
"version": "0.4.2",
|
"version": "0.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz",
|
||||||
@@ -69,10 +81,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
||||||
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
|
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
|
||||||
},
|
},
|
||||||
|
"detect-libc": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
|
||||||
|
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
|
||||||
|
},
|
||||||
"end-of-stream": {
|
"end-of-stream": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
|
||||||
"integrity": "sha1-epDYM+/abPpurA9JSduw+tOmMgY=",
|
"integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"once": "1.4.0"
|
"once": "1.4.0"
|
||||||
}
|
}
|
||||||
@@ -113,9 +130,9 @@
|
|||||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
||||||
},
|
},
|
||||||
"ini": {
|
"ini": {
|
||||||
"version": "1.3.4",
|
"version": "1.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
|
||||||
"integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4="
|
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
|
||||||
},
|
},
|
||||||
"is-fullwidth-code-point": {
|
"is-fullwidth-code-point": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -130,6 +147,16 @@
|
|||||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||||
},
|
},
|
||||||
|
"lodash-es": {
|
||||||
|
"version": "4.17.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.10.tgz",
|
||||||
|
"integrity": "sha512-iesFYPmxYYGTcmQK0sL8bX3TGHyM6b2qREaB4kamHfQyfPJP0xgoGxp19nsH16nsfquLdiyKyX3mQkfiSGV8Rg=="
|
||||||
|
},
|
||||||
|
"mimic-response": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-3z02Uqc/3ta5sLJBRub9BSNTRY4="
|
||||||
|
},
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||||
@@ -151,14 +178,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nan": {
|
"nan": {
|
||||||
"version": "2.7.0",
|
"version": "2.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz",
|
||||||
"integrity": "sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY="
|
"integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA=="
|
||||||
},
|
},
|
||||||
"node-abi": {
|
"node-abi": {
|
||||||
"version": "2.1.1",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.3.0.tgz",
|
||||||
"integrity": "sha512-6oxV13poCOv7TfGvhsSz6XZWpXeKkdGVh72++cs33OfMh3KAX8lN84dCvmqSETyDXAFcUHtV7eJrgFBoOqZbNQ=="
|
"integrity": "sha512-zwm6vU3SsVgw3e9fu48JBaRBCJGIvAgysDsqtf5+vEexFE71bEOtaMWb5zr/zODZNzTPtQlqUUpC79k68Hspow==",
|
||||||
|
"requires": {
|
||||||
|
"semver": "5.5.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node-hid": {
|
"node-hid": {
|
||||||
"version": "0.5.7",
|
"version": "0.5.7",
|
||||||
@@ -166,8 +196,8 @@
|
|||||||
"integrity": "sha512-dwwpOetL2+MGYgivbO22ML+45ieCGbueWv1rYxRgBoEc2QMp6UF6ZucEkYts1IA3YPWJNkmpGh6dqQ85n19szw==",
|
"integrity": "sha512-dwwpOetL2+MGYgivbO22ML+45ieCGbueWv1rYxRgBoEc2QMp6UF6ZucEkYts1IA3YPWJNkmpGh6dqQ85n19szw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"bindings": "1.3.0",
|
"bindings": "1.3.0",
|
||||||
"nan": "2.7.0",
|
"nan": "2.10.0",
|
||||||
"prebuild-install": "2.3.0"
|
"prebuild-install": "2.5.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"noop-logger": {
|
"noop-logger": {
|
||||||
@@ -210,62 +240,63 @@
|
|||||||
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
|
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
|
||||||
},
|
},
|
||||||
"prebuild-install": {
|
"prebuild-install": {
|
||||||
"version": "2.3.0",
|
"version": "2.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-2.5.1.tgz",
|
||||||
"integrity": "sha512-gzjq2oHB8oMbzJSsSh9MQ64zrXZGt092/uT4TLZlz2qnrPxpWqp4vYB7LZrDxnlxf5RfbCjkgDI/z0EIVuYzAw==",
|
"integrity": "sha512-3DX9L6pzwc1m1ksMkW3Ky2WLgPQUBiySOfXVl3WZyAeJSyJb4wtoH9OmeRGcubAWsMlLiL8BTHbwfm/jPQE9Ag==",
|
||||||
"requires": {
|
"requires": {
|
||||||
|
"detect-libc": "1.0.3",
|
||||||
"expand-template": "1.1.0",
|
"expand-template": "1.1.0",
|
||||||
"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.1.1",
|
"node-abi": "2.3.0",
|
||||||
"noop-logger": "0.1.1",
|
"noop-logger": "0.1.1",
|
||||||
"npmlog": "4.1.2",
|
"npmlog": "4.1.2",
|
||||||
"os-homedir": "1.0.2",
|
"os-homedir": "1.0.2",
|
||||||
"pump": "1.0.2",
|
"pump": "2.0.1",
|
||||||
"rc": "1.2.2",
|
"rc": "1.2.6",
|
||||||
"simple-get": "1.4.3",
|
"simple-get": "2.7.0",
|
||||||
"tar-fs": "1.16.0",
|
"tar-fs": "1.16.0",
|
||||||
"tunnel-agent": "0.6.0",
|
"tunnel-agent": "0.6.0",
|
||||||
"xtend": "4.0.1"
|
"which-pm-runs": "1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"process-nextick-args": {
|
"process-nextick-args": {
|
||||||
"version": "1.0.7",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
|
||||||
"integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
|
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
|
||||||
},
|
},
|
||||||
"pump": {
|
"pump": {
|
||||||
"version": "1.0.2",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/pump/-/pump-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
|
||||||
"integrity": "sha1-Oz7mUS+U8OV1U4wXmV+fFpkKXVE=",
|
"integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"end-of-stream": "1.4.0",
|
"end-of-stream": "1.4.1",
|
||||||
"once": "1.4.0"
|
"once": "1.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rc": {
|
"rc": {
|
||||||
"version": "1.2.2",
|
"version": "1.2.6",
|
||||||
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.6.tgz",
|
||||||
"integrity": "sha1-2M6ctX6NZNnHut2YdsfDTL48cHc=",
|
"integrity": "sha1-6xiYnG1PTxYsOZ953dKfODVWgJI=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"deep-extend": "0.4.2",
|
"deep-extend": "0.4.2",
|
||||||
"ini": "1.3.4",
|
"ini": "1.3.5",
|
||||||
"minimist": "1.2.0",
|
"minimist": "1.2.0",
|
||||||
"strip-json-comments": "2.0.1"
|
"strip-json-comments": "2.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"readable-stream": {
|
"readable-stream": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||||
"integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
|
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"core-util-is": "1.0.2",
|
"core-util-is": "1.0.2",
|
||||||
"inherits": "2.0.3",
|
"inherits": "2.0.3",
|
||||||
"isarray": "1.0.0",
|
"isarray": "1.0.0",
|
||||||
"process-nextick-args": "1.0.7",
|
"process-nextick-args": "2.0.0",
|
||||||
"safe-buffer": "5.1.1",
|
"safe-buffer": "5.1.1",
|
||||||
"string_decoder": "1.0.3",
|
"string_decoder": "1.1.1",
|
||||||
"util-deprecate": "1.0.2"
|
"util-deprecate": "1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -274,6 +305,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
|
||||||
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
|
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
|
||||||
},
|
},
|
||||||
|
"semver": {
|
||||||
|
"version": "5.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
|
||||||
|
"integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA=="
|
||||||
|
},
|
||||||
"set-blocking": {
|
"set-blocking": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
||||||
@@ -284,14 +320,19 @@
|
|||||||
"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",
|
||||||
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
|
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
|
||||||
},
|
},
|
||||||
|
"simple-concat": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY="
|
||||||
|
},
|
||||||
"simple-get": {
|
"simple-get": {
|
||||||
"version": "1.4.3",
|
"version": "2.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-1.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.7.0.tgz",
|
||||||
"integrity": "sha1-6XVe2kB+ltpAxeUVjJ6jezO+y+s=",
|
"integrity": "sha512-RkE9rGPHcxYZ/baYmgJtOSM63vH0Vyq+ma5TijBcLla41SWlh8t6XYIGMR/oeZcmr+/G8k+zrClkkVrtnQ0esg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
|
"decompress-response": "3.3.0",
|
||||||
"once": "1.4.0",
|
"once": "1.4.0",
|
||||||
"unzip-response": "1.0.2",
|
"simple-concat": "1.0.0"
|
||||||
"xtend": "4.0.1"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"string-width": {
|
"string-width": {
|
||||||
@@ -305,9 +346,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"string_decoder": {
|
"string_decoder": {
|
||||||
"version": "1.0.3",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||||
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
|
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"safe-buffer": "5.1.1"
|
"safe-buffer": "5.1.1"
|
||||||
}
|
}
|
||||||
@@ -332,18 +373,29 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"chownr": "1.0.1",
|
"chownr": "1.0.1",
|
||||||
"mkdirp": "0.5.1",
|
"mkdirp": "0.5.1",
|
||||||
"pump": "1.0.2",
|
"pump": "1.0.3",
|
||||||
"tar-stream": "1.5.4"
|
"tar-stream": "1.5.5"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"pump": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==",
|
||||||
|
"requires": {
|
||||||
|
"end-of-stream": "1.4.1",
|
||||||
|
"once": "1.4.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tar-stream": {
|
"tar-stream": {
|
||||||
"version": "1.5.4",
|
"version": "1.5.5",
|
||||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.5.tgz",
|
||||||
"integrity": "sha1-NlSc8E7RrumyowwBQyUiONr5QBY=",
|
"integrity": "sha512-mQdgLPc/Vjfr3VWqWbfxW8yQNiJCbAZ+Gf6GDu1Cy0bdb33ofyiNGBtAY96jHFhDuivCwgW1H9DgTON+INiXgg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"bl": "1.2.1",
|
"bl": "1.2.2",
|
||||||
"end-of-stream": "1.4.0",
|
"end-of-stream": "1.4.1",
|
||||||
"readable-stream": "2.3.3",
|
"readable-stream": "2.3.6",
|
||||||
"xtend": "4.0.1"
|
"xtend": "4.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -355,16 +407,16 @@
|
|||||||
"safe-buffer": "5.1.1"
|
"safe-buffer": "5.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"unzip-response": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-1.0.2.tgz",
|
|
||||||
"integrity": "sha1-uYTwh3/AqJwsdzzB73tbIytbBv4="
|
|
||||||
},
|
|
||||||
"util-deprecate": {
|
"util-deprecate": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||||
},
|
},
|
||||||
|
"which-pm-runs": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs="
|
||||||
|
},
|
||||||
"wide-align": {
|
"wide-align": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"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",
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"@types/node": "8.0.28"
|
"@types/node": "8.0.28"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"lodash-es": "^4.17.10",
|
||||||
"node-hid": "0.5.7",
|
"node-hid": "0.5.7",
|
||||||
"uhk-common": "1.0.0"
|
"uhk-common": "1.0.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export enum UsbCommand {
|
|||||||
GetDebugBuffer = 0x0b,
|
GetDebugBuffer = 0x0b,
|
||||||
GetAdcValue = 0x0c,
|
GetAdcValue = 0x0c,
|
||||||
SetLedPwmBrightness = 0x0d,
|
SetLedPwmBrightness = 0x0d,
|
||||||
GetModuleProperties = 0x0e
|
GetModuleProperty = 0x0e
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum EepromOperation {
|
export enum EepromOperation {
|
||||||
@@ -39,7 +39,8 @@ export enum ConfigBufferId {
|
|||||||
export enum DevicePropertyIds {
|
export enum DevicePropertyIds {
|
||||||
DeviceProtocolVersion = 0,
|
DeviceProtocolVersion = 0,
|
||||||
ProtocolVersions = 1,
|
ProtocolVersions = 1,
|
||||||
ConfigSizes = 2
|
ConfigSizes = 2,
|
||||||
|
CurrentKbootCommand = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum EnumerationModes {
|
export enum EnumerationModes {
|
||||||
@@ -80,3 +81,7 @@ export enum KbootCommands {
|
|||||||
ping = 1,
|
ping = 1,
|
||||||
reset = 2
|
reset = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum ModulePropertyId {
|
||||||
|
protocolVersions = 0
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
import { cloneDeep, isEqual } from 'lodash-es';
|
||||||
import { Device, devices, HID } from 'node-hid';
|
import { Device, devices, HID } from 'node-hid';
|
||||||
import { LogService } from 'uhk-common';
|
import { CommandLineArgs, LogService } from 'uhk-common';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ConfigBufferId,
|
ConfigBufferId,
|
||||||
@@ -24,10 +25,12 @@ export class UhkHidDevice {
|
|||||||
* Internal variable that represent the USB UHK device
|
* Internal variable that represent the USB UHK device
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
private _prevDevices = {};
|
||||||
private _device: HID;
|
private _device: HID;
|
||||||
private _hasPermission = false;
|
private _hasPermission = false;
|
||||||
|
|
||||||
constructor(private logService: LogService) {
|
constructor(private logService: LogService,
|
||||||
|
private options: CommandLineArgs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,6 +41,10 @@ export class UhkHidDevice {
|
|||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
public hasPermission(): boolean {
|
public hasPermission(): boolean {
|
||||||
|
if (this.options.spe) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (this._hasPermission) {
|
if (this._hasPermission) {
|
||||||
return true;
|
return true;
|
||||||
@@ -192,7 +199,7 @@ export class UhkHidDevice {
|
|||||||
|
|
||||||
async sendKbootCommandToModule(module: ModuleSlotToI2cAddress, command: KbootCommands, maxTry = 1): Promise<any> {
|
async sendKbootCommandToModule(module: ModuleSlotToI2cAddress, command: KbootCommands, maxTry = 1): Promise<any> {
|
||||||
let transfer;
|
let transfer;
|
||||||
const moduleName = kbootKommandName(module);
|
const moduleName = kbootCommandName(module);
|
||||||
this.logService.debug(`[UhkHidDevice] USB[T]: Send KbootCommand ${moduleName} ${KbootCommands[command].toString()}`);
|
this.logService.debug(`[UhkHidDevice] USB[T]: Send KbootCommand ${moduleName} ${KbootCommands[command].toString()}`);
|
||||||
if (command === KbootCommands.idle) {
|
if (command === KbootCommands.idle) {
|
||||||
transfer = new Buffer([UsbCommand.SendKbootCommandToModule, command]);
|
transfer = new Buffer([UsbCommand.SendKbootCommandToModule, command]);
|
||||||
@@ -228,12 +235,20 @@ export class UhkHidDevice {
|
|||||||
private connectToDevice(): HID {
|
private connectToDevice(): HID {
|
||||||
try {
|
try {
|
||||||
const devs = devices();
|
const devs = devices();
|
||||||
this.logService.debug('[UhkHidDevice] Available devices:', devs);
|
if (!isEqual(this._prevDevices, devs)) {
|
||||||
|
this.logService.debug('[UhkHidDevice] Available devices:', devs);
|
||||||
|
this._prevDevices = devs;
|
||||||
|
} else {
|
||||||
|
this.logService.debug('[UhkHidDevice] Available devices unchanged');
|
||||||
|
}
|
||||||
|
|
||||||
const dev = devs.find((x: Device) =>
|
const dev = devs.find((x: Device) =>
|
||||||
x.vendorId === Constants.VENDOR_ID &&
|
x.vendorId === Constants.VENDOR_ID &&
|
||||||
x.productId === Constants.PRODUCT_ID &&
|
x.productId === Constants.PRODUCT_ID &&
|
||||||
((x.usagePage === 128 && x.usage === 129) || x.interface === 0));
|
// hidapi can not read the interface number on Mac, so check the usage page and usage
|
||||||
|
((x.usagePage === 128 && x.usage === 129) || // Old firmware
|
||||||
|
(x.usagePage === (0xFF00 | 0x00) && x.usage === 0x01) || // New firmware
|
||||||
|
x.interface === 0));
|
||||||
|
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
this.logService.debug('[UhkHidDevice] UHK Device not found:');
|
this.logService.debug('[UhkHidDevice] UHK Device not found:');
|
||||||
@@ -251,7 +266,7 @@ export class UhkHidDevice {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function kbootKommandName(module: ModuleSlotToI2cAddress): string {
|
function kbootCommandName(module: ModuleSlotToI2cAddress): string {
|
||||||
switch (module) {
|
switch (module) {
|
||||||
case ModuleSlotToI2cAddress.leftHalf:
|
case ModuleSlotToI2cAddress.leftHalf:
|
||||||
return 'leftHalf';
|
return 'leftHalf';
|
||||||
|
|||||||
@@ -1,12 +1,24 @@
|
|||||||
import { LogService } from 'uhk-common';
|
import { HardwareModuleInfo, LogService, UhkBuffer } from 'uhk-common';
|
||||||
import { EnumerationModes, EnumerationNameToProductId, KbootCommands, ModuleSlotToI2cAddress, ModuleSlotToId } from './constants';
|
import {
|
||||||
|
EnumerationModes,
|
||||||
|
EnumerationNameToProductId,
|
||||||
|
KbootCommands,
|
||||||
|
ModulePropertyId,
|
||||||
|
ModuleSlotToI2cAddress,
|
||||||
|
ModuleSlotToId
|
||||||
|
} from './constants';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import { UhkBlhost } from './uhk-blhost';
|
import { UhkBlhost } from './uhk-blhost';
|
||||||
import { UhkHidDevice } from './uhk-hid-device';
|
import { UhkHidDevice } from './uhk-hid-device';
|
||||||
import { snooze } from './util';
|
import { snooze } from './util';
|
||||||
import { convertBufferToIntArray, getTransferBuffers, DevicePropertyIds, UsbCommand, ConfigBufferId
|
import {
|
||||||
} from '../index';
|
convertBufferToIntArray,
|
||||||
|
getTransferBuffers,
|
||||||
|
DevicePropertyIds,
|
||||||
|
UsbCommand,
|
||||||
|
ConfigBufferId
|
||||||
|
} from '../index';
|
||||||
import { LoadConfigurationsResult } from './models/load-configurations-result';
|
import { LoadConfigurationsResult } from './models/load-configurations-result';
|
||||||
|
|
||||||
export class UhkOperations {
|
export class UhkOperations {
|
||||||
@@ -42,6 +54,13 @@ export class UhkOperations {
|
|||||||
await snooze(1000);
|
await snooze(1000);
|
||||||
await this.device.jumpToBootloaderModule(ModuleSlotToId.leftHalf);
|
await this.device.jumpToBootloaderModule(ModuleSlotToId.leftHalf);
|
||||||
this.device.close();
|
this.device.close();
|
||||||
|
|
||||||
|
const leftModuleBricked = await this.waitForKbootIdle();
|
||||||
|
if (!leftModuleBricked) {
|
||||||
|
this.logService.error('[UhkOperations] Couldn\'t connect to the left keyboard half.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await this.device.reenumerate(EnumerationModes.Buspal);
|
await this.device.reenumerate(EnumerationModes.Buspal);
|
||||||
this.device.close();
|
this.device.close();
|
||||||
await this.blhost.runBlhostCommandRetry([...buspalPrefix, 'get-property', '1']);
|
await this.blhost.runBlhostCommandRetry([...buspalPrefix, 'get-property', '1']);
|
||||||
@@ -86,8 +105,6 @@ export class UhkOperations {
|
|||||||
* @returns {Promise<Buffer>}
|
* @returns {Promise<Buffer>}
|
||||||
*/
|
*/
|
||||||
public async loadConfiguration(configBufferId: ConfigBufferId): Promise<string> {
|
public async loadConfiguration(configBufferId: ConfigBufferId): Promise<string> {
|
||||||
let response = [];
|
|
||||||
|
|
||||||
const configBufferIdToName = ['HardwareConfig', 'StagingUserConfig', 'ValidatedUserConfig'];
|
const configBufferIdToName = ['HardwareConfig', 'StagingUserConfig', 'ValidatedUserConfig'];
|
||||||
const configName = configBufferIdToName[configBufferId];
|
const configName = configBufferIdToName[configBufferId];
|
||||||
|
|
||||||
@@ -121,7 +138,8 @@ export class UhkOperations {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
response = convertBufferToIntArray(configBuffer);
|
const response = convertBufferToIntArray(configBuffer);
|
||||||
|
|
||||||
return Promise.resolve(JSON.stringify(response));
|
return Promise.resolve(JSON.stringify(response));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const errMsg = `[DeviceOperation] ${configName} from eeprom error`;
|
const errMsg = `[DeviceOperation] ${configName} from eeprom error`;
|
||||||
@@ -146,10 +164,10 @@ export class UhkOperations {
|
|||||||
return configSize;
|
return configSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async saveUserConfiguration(json: string): Promise<void> {
|
public async saveUserConfiguration(buffer: Buffer): Promise<void> {
|
||||||
try {
|
try {
|
||||||
this.logService.debug('[DeviceOperation] USB[T]: Write user configuration to keyboard');
|
this.logService.debug('[DeviceOperation] USB[T]: Write user configuration to keyboard');
|
||||||
await this.sendUserConfigToKeyboard(json);
|
await this.sendUserConfigToKeyboard(buffer);
|
||||||
this.logService.debug('[DeviceOperation] USB[T]: Write user configuration to EEPROM');
|
this.logService.debug('[DeviceOperation] USB[T]: Write user configuration to EEPROM');
|
||||||
await this.device.writeConfigToEeprom(ConfigBufferId.validatedUserConfig);
|
await this.device.writeConfigToEeprom(ConfigBufferId.validatedUserConfig);
|
||||||
}
|
}
|
||||||
@@ -161,14 +179,77 @@ export class UhkOperations {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async waitForKbootIdle(): Promise<boolean> {
|
||||||
|
const timeoutTime = new Date(new Date().getTime() + 30000);
|
||||||
|
|
||||||
|
while (new Date() < timeoutTime) {
|
||||||
|
const buffer = await this.device.write(new Buffer([UsbCommand.GetProperty, DevicePropertyIds.CurrentKbootCommand]));
|
||||||
|
this.device.close();
|
||||||
|
|
||||||
|
if (buffer[1] === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// tslint:disable-next-line: max-line-length
|
||||||
|
this.logService.info('[DeviceOperation] Cannot ping the bootloader. Please reconnect the left keyboard half. It probably needs several tries, so keep reconnecting until you see this message.');
|
||||||
|
|
||||||
|
await snooze(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getLeftModuleVersionInfo(): Promise<HardwareModuleInfo> {
|
||||||
|
try {
|
||||||
|
this.logService.debug('[DeviceOperation] USB[T]: Read left module version information');
|
||||||
|
|
||||||
|
const command = new Buffer([
|
||||||
|
UsbCommand.GetModuleProperty,
|
||||||
|
ModuleSlotToId.leftHalf,
|
||||||
|
ModulePropertyId.protocolVersions
|
||||||
|
]);
|
||||||
|
|
||||||
|
const buffer = await this.device.write(command);
|
||||||
|
const uhkBuffer = UhkBuffer.fromArray(convertBufferToIntArray(buffer));
|
||||||
|
// skip the first 2 byte
|
||||||
|
uhkBuffer.readUInt16();
|
||||||
|
|
||||||
|
return {
|
||||||
|
moduleProtocolVersion: `${uhkBuffer.readUInt16()}.${uhkBuffer.readUInt16()}.${uhkBuffer.readUInt16()}`,
|
||||||
|
firmwareVersion: `${uhkBuffer.readUInt16()}.${uhkBuffer.readUInt16()}.${uhkBuffer.readUInt16()}`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
this.logService.error('[DeviceOperation] Could not read left module version information', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
moduleProtocolVersion: '',
|
||||||
|
firmwareVersion: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getRightModuleVersionInfo(): Promise<HardwareModuleInfo> {
|
||||||
|
this.logService.debug('[DeviceOperation] USB[T]: Read right module version information');
|
||||||
|
|
||||||
|
const command = new Buffer([UsbCommand.GetProperty, DevicePropertyIds.ProtocolVersions]);
|
||||||
|
const buffer = await this.device.write(command);
|
||||||
|
const uhkBuffer = UhkBuffer.fromArray(convertBufferToIntArray(buffer));
|
||||||
|
// skip the first byte
|
||||||
|
uhkBuffer.readUInt8();
|
||||||
|
|
||||||
|
return {
|
||||||
|
firmwareVersion: `${uhkBuffer.readUInt16()}.${uhkBuffer.readUInt16()}.${uhkBuffer.readUInt16()}`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IpcMain handler. Send the UserConfiguration to the UHK Device and send a response with the result.
|
* IpcMain handler. Send the UserConfiguration to the UHK Device and send a response with the result.
|
||||||
* @param {string} json - UserConfiguration in JSON format
|
* @param {Buffer} buffer - UserConfiguration buffer
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
private async sendUserConfigToKeyboard(json: string): Promise<void> {
|
private async sendUserConfigToKeyboard(buffer: Buffer): Promise<void> {
|
||||||
const buffer: Buffer = new Buffer(JSON.parse(json).data);
|
|
||||||
const fragments = getTransferBuffers(UsbCommand.WriteStagingUserConfig, buffer);
|
const fragments = getTransferBuffers(UsbCommand.WriteStagingUserConfig, buffer);
|
||||||
for (const fragment of fragments) {
|
for (const fragment of fragments) {
|
||||||
await this.device.write(fragment);
|
await this.device.write(fragment);
|
||||||
|
|||||||
9157
packages/uhk-web/package-lock.json
generated
@@ -10,22 +10,24 @@
|
|||||||
"lint": "ng lint",
|
"lint": "ng lint",
|
||||||
"e2e": "ng e2e",
|
"e2e": "ng e2e",
|
||||||
"build:renderer": "webpack --config webpack.config.js",
|
"build:renderer": "webpack --config webpack.config.js",
|
||||||
"server:renderer": "webpack --config webpack.config.js --watch"
|
"server:renderer": "webpack --config webpack.config.js --watch",
|
||||||
|
"pree2e": "webdriver-manager update --standalone false --gecko false --quiet"
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular/animations": "4.4.5",
|
"@angular/animations": "5.2.9",
|
||||||
"@angular/cli": "1.4.7",
|
"@angular/cli": "1.7.4",
|
||||||
"@angular/common": "4.4.5",
|
"@angular/common": "5.2.9",
|
||||||
"@angular/compiler": "4.4.5",
|
"@angular/compiler": "5.2.9",
|
||||||
"@angular/compiler-cli": "4.4.5",
|
"@angular/compiler-cli": "5.2.9",
|
||||||
"@angular/core": "4.4.5",
|
"@angular/core": "5.2.9",
|
||||||
"@angular/forms": "4.4.5",
|
"@angular-devkit/build-optimizer": "0.3.2",
|
||||||
"@angular/http": "4.4.5",
|
"@angular/forms": "5.2.9",
|
||||||
"@angular/language-service": "4.4.5",
|
"@angular/http": "5.2.9",
|
||||||
"@angular/platform-browser": "4.4.5",
|
"@angular/language-service": "5.2.9",
|
||||||
"@angular/platform-browser-dynamic": "4.4.5",
|
"@angular/platform-browser": "5.2.9",
|
||||||
"@angular/router": "4.4.5",
|
"@angular/platform-browser-dynamic": "5.2.9",
|
||||||
|
"@angular/router": "5.2.9",
|
||||||
"@ngrx/effects": "4.0.5",
|
"@ngrx/effects": "4.0.5",
|
||||||
"@ngrx/router-store": "4.0.4",
|
"@ngrx/router-store": "4.0.4",
|
||||||
"@ngrx/store": "4.0.3",
|
"@ngrx/store": "4.0.3",
|
||||||
@@ -37,64 +39,45 @@
|
|||||||
"@types/jasmine": "2.5.53",
|
"@types/jasmine": "2.5.53",
|
||||||
"@types/jasminewd2": "2.0.2",
|
"@types/jasminewd2": "2.0.2",
|
||||||
"@types/jquery": "3.2.9",
|
"@types/jquery": "3.2.9",
|
||||||
"@types/node-hid": "0.5.2",
|
"@types/lodash-es": "4.17.0",
|
||||||
"@types/usb": "1.1.3",
|
"@types/usb": "1.1.3",
|
||||||
"angular-confirmation-popover": "3.2.0",
|
"angular-confirmation-popover": "3.2.0",
|
||||||
"angular-notifier": "2.0.0",
|
"angular-notifier": "2.0.0",
|
||||||
"autoprefixer": "6.5.3",
|
"autoprefixer": "^7.2.3",
|
||||||
"bootstrap": "3.3.7",
|
"bootstrap": "3.3.7",
|
||||||
"buffer": "5.0.6",
|
"buffer": "5.0.6",
|
||||||
"circular-dependency-plugin": "3.0.0",
|
"circular-dependency-plugin": "^4.2.1",
|
||||||
"codelyzer": "3.0.1",
|
"codelyzer": "3.0.1",
|
||||||
"copy-webpack-plugin": "4.0.1",
|
|
||||||
"css-loader": "0.28.1",
|
|
||||||
"cssnano": "3.10.0",
|
|
||||||
"dragula": "3.7.2",
|
"dragula": "3.7.2",
|
||||||
"exports-loader": "0.6.3",
|
|
||||||
"file-loader": "0.10.0",
|
|
||||||
"file-saver": "1.3.3",
|
|
||||||
"font-awesome": "4.7.0",
|
"font-awesome": "4.7.0",
|
||||||
"html-webpack-plugin": "2.29.0",
|
"html-webpack-plugin": "^2.29.0",
|
||||||
"istanbul-instrumenter-loader": "2.0.0",
|
|
||||||
"jasmine-core": "2.6.2",
|
"jasmine-core": "2.6.2",
|
||||||
"jasmine-spec-reporter": "4.1.0",
|
"jasmine-spec-reporter": "4.1.0",
|
||||||
"jquery": "3.2.1",
|
"jquery": "3.2.1",
|
||||||
"jsonfile": "3.0.1",
|
"jsonfile": "3.0.1",
|
||||||
"karma": "1.7.0",
|
"karma": "1.7.0",
|
||||||
"karma-chrome-launcher": "2.1.1",
|
"karma-chrome-launcher": "2.1.1",
|
||||||
"karma-cli": "1.0.1",
|
|
||||||
"karma-coverage-istanbul-reporter": "1.2.1",
|
"karma-coverage-istanbul-reporter": "1.2.1",
|
||||||
"karma-jasmine": "1.1.0",
|
"karma-jasmine": "1.1.0",
|
||||||
"karma-jasmine-html-reporter": "0.2.2",
|
"karma-jasmine-html-reporter": "0.2.2",
|
||||||
"less-loader": "4.0.5",
|
"lodash-es": "4.17.4",
|
||||||
"lodash": "4.17.4",
|
|
||||||
"ng2-dragula": "1.5.0",
|
"ng2-dragula": "1.5.0",
|
||||||
"ng2-nouislider": "^1.7.6",
|
"ng2-nouislider": "^1.7.7",
|
||||||
"ng2-select2": "1.0.0-beta.10",
|
"ng2-select2": "1.0.0-beta.10",
|
||||||
|
"ngx-clipboard": "10.0.0",
|
||||||
"ngrx-store-freeze": "0.1.9",
|
"ngrx-store-freeze": "0.1.9",
|
||||||
"node-hid": "0.5.4",
|
"nouislider": "^11.1.0",
|
||||||
"nouislider": "^10.1.0",
|
"postcss-url": "^7.1.2",
|
||||||
"postcss-loader": "1.3.3",
|
|
||||||
"postcss-url": "5.1.2",
|
|
||||||
"protractor": "5.1.2",
|
"protractor": "5.1.2",
|
||||||
"raw-loader": "0.5.1",
|
|
||||||
"reselect": "3.0.1",
|
"reselect": "3.0.1",
|
||||||
"sass-loader": "6.0.3",
|
"rxjs": "5.5.8",
|
||||||
"script-loader": "0.7.0",
|
|
||||||
"select2": "4.0.3",
|
"select2": "4.0.3",
|
||||||
"source-map-loader": "0.2.0",
|
"typescript": "2.6.2",
|
||||||
"style-loader": "0.13.1",
|
|
||||||
"stylus-loader": "3.0.1",
|
|
||||||
"sudo-prompt": "7.1.1",
|
|
||||||
"ts-loader": "2.3.1",
|
|
||||||
"ts-node": "3.0.4",
|
|
||||||
"uhk-common": "1.0.0",
|
"uhk-common": "1.0.0",
|
||||||
"url-loader": "0.5.7",
|
|
||||||
"webpack": "3.4.1",
|
|
||||||
"webpack-dev-server": "2.5.1",
|
|
||||||
"webpack-svgstore-plugin": "4.0.1",
|
|
||||||
"xml-loader": "1.2.1",
|
"xml-loader": "1.2.1",
|
||||||
"zone.js": "0.8.14"
|
"zone.js": "0.8.26",
|
||||||
|
"@angular-devkit/core": "0.3.2",
|
||||||
|
"@ngtools/webpack": "1.10.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"classlist.js": "1.1.20150312",
|
"classlist.js": "1.1.20150312",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Component, HostListener, ViewEncapsulation } from '@angular/core';
|
import { Component, ViewEncapsulation } 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 { Action, Store } from '@ngrx/store';
|
import { Action, Store } from '@ngrx/store';
|
||||||
@@ -14,7 +14,6 @@ import {
|
|||||||
saveToKeyboardState
|
saveToKeyboardState
|
||||||
} from './store';
|
} from './store';
|
||||||
import { ProgressButtonState } from './store/reducers/progress-button-state';
|
import { ProgressButtonState } from './store/reducers/progress-button-state';
|
||||||
import { SaveUserConfigInBinaryFileAction, SaveUserConfigInJsonFileAction } from './store/actions/user-config';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'main-app',
|
selector: 'main-app',
|
||||||
|
|||||||
@@ -9,13 +9,13 @@
|
|||||||
|
|
||||||
<ul class="list-unstyled btn-list">
|
<ul class="list-unstyled btn-list">
|
||||||
<li>
|
<li>
|
||||||
Download device configuration in
|
<button class="btn btn-default"
|
||||||
<span role="button" class="btn-link" (click)="saveConfigurationInJSONFormat()">JSON</span> or
|
(click)="exportUserConfiguration($event)">Export device configuration
|
||||||
<span role="button" class="btn-link" (click)="saveConfigurationInBINFormat()">binary</span> format.
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label class="btn btn-default btn-file">
|
<label class="btn btn-default btn-file">
|
||||||
Upload device configuration
|
Import device configuration
|
||||||
<input type="file"
|
<input type="file"
|
||||||
(change)="changeFile($event)">
|
(change)="changeFile($event)">
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
@@ -34,6 +34,14 @@ export class DeviceConfigurationComponent {
|
|||||||
this.store.dispatch(new SaveUserConfigInBinaryFileAction());
|
this.store.dispatch(new SaveUserConfigInBinaryFileAction());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exportUserConfiguration(event: MouseEvent) {
|
||||||
|
if (event.shiftKey) {
|
||||||
|
this.saveConfigurationInBINFormat();
|
||||||
|
} else {
|
||||||
|
this.saveConfigurationInJSONFormat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
changeFile(event): void {
|
changeFile(event): void {
|
||||||
const files = event.srcElement.files;
|
const files = event.srcElement.files;
|
||||||
const fileReader = new FileReader();
|
const fileReader = new FileReader();
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { DeviceConfigurationComponent } from './configuration/device-configurati
|
|||||||
import { DeviceFirmwareComponent } from './firmware/device-firmware.component';
|
import { DeviceFirmwareComponent } from './firmware/device-firmware.component';
|
||||||
import { MouseSpeedComponent } from './mouse-speed/mouse-speed.component';
|
import { MouseSpeedComponent } from './mouse-speed/mouse-speed.component';
|
||||||
import { LEDBrightnessComponent } from './led-brightness/led-brightness.component';
|
import { LEDBrightnessComponent } from './led-brightness/led-brightness.component';
|
||||||
|
import { RestoreConfigurationComponent } from './restore-configuration/restore-configuration.component';
|
||||||
|
|
||||||
export const deviceRoutes: Routes = [
|
export const deviceRoutes: Routes = [
|
||||||
{
|
{
|
||||||
@@ -29,6 +30,10 @@ export const deviceRoutes: Routes = [
|
|||||||
{
|
{
|
||||||
path: 'firmware',
|
path: 'firmware',
|
||||||
component: DeviceFirmwareComponent
|
component: DeviceFirmwareComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'restore-user-configuration',
|
||||||
|
component: RestoreConfigurationComponent
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,23 +6,36 @@
|
|||||||
<i class="fa fa-sliders"></i>
|
<i class="fa fa-sliders"></i>
|
||||||
<span>Firmware</span>
|
<span>Firmware</span>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Flash firmware {{ (getAgentVersionInfo$ | async).firmwareVersion }} (bundled with Agent)
|
Firmware {{ hardwareModules.leftModuleInfo.firmwareVersion }} is running on the left keyboard half.<br>
|
||||||
<button class="btn btn-primary"
|
Firmware {{ hardwareModules.rightModuleInfo.firmwareVersion }} is running on the right keyboard half.
|
||||||
[disabled]="flashFirmwareButtonDisbabled$ | async"
|
</p>
|
||||||
(click)="onUpdateFirmware()">Flash firmware
|
|
||||||
</button>
|
<p>
|
||||||
|
<i>
|
||||||
|
Please note that the firmware update process may sometimes fail. If if fails then
|
||||||
|
simply retry until it succeeds. If the left half becomes unresponsive after a failed
|
||||||
|
update then retry and follow the instructions displayed during the update to fix it.
|
||||||
|
We'll make the firmware update process more robust.
|
||||||
|
</i>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Flash firmware file <input id="firmware-file-select"
|
|
||||||
type="file"
|
|
||||||
[disabled]="flashFirmwareButtonDisbabled$ | async"
|
|
||||||
(change)="changeFile($event)">
|
|
||||||
<button class="btn btn-primary"
|
<button class="btn btn-primary"
|
||||||
[disabled]="flashFirmwareButtonDisbabled$ | async"
|
[disabled]="flashFirmwareButtonDisbabled$ | async"
|
||||||
(click)="onUpdateFirmwareWithFile()">Flash firmware
|
(click)="onUpdateFirmware()">
|
||||||
|
Flash firmware {{ (getAgentVersionInfo$ | async).firmwareVersion }} (bundled with Agent)
|
||||||
</button>
|
</button>
|
||||||
|
<label class="btn btn-primary btn-file"
|
||||||
|
[class.disabled]="flashFirmwareButtonDisbabled$ | async">
|
||||||
|
Choose firmware file and flash it
|
||||||
|
<input id="firmware-file-select"
|
||||||
|
type="file"
|
||||||
|
accept=".tar.bz2"
|
||||||
|
[disabled]="flashFirmwareButtonDisbabled$ | async"
|
||||||
|
(change)="changeFile($event)">
|
||||||
|
</label>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,16 @@ import { Component, ElementRef, OnDestroy, ViewChild } from '@angular/core';
|
|||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { Subscription } from 'rxjs/Subscription';
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
import { VersionInformation } from 'uhk-common';
|
import { HardwareModules, VersionInformation } from 'uhk-common';
|
||||||
|
|
||||||
import { AppState, firmwareOkButtonDisabled, flashFirmwareButtonDisbabled, getAgentVersionInfo, xtermLog } from '../../../store';
|
import {
|
||||||
|
AppState,
|
||||||
|
firmwareOkButtonDisabled,
|
||||||
|
flashFirmwareButtonDisbabled,
|
||||||
|
getAgentVersionInfo,
|
||||||
|
getHardwareModules,
|
||||||
|
xtermLog
|
||||||
|
} from '../../../store';
|
||||||
import { UpdateFirmwareAction, UpdateFirmwareOkButtonAction, UpdateFirmwareWithAction } from '../../../store/actions/device';
|
import { UpdateFirmwareAction, UpdateFirmwareOkButtonAction, UpdateFirmwareWithAction } from '../../../store/actions/device';
|
||||||
import { XtermLog } from '../../../models/xterm-log';
|
import { XtermLog } from '../../../models/xterm-log';
|
||||||
|
|
||||||
@@ -22,8 +29,9 @@ export class DeviceFirmwareComponent implements OnDestroy {
|
|||||||
xtermLogSubscription: Subscription;
|
xtermLogSubscription: Subscription;
|
||||||
getAgentVersionInfo$: Observable<VersionInformation>;
|
getAgentVersionInfo$: Observable<VersionInformation>;
|
||||||
firmwareOkButtonDisabled$: Observable<boolean>;
|
firmwareOkButtonDisabled$: Observable<boolean>;
|
||||||
|
hardwareModulesSubscription: Subscription;
|
||||||
|
hardwareModules: HardwareModules;
|
||||||
|
|
||||||
arrayBuffer: Uint8Array;
|
|
||||||
@ViewChild('scrollMe') divElement: ElementRef;
|
@ViewChild('scrollMe') divElement: ElementRef;
|
||||||
|
|
||||||
constructor(private store: Store<AppState>) {
|
constructor(private store: Store<AppState>) {
|
||||||
@@ -38,24 +46,20 @@ export class DeviceFirmwareComponent implements OnDestroy {
|
|||||||
});
|
});
|
||||||
this.getAgentVersionInfo$ = store.select(getAgentVersionInfo);
|
this.getAgentVersionInfo$ = store.select(getAgentVersionInfo);
|
||||||
this.firmwareOkButtonDisabled$ = store.select(firmwareOkButtonDisabled);
|
this.firmwareOkButtonDisabled$ = store.select(firmwareOkButtonDisabled);
|
||||||
|
this.hardwareModulesSubscription = store.select(getHardwareModules).subscribe(data => {
|
||||||
|
this.hardwareModules = data;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.xtermLogSubscription.unsubscribe();
|
this.xtermLogSubscription.unsubscribe();
|
||||||
|
this.hardwareModulesSubscription.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
onUpdateFirmware(): void {
|
onUpdateFirmware(): void {
|
||||||
this.store.dispatch(new UpdateFirmwareAction());
|
this.store.dispatch(new UpdateFirmwareAction());
|
||||||
}
|
}
|
||||||
|
|
||||||
onUpdateFirmwareWithFile(): void {
|
|
||||||
if (!this.arrayBuffer) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.store.dispatch(new UpdateFirmwareWithAction(Array.prototype.slice.call(this.arrayBuffer)));
|
|
||||||
}
|
|
||||||
|
|
||||||
onOkButtonClick(): void {
|
onOkButtonClick(): void {
|
||||||
this.store.dispatch(new UpdateFirmwareOkButtonAction());
|
this.store.dispatch(new UpdateFirmwareOkButtonAction());
|
||||||
}
|
}
|
||||||
@@ -64,14 +68,13 @@ export class DeviceFirmwareComponent implements OnDestroy {
|
|||||||
const files = event.srcElement.files;
|
const files = event.srcElement.files;
|
||||||
|
|
||||||
if (files.length === 0) {
|
if (files.length === 0) {
|
||||||
this.arrayBuffer = null;
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileReader = new FileReader();
|
const fileReader = new FileReader();
|
||||||
fileReader.onloadend = function () {
|
fileReader.onloadend = function () {
|
||||||
this.arrayBuffer = new Uint8Array(fileReader.result);
|
const arrayBuffer = new Uint8Array(fileReader.result);
|
||||||
|
this.store.dispatch(new UpdateFirmwareWithAction(Array.prototype.slice.call(arrayBuffer)));
|
||||||
}.bind(this);
|
}.bind(this);
|
||||||
fileReader.readAsArrayBuffer(files[0]);
|
fileReader.readAsArrayBuffer(files[0]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,4 +2,5 @@ export * from './configuration/device-configuration.component';
|
|||||||
export * from './firmware/device-firmware.component';
|
export * from './firmware/device-firmware.component';
|
||||||
export * from './mouse-speed/mouse-speed.component';
|
export * from './mouse-speed/mouse-speed.component';
|
||||||
export * from './led-brightness/led-brightness.component';
|
export * from './led-brightness/led-brightness.component';
|
||||||
|
export * from './restore-configuration/restore-configuration.component';
|
||||||
export * from './device.routes';
|
export * from './device.routes';
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<h1>
|
||||||
|
<i class="fa fa-exclamation-circle"></i>
|
||||||
|
<span>Fix configuration</span>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Your on-board device configuration is invalid.
|
||||||
|
</p>
|
||||||
|
<button class="btn btn-primary"
|
||||||
|
*ngIf="state.hasBackupUserConfiguration"
|
||||||
|
[disabled]="state.restoringUserConfiguration"
|
||||||
|
(click)="restoreUserConfiguration()"> Restore the last valid device configuration
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="btn btn-danger"
|
||||||
|
*ngIf="!state.hasBackupUserConfiguration"
|
||||||
|
[disabled]="state.restoringUserConfiguration"
|
||||||
|
(click)="resetUserConfiguration()">Reset device configuration
|
||||||
|
</button>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
:host {
|
||||||
|
overflow-y: auto;
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 1.5rem 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
|
|
||||||
|
import { AppState, getBackupUserConfigurationState } from '../../../store';
|
||||||
|
import { ResetUserConfigurationAction, RestoreUserConfigurationFromBackupAction } from '../../../store/actions/device';
|
||||||
|
import { RestoreConfigurationState } from '../../../models/restore-configuration-state';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'restore-configuration',
|
||||||
|
templateUrl: './restore-configuration.component.html',
|
||||||
|
styleUrls: ['./restore-configuration.component.scss'],
|
||||||
|
host: {
|
||||||
|
'class': 'container-fluid'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
export class RestoreConfigurationComponent implements OnInit, OnDestroy {
|
||||||
|
state: RestoreConfigurationState;
|
||||||
|
|
||||||
|
private stateSubscription: Subscription;
|
||||||
|
|
||||||
|
constructor(private store: Store<AppState>,
|
||||||
|
private cdRef: ChangeDetectorRef) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
if (this.stateSubscription) {
|
||||||
|
this.stateSubscription.unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.stateSubscription = this.store
|
||||||
|
.select(getBackupUserConfigurationState)
|
||||||
|
.subscribe(data => {
|
||||||
|
this.state = data;
|
||||||
|
this.cdRef.markForCheck();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
resetUserConfiguration() {
|
||||||
|
this.store.dispatch(new ResetUserConfigurationAction());
|
||||||
|
}
|
||||||
|
|
||||||
|
restoreUserConfiguration(): void {
|
||||||
|
this.store.dispatch(new RestoreUserConfigurationFromBackupAction());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<div class="text-center">
|
||||||
|
<span *ngIf="showPlaceholder"
|
||||||
|
class="placeholder">
|
||||||
|
<span (click)="editText()">{{ placeholder }}</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span *ngIf="showText"
|
||||||
|
class="editable">
|
||||||
|
<span (click)="editText()"
|
||||||
|
[innerHtml]="displayText"></span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="editing">
|
||||||
|
<textarea class="text-editor"
|
||||||
|
[(ngModel)]="text"
|
||||||
|
autofocus
|
||||||
|
(keydown.control.enter)="keydownEnter()"
|
||||||
|
(keydown.alt.enter)="keydownEnter()"></textarea>
|
||||||
|
<div class="pull-right buttons">
|
||||||
|
<button class="btn btn-danger"
|
||||||
|
(click)="cancelEditText()">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-primary"
|
||||||
|
(click)="saveText()"
|
||||||
|
[disabled]="isSaveDisabled">
|
||||||
|
Update description
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
:host {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
|
||||||
|
span.placeholder {
|
||||||
|
color: gray;
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
.glyphicon {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
span.editable,
|
||||||
|
span.placeholder {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea.text-editor {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, Input } from '@angular/core';
|
||||||
|
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'editable-text',
|
||||||
|
templateUrl: './editable-text.component.html',
|
||||||
|
styleUrls: ['./editable-text.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
providers: [
|
||||||
|
{provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => EditableTextComponent), multi: true}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class EditableTextComponent implements ControlValueAccessor {
|
||||||
|
|
||||||
|
@Input() placeholder = 'No editable content';
|
||||||
|
text: string;
|
||||||
|
originalText: string;
|
||||||
|
editing = false;
|
||||||
|
|
||||||
|
get isSaveDisabled(): boolean {
|
||||||
|
return !this.text || this.text.trim().length === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
get displayText(): string {
|
||||||
|
return this.text && this.text.replace(/\n/g, '<br>');
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(private cdr: ChangeDetectorRef) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
writeValue(obj: any): void {
|
||||||
|
if (this.text === obj) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.text = obj;
|
||||||
|
this.cdr.markForCheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnChange(fn: any): void {
|
||||||
|
this.textChange = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnTouched(fn: any): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
saveText(): void {
|
||||||
|
this.originalText = null;
|
||||||
|
this.editing = false;
|
||||||
|
this.textChange(this.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
editText(): void {
|
||||||
|
this.originalText = this.text;
|
||||||
|
this.editing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelEditText(): void {
|
||||||
|
this.text = this.originalText;
|
||||||
|
this.editing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
keydownEnter(): void {
|
||||||
|
if (this.isSaveDisabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.saveText();
|
||||||
|
}
|
||||||
|
|
||||||
|
get showPlaceholder(): boolean {
|
||||||
|
return !this.editing && !this.text;
|
||||||
|
}
|
||||||
|
|
||||||
|
get showText(): boolean {
|
||||||
|
return !this.editing && !!this.text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private textChange: any = () => {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,8 +7,11 @@
|
|||||||
[selectedKey]="selectedKey"
|
[selectedKey]="selectedKey"
|
||||||
[selected]="selectedKey?.layerId === index"
|
[selected]="selectedKey?.layerId === index"
|
||||||
[keyboardLayout]="keyboardLayout"
|
[keyboardLayout]="keyboardLayout"
|
||||||
|
[description]="description"
|
||||||
|
[showDescription]="true"
|
||||||
(keyClick)="keyClick.emit($event)"
|
(keyClick)="keyClick.emit($event)"
|
||||||
(keyHover)="keyHover.emit($event)"
|
(keyHover)="keyHover.emit($event)"
|
||||||
(capture)="capture.emit($event)"
|
(capture)="capture.emit($event)"
|
||||||
|
(descriptionChanged)="descriptionChanged.emit($event)"
|
||||||
>
|
>
|
||||||
</svg-keyboard>
|
</svg-keyboard>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 659 B After Width: | Height: | Size: 809 B |
@@ -1,4 +1,4 @@
|
|||||||
import { Component, ChangeDetectionStrategy, Input, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
|
||||||
import { animate, keyframes, state, style, transition, trigger } from '@angular/animations';
|
import { animate, keyframes, state, style, transition, trigger } from '@angular/animations';
|
||||||
import { Layer } from 'uhk-common';
|
import { Layer } from 'uhk-common';
|
||||||
|
|
||||||
@@ -81,11 +81,14 @@ export class KeyboardSliderComponent implements OnChanges {
|
|||||||
@Input() halvesSplit: boolean;
|
@Input() halvesSplit: boolean;
|
||||||
@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;
|
||||||
@Output() keyClick = new EventEmitter();
|
@Output() keyClick = new EventEmitter();
|
||||||
@Output() keyHover = new EventEmitter();
|
@Output() keyHover = new EventEmitter();
|
||||||
@Output() capture = new EventEmitter();
|
@Output() capture = new EventEmitter();
|
||||||
|
@Output() descriptionChanged = new EventEmitter<string>();
|
||||||
|
|
||||||
layerAnimationState: AnimationKeyboard[];
|
layerAnimationState: AnimationKeyboard[];
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
if (changes['layers']) {
|
if (changes['layers']) {
|
||||||
this.layerAnimationState = this.layers.map<AnimationKeyboard>(() => 'initOut');
|
this.layerAnimationState = this.layers.map<AnimationKeyboard>(() => 'initOut');
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
(downloadClick)="downloadKeymap()"></keymap-header>
|
(downloadClick)="downloadKeymap()"></keymap-header>
|
||||||
<svg-keyboard-wrap [keymap]="keymap$ | async"
|
<svg-keyboard-wrap [keymap]="keymap$ | async"
|
||||||
[halvesSplit]="keyboardSplit"
|
[halvesSplit]="keyboardSplit"
|
||||||
[keyboardLayout]="keyboardLayout$ | async"></svg-keyboard-wrap>
|
[keyboardLayout]="keyboardLayout$ | async"
|
||||||
|
(descriptionChanged)="descriptionChanged($event)"></svg-keyboard-wrap>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<div *ngIf="!(keymap$ | async)" class="not-found">
|
<div *ngIf="!(keymap$ | async)" class="not-found">
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ import { AppState, getKeyboardLayout } from '../../../store';
|
|||||||
import { getKeymap, getKeymaps, getUserConfiguration } from '../../../store/reducers/user-configuration';
|
import { getKeymap, getKeymaps, getUserConfiguration } from '../../../store/reducers/user-configuration';
|
||||||
import { SvgKeyboardWrapComponent } from '../../svg/wrap';
|
import { SvgKeyboardWrapComponent } from '../../svg/wrap';
|
||||||
import { KeyboardLayout } from '../../../keyboard/keyboard-layout.enum';
|
import { KeyboardLayout } from '../../../keyboard/keyboard-layout.enum';
|
||||||
|
import { KeymapActions } from '../../../store/actions';
|
||||||
|
import { ChangeKeymapDescription } from '../../../models/ChangeKeymapDescription';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'keymap-edit',
|
selector: 'keymap-edit',
|
||||||
@@ -64,7 +66,7 @@ export class KeymapEditComponent {
|
|||||||
const keymap = latest[0];
|
const keymap = latest[0];
|
||||||
const exportableJSON = latest[1];
|
const exportableJSON = latest[1];
|
||||||
const fileName = keymap.name + '_keymap.json';
|
const fileName = keymap.name + '_keymap.json';
|
||||||
saveAs(new Blob([exportableJSON], { type: 'application/json' }), fileName);
|
saveAs(new Blob([exportableJSON], {type: 'application/json'}), fileName);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,6 +75,10 @@ export class KeymapEditComponent {
|
|||||||
this.keyboardSplit = !this.keyboardSplit;
|
this.keyboardSplit = !this.keyboardSplit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
descriptionChanged(event: ChangeKeymapDescription): void {
|
||||||
|
this.store.dispatch(new KeymapActions.EditDescriptionAction(event));
|
||||||
|
}
|
||||||
|
|
||||||
private toExportableJSON(keymap: Keymap): Observable<any> {
|
private toExportableJSON(keymap: Keymap): Observable<any> {
|
||||||
return this.store
|
return this.store
|
||||||
.let(getUserConfiguration())
|
.let(getUserConfiguration())
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ export class MacroKeyTabComponent extends MacroBaseComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getKeyMacroAction(): KeyMacroAction {
|
getKeyMacroAction(): KeyMacroAction {
|
||||||
const keyMacroAction = Object.assign(new KeyMacroAction(), this.keypressTab.toKeyAction());
|
const keyMacroAction = new KeyMacroAction(this.keypressTab.toKeyAction() as any);
|
||||||
keyMacroAction.action = this.getActionType(this.activeTab);
|
keyMacroAction.action = this.getActionType(this.activeTab);
|
||||||
return keyMacroAction;
|
return keyMacroAction;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,5 +13,5 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<div *ngIf="!macro" class="not-found">
|
<div *ngIf="!macro" class="not-found">
|
||||||
There is no macro with id {{ route.params.select('id') | async }}.
|
There is no macro with id {{ macroId }}.
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { Subscription } from 'rxjs/Subscription';
|
|||||||
import 'rxjs/add/operator/pluck';
|
import 'rxjs/add/operator/pluck';
|
||||||
|
|
||||||
import { MacroActions } from '../../../store/actions';
|
import { MacroActions } from '../../../store/actions';
|
||||||
import { AppState } from '../../../store/index';
|
import { AppState } from '../../../store';
|
||||||
import { getMacro } from '../../../store/reducers/user-configuration';
|
import { getMacro } from '../../../store/reducers/user-configuration';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -21,13 +21,17 @@ import { getMacro } from '../../../store/reducers/user-configuration';
|
|||||||
export class MacroEditComponent implements OnDestroy {
|
export class MacroEditComponent implements OnDestroy {
|
||||||
macro: Macro;
|
macro: Macro;
|
||||||
isNew: boolean;
|
isNew: boolean;
|
||||||
|
macroId: number;
|
||||||
|
|
||||||
private subscription: Subscription;
|
private subscription: Subscription;
|
||||||
constructor(private store: Store<AppState>, public route: ActivatedRoute) {
|
constructor(private store: Store<AppState>, public route: ActivatedRoute) {
|
||||||
this.subscription = route
|
this.subscription = route
|
||||||
.params
|
.params
|
||||||
.pluck<{}, string>('id')
|
.pluck<{}, string>('id')
|
||||||
.switchMap((id: string) => store.let(getMacro(+id)))
|
.switchMap((id: string) => {
|
||||||
|
this.macroId = +id;
|
||||||
|
return store.let(getMacro(this.macroId));
|
||||||
|
})
|
||||||
.subscribe((macro: Macro) => {
|
.subscribe((macro: Macro) => {
|
||||||
this.macro = macro;
|
this.macro = macro;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<div class="row list-container">
|
<div class="row list-container">
|
||||||
<div class="col-xs-10 col-xs-offset-1 list-group">
|
<div class="col-xs-10 col-xs-offset-1 list-group">
|
||||||
|
<p><i>Please note that macro playback is not implemented yet. You can create macros, but they won't have any effect until firmware support is implemented. We're working on this.</i></p>
|
||||||
<div class="macro-actions-container" [dragula]="'macroActions'" [dragulaModel]="macro.macroActions">
|
<div class="macro-actions-container" [dragula]="'macroActions'" [dragulaModel]="macro.macroActions">
|
||||||
<macro-item *ngFor="let macroAction of macro.macroActions; let macroActionIndex = index"
|
<macro-item *ngFor="let macroAction of macro.macroActions; let macroActionIndex = index"
|
||||||
[macroAction]="macroAction"
|
[macroAction]="macroAction"
|
||||||
|
|||||||
@@ -79,8 +79,8 @@ export class PopoverComponent implements OnChanges {
|
|||||||
@Input() defaultKeyAction: KeyAction;
|
@Input() defaultKeyAction: KeyAction;
|
||||||
@Input() currentKeymap: Keymap;
|
@Input() currentKeymap: Keymap;
|
||||||
@Input() currentLayer: number;
|
@Input() currentLayer: number;
|
||||||
@Input() keyPosition: ClientRect;
|
@Input() keyPosition: any;
|
||||||
@Input() wrapPosition: ClientRect;
|
@Input() wrapPosition: any;
|
||||||
@Input() visible: boolean;
|
@Input() visible: boolean;
|
||||||
|
|
||||||
@Output() cancel = new EventEmitter<any>();
|
@Output() cancel = new EventEmitter<any>();
|
||||||
|
|||||||
@@ -7,6 +7,10 @@
|
|||||||
[width]="200"
|
[width]="200"
|
||||||
[options]="options"
|
[options]="options"
|
||||||
></select2>
|
></select2>
|
||||||
|
<icon name="question-circle"
|
||||||
|
data-toggle="tooltip"
|
||||||
|
title="Looking for a non-US character? Just pick the character of the desired key according to the US layout. For example, on US keyboards next to Tab there is the Q key, but it's й on Russian keyboards, so in this case choose Q instead of й in Agent."
|
||||||
|
data-placement="bottom"></icon>
|
||||||
<capture-keystroke-button (capture)="onKeysCapture($event)" tabindex="0"></capture-keystroke-button>
|
<capture-keystroke-button (capture)="onKeysCapture($event)" tabindex="0"></capture-keystroke-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modifier-options">
|
<div class="modifier-options">
|
||||||
|
|||||||
@@ -10,6 +10,10 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
top: 2px;
|
top: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
icon {
|
||||||
|
display: inline-block;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
.modifier-options {
|
.modifier-options {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Component, Input, OnChanges } from '@angular/core';
|
import { Component, Input, OnChanges } from '@angular/core';
|
||||||
import { Select2OptionData, Select2TemplateFunction } from 'ng2-select2';
|
import { Select2OptionData, Select2TemplateFunction } from 'ng2-select2';
|
||||||
import { KeyAction, KeystrokeAction, KeystrokeType } 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';
|
||||||
@@ -35,8 +35,8 @@ export class KeypressTabComponent extends Tab implements OnChanges {
|
|||||||
id: '0',
|
id: '0',
|
||||||
text: 'None'
|
text: 'None'
|
||||||
}];
|
}];
|
||||||
this.scanCodeGroups = this.scanCodeGroups.concat(require('./scancodes.json'));
|
this.scanCodeGroups = this.scanCodeGroups.concat(SCANCODES);
|
||||||
this.secondaryRoleGroups = require('./secondaryRole.json');
|
this.secondaryRoleGroups = SECONDARY_ROLES;
|
||||||
this.leftModifierSelects = Array(this.leftModifiers.length).fill(false);
|
this.leftModifierSelects = Array(this.leftModifiers.length).fill(false);
|
||||||
this.rightModifierSelects = Array(this.rightModifiers.length).fill(false);
|
this.rightModifierSelects = Array(this.rightModifiers.length).fill(false);
|
||||||
this.selectedScancodeOption = this.scanCodeGroups[0];
|
this.selectedScancodeOption = this.scanCodeGroups[0];
|
||||||
@@ -115,7 +115,7 @@ export class KeypressTabComponent extends Tab implements OnChanges {
|
|||||||
const scTypePair = this.toScancodeTypePair(this.selectedScancodeOption);
|
const scTypePair = this.toScancodeTypePair(this.selectedScancodeOption);
|
||||||
keystrokeAction.scancode = scTypePair[0];
|
keystrokeAction.scancode = scTypePair[0];
|
||||||
if (scTypePair[1] === 'media') {
|
if (scTypePair[1] === 'media') {
|
||||||
keystrokeAction.type = KeystrokeType.shortMedia;
|
keystrokeAction.type = keystrokeAction.scancode > 255 ? KeystrokeType.longMedia : KeystrokeType.shortMedia;
|
||||||
} else {
|
} else {
|
||||||
keystrokeAction.type = KeystrokeType[scTypePair[1]];
|
keystrokeAction.type = KeystrokeType[scTypePair[1]];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
<span [ngSwitch]="toggle">
|
<span [ngSwitch]="toggle">
|
||||||
<ng-template [ngSwitchCase]="true">layer by pressing this key.</ng-template>
|
<ng-template [ngSwitchCase]="true">layer by tapping this key.</ng-template>
|
||||||
<ng-template ngSwitchDefault>layer by holding this key.</ng-template>
|
<ng-template ngSwitchDefault>layer by holding this key.</ng-template>
|
||||||
</span>
|
</span>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<span> No macros are available to choose from. Create a macro first! </span>
|
<span> No macros are available to choose from. Create a macro first! </span>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template [ngIf]="macroOptions.length > 0">
|
<ng-template [ngIf]="macroOptions.length > 0">
|
||||||
<p><i>Please note that macro playback is not implemented yet. You can bind macros, but they don't have any effect.</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>
|
<select2 [data]="macroOptions" [value]="macroOptions[selectedMacroIndex].id" (valueChanged)="onChange($event)" [width]="'100%'"></select2>
|
||||||
|
|||||||
@@ -1,4 +1,39 @@
|
|||||||
<span class="privilege-checker-wrapper">
|
<div class="privilege-checker-wrapper">
|
||||||
<uhk-message header="Cannot talk to your UHK" subtitle="Your UHK has been detected, but its permissions are not set up yet, so Agent can't talk to it."></uhk-message>
|
<uhk-message header="Cannot talk to your UHK"
|
||||||
<button class="btn btn-default btn-lg btn-primary" (click)="setUpPermissions()"> Set up permissions </button>
|
subtitle="Your UHK has been detected, but its permissions are not set up yet, so Agent can't talk to it."></uhk-message>
|
||||||
</span>
|
|
||||||
|
<button class="btn btn-default btn-lg btn-primary"
|
||||||
|
(click)="setUpPermissions()"> Set up permissions
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="mt-10">
|
||||||
|
<a class="link-inline"
|
||||||
|
*ngIf="state.showWhatWillThisDo"
|
||||||
|
(click)="whatWillThisDo()">What will this do?
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p class="privilege-error"
|
||||||
|
#privilegeError
|
||||||
|
*ngIf="state.permissionSetupFailed">
|
||||||
|
Agent wasn't able to set up permissions via PolicyKit. This is most likely because the
|
||||||
|
<code>polkit</code> package is not installed on your system.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div *ngIf="state.showWhatWillThisDoContent">
|
||||||
|
Agent uses the following script to set up permissions. You can run it manually as root, then
|
||||||
|
<a class="link-inline"
|
||||||
|
(click)="retry()">retry</a>.
|
||||||
|
<div class="copy-container">
|
||||||
|
<span class="fa fa-2x fa-copy"
|
||||||
|
ngxClipboard
|
||||||
|
[cbContent]="command"
|
||||||
|
title="Copy to clipboard"
|
||||||
|
data-toggle="tooltip"
|
||||||
|
data-placement="top"></span>
|
||||||
|
<pre><code>{{ command }}</code></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -9,3 +9,19 @@
|
|||||||
uhk-message {
|
uhk-message {
|
||||||
max-width: 50%;
|
max-width: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.privilege-error {
|
||||||
|
animation: error-fade-in 2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes error-fade-in {
|
||||||
|
0% {
|
||||||
|
color: white;
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
color: inherit;
|
||||||
|
background-color: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,26 +1,61 @@
|
|||||||
import { Component } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import 'rxjs/add/observable/of';
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
import 'rxjs/add/observable/throw';
|
|
||||||
import 'rxjs/add/operator/distinctUntilChanged';
|
|
||||||
import 'rxjs/add/operator/ignoreElements';
|
|
||||||
import 'rxjs/add/operator/takeWhile';
|
|
||||||
|
|
||||||
import { AppState } from '../../store/index';
|
import { AppState, getPrivilegePageState } from '../../store';
|
||||||
import { SetPrivilegeOnLinuxAction } from '../../store/actions/device';
|
import { SetPrivilegeOnLinuxAction } from '../../store/actions/device';
|
||||||
|
import { LoadAppStartInfoAction, PrivilegeWhatWillThisDoAction } from '../../store/actions/app';
|
||||||
|
import { PrivilagePageSate } from '../../models/privilage-page-sate';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'privilege-checker',
|
selector: 'privilege-checker',
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
templateUrl: './privilege-checker.component.html',
|
templateUrl: './privilege-checker.component.html',
|
||||||
styleUrls: ['./privilege-checker.component.scss']
|
styleUrls: ['./privilege-checker.component.scss']
|
||||||
})
|
})
|
||||||
export class PrivilegeCheckerComponent {
|
|
||||||
|
|
||||||
constructor(protected store: Store<AppState>) {
|
export class PrivilegeCheckerComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
|
state: PrivilagePageSate;
|
||||||
|
|
||||||
|
command = `cat <<EOF >/etc/udev/rules.d/50-uhk60.rules
|
||||||
|
# Ultimate Hacking Keyboard rules
|
||||||
|
# These are the udev rules for accessing the USB interfaces of the UHK as non-root users.
|
||||||
|
# Copy this file to /etc/udev/rules.d and physically reconnect the UHK afterwards.
|
||||||
|
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="612[0-7]", MODE:="0666"
|
||||||
|
EOF
|
||||||
|
udevadm trigger
|
||||||
|
udevadm settle`;
|
||||||
|
|
||||||
|
private stateSubscription: Subscription;
|
||||||
|
|
||||||
|
constructor(private store: Store<AppState>,
|
||||||
|
private cdRef: ChangeDetectorRef) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.stateSubscription = this.store.select(getPrivilegePageState)
|
||||||
|
.subscribe(state => {
|
||||||
|
this.state = state;
|
||||||
|
this.cdRef.markForCheck();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
if (this.stateSubscription) {
|
||||||
|
this.stateSubscription.unsubscribe();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setUpPermissions(): void {
|
setUpPermissions(): void {
|
||||||
this.store.dispatch(new SetPrivilegeOnLinuxAction());
|
this.store.dispatch(new SetPrivilegeOnLinuxAction());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
whatWillThisDo(): void {
|
||||||
|
this.store.dispatch(new PrivilegeWhatWillThisDoAction());
|
||||||
|
}
|
||||||
|
|
||||||
|
retry(): void {
|
||||||
|
this.store.dispatch(new LoadAppStartInfoAction());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
<input #deviceName cancelable
|
<input #deviceName cancelable
|
||||||
class="pane-title__name"
|
class="pane-title__name"
|
||||||
type="text"
|
type="text"
|
||||||
|
[readonly]="state.restoreUserConfiguration"
|
||||||
(change)="editDeviceName($event.target.value)"
|
(change)="editDeviceName($event.target.value)"
|
||||||
(keyup.enter)="deviceName.blur()"
|
(keyup.enter)="deviceName.blur()"
|
||||||
(keyup)="calculateHeaderTextWidth($event.target.value)">
|
(keyup)="calculateHeaderTextWidth($event.target.value)">
|
||||||
@@ -17,33 +18,43 @@
|
|||||||
<i class="fa fa-chevron-up pull-right" (click)="toggleHide($event, 'configuration')"></i>
|
<i class="fa fa-chevron-up pull-right" (click)="toggleHide($event, 'configuration')"></i>
|
||||||
</div>
|
</div>
|
||||||
<ul [@toggler]="animation['configuration']">
|
<ul [@toggler]="animation['configuration']">
|
||||||
<li class="sidebar__level-2--item">
|
<li class="sidebar__level-2--item"
|
||||||
|
*ngIf="!state.restoreUserConfiguration">
|
||||||
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
||||||
<a [routerLink]="['/device/mouse-speed']"
|
<a [routerLink]="['/device/mouse-speed']"
|
||||||
[class.disabled]="updatingFirmware$ | async">Mouse speed</a>
|
[class.disabled]="state.updatingFirmware">Mouse speed</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li class="sidebar__level-2--item">
|
<li class="sidebar__level-2--item"
|
||||||
|
*ngIf="!state.restoreUserConfiguration">
|
||||||
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
||||||
<a [routerLink]="['/device/led-brightness']"
|
<a [routerLink]="['/device/led-brightness']"
|
||||||
[class.disabled]="updatingFirmware$ | async">LED brightness</a>
|
[class.disabled]="state.updatingFirmware">LED brightness</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li class="sidebar__level-2--item">
|
<li class="sidebar__level-2--item"
|
||||||
|
*ngIf="!state.restoreUserConfiguration">
|
||||||
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
||||||
<a [routerLink]="['/device/configuration']"
|
<a [routerLink]="['/device/configuration']"
|
||||||
[class.disabled]="updatingFirmware$ | async">Configuration</a>
|
[class.disabled]="state.updatingFirmware">Configuration</a>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="sidebar__level-2--item"
|
||||||
|
*ngIf="state.restoreUserConfiguration">
|
||||||
|
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
||||||
|
<a [routerLink]="['/device/restore-user-configuration']">Fix configuration</a>
|
||||||
</div>
|
</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']">
|
||||||
<a [routerLink]="['/device/firmware']"
|
<a [routerLink]="['/device/firmware']"
|
||||||
[class.disabled]="updatingFirmware$ | async">Firmware</a>
|
[class.disabled]="state.updatingFirmware">Firmware</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li class="sidebar__level-1--item">
|
<li class="sidebar__level-1--item"
|
||||||
|
*ngIf="!state.restoreUserConfiguration">
|
||||||
<div class="sidebar__level-1">
|
<div class="sidebar__level-1">
|
||||||
<i class="fa fa-keyboard-o"></i> Keymaps
|
<i class="fa fa-keyboard-o"></i> Keymaps
|
||||||
<!--a [routerLink]="['/keymap/add']"
|
<!--a [routerLink]="['/keymap/add']"
|
||||||
@@ -55,10 +66,10 @@
|
|||||||
(click)="toggleHide($event, 'keymap')"></i>
|
(click)="toggleHide($event, 'keymap')"></i>
|
||||||
</div>
|
</div>
|
||||||
<ul [@toggler]="animation['keymap']">
|
<ul [@toggler]="animation['keymap']">
|
||||||
<li *ngFor="let keymap of keymaps$ | async" class="sidebar__level-2--item">
|
<li *ngFor="let keymap of state.keymaps" class="sidebar__level-2--item">
|
||||||
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
||||||
<a [routerLink]="['/keymap', keymap.abbreviation]"
|
<a [routerLink]="['/keymap', keymap.abbreviation]"
|
||||||
[class.disabled]="updatingFirmware$ | async">{{keymap.name}}</a>
|
[class.disabled]="state.updatingFirmware">{{keymap.name}}</a>
|
||||||
<i *ngIf="keymap.isDefault" class="fa fa-star sidebar__fav"
|
<i *ngIf="keymap.isDefault" class="fa fa-star sidebar__fav"
|
||||||
title="This is the default keymap which gets activated when powering the keyboard."
|
title="This is the default keymap which gets activated when powering the keyboard."
|
||||||
data-toggle="tooltip" data-placement="bottom"></i>
|
data-toggle="tooltip" data-placement="bottom"></i>
|
||||||
@@ -66,26 +77,27 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li class="sidebar__level-1--item">
|
<li class="sidebar__level-1--item"
|
||||||
|
*ngIf="!state.restoreUserConfiguration">
|
||||||
<div class="sidebar__level-1">
|
<div class="sidebar__level-1">
|
||||||
<i class="fa fa-play"></i> Macros
|
<i class="fa fa-play"></i> Macros
|
||||||
<a (click)="addMacro()"
|
<a (click)="addMacro()"
|
||||||
class="btn btn-default pull-right btn-sm"
|
class="btn btn-default pull-right btn-sm"
|
||||||
[class.disabled]="updatingFirmware$ | async">
|
[class.disabled]="state.updatingFirmware">
|
||||||
<i class="fa fa-plus"></i>
|
<i class="fa fa-plus"></i>
|
||||||
</a>
|
</a>
|
||||||
<i class="fa fa-chevron-up pull-right" (click)="toggleHide($event, 'macro')"></i>
|
<i class="fa fa-chevron-up pull-right" (click)="toggleHide($event, 'macro')"></i>
|
||||||
</div>
|
</div>
|
||||||
<ul [@toggler]="animation['macro']">
|
<ul [@toggler]="animation['macro']">
|
||||||
<li *ngFor="let macro of macros$ | async" class="sidebar__level-2--item">
|
<li *ngFor="let macro of state.macros" class="sidebar__level-2--item">
|
||||||
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
||||||
<a [routerLink]="['/macro', macro.id]"
|
<a [routerLink]="['/macro', macro.id]"
|
||||||
[class.disabled]="updatingFirmware$ | async">{{macro.name}}</a>
|
[class.disabled]="state.updatingFirmware">{{macro.name}}</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li class="sidebar__level-1--item" *ngIf="showAddonMenu$ | async">
|
<li class="sidebar__level-1--item" *ngIf="state.showAddonMenu">
|
||||||
<div class="sidebar__level-1">
|
<div class="sidebar__level-1">
|
||||||
<i class="fa fa-puzzle-piece"></i> Add-on modules
|
<i class="fa fa-puzzle-piece"></i> Add-on modules
|
||||||
<i class="fa fa-chevron-up pull-right" (click)="toggleHide($event, 'addon')"></i>
|
<i class="fa fa-chevron-up pull-right" (click)="toggleHide($event, 'addon')"></i>
|
||||||
@@ -94,25 +106,25 @@
|
|||||||
<li class="sidebar__level-2--item" data-name="Key cluster" data-abbrev="">
|
<li class="sidebar__level-2--item" data-name="Key cluster" data-abbrev="">
|
||||||
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
||||||
<a [routerLink]="['/add-on', 'Key cluster']"
|
<a [routerLink]="['/add-on', 'Key cluster']"
|
||||||
[class.disabled]="updatingFirmware$ | async">Key cluster</a>
|
[class.disabled]="state.updatingFirmware">Key cluster</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li class="sidebar__level-2--item" data-name="Trackball" data-abbrev="">
|
<li class="sidebar__level-2--item" data-name="Trackball" data-abbrev="">
|
||||||
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
||||||
<a [routerLink]="['/add-on', 'Trackball']"
|
<a [routerLink]="['/add-on', 'Trackball']"
|
||||||
[class.disabled]="updatingFirmware$ | async">Trackball</a>
|
[class.disabled]="state.updatingFirmware">Trackball</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li class="sidebar__level-2--item" data-name="Toucpad" data-abbrev="">
|
<li class="sidebar__level-2--item" data-name="Toucpad" data-abbrev="">
|
||||||
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
||||||
<a [routerLink]="['/add-on', 'Touchpad']"
|
<a [routerLink]="['/add-on', 'Touchpad']"
|
||||||
[class.disabled]="updatingFirmware$ | async">Touchpad</a>
|
[class.disabled]="state.updatingFirmware">Touchpad</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li class="sidebar__level-2--item" data-name="Trackpoint" data-abbrev="">
|
<li class="sidebar__level-2--item" data-name="Trackpoint" data-abbrev="">
|
||||||
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
<div class="sidebar__level-2" [routerLinkActive]="['active']">
|
||||||
<a [routerLink]="['/add-on', 'Trackpoint']"
|
<a [routerLink]="['/add-on', 'Trackpoint']"
|
||||||
[class.disabled]="updatingFirmware$ | async">Trackpoint</a>
|
[class.disabled]="state.updatingFirmware">Trackpoint</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -123,17 +135,19 @@
|
|||||||
<div class="sidebar__level-0">
|
<div class="sidebar__level-0">
|
||||||
<i class="uhk-icon uhk-icon-agent-icon"></i> Agent
|
<i class="uhk-icon uhk-icon-agent-icon"></i> Agent
|
||||||
<i class="fa fa-chevron-up pull-right"
|
<i class="fa fa-chevron-up pull-right"
|
||||||
(click)="toggleHide($event, 'agent')"></i>
|
(click)="toggleHide($event, 'agent')"></i>
|
||||||
</div>
|
</div>
|
||||||
<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']">Settings</a>
|
<a [routerLink]="['/settings']"
|
||||||
|
[class.disabled]="state.updatingFirmware">Settings</a>
|
||||||
</div>
|
</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']">
|
||||||
<a [routerLink]="['/about']">About</a>
|
<a [routerLink]="['/about']"
|
||||||
|
[class.disabled]="state.updatingFirmware">About</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -9,6 +9,10 @@
|
|||||||
|
|
||||||
a {
|
a {
|
||||||
color: #333;
|
color: #333;
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
opacity: 0.65;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// General list styles for the sidebar-menu.
|
// General list styles for the sidebar-menu.
|
||||||
@@ -112,6 +116,10 @@ ul {
|
|||||||
&:focus {
|
&:focus {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
opacity: 0.65;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -164,12 +172,12 @@ ul {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0 0.25rem;
|
margin: 0 0.25rem;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
background-color: inherit;
|
background-color: transparent;
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
box-shadow: 0 0 0 1px #ccc, 0 0 5px 0 #ccc;
|
box-shadow: 0 0 0 1px #ccc, 0 0 5px 0 #ccc;
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
background-color: inherit;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,27 @@
|
|||||||
import { AfterContentInit, Component, ElementRef, OnDestroy, Renderer2, ViewChild } from '@angular/core';
|
import {
|
||||||
|
AfterContentInit,
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
ChangeDetectorRef,
|
||||||
|
Component,
|
||||||
|
ElementRef,
|
||||||
|
OnDestroy, OnInit,
|
||||||
|
Renderer2,
|
||||||
|
ViewChild
|
||||||
|
} from '@angular/core';
|
||||||
import { animate, state, style, transition, trigger } from '@angular/animations';
|
import { animate, state, style, transition, trigger } from '@angular/animations';
|
||||||
import { Keymap, Macro } from 'uhk-common';
|
|
||||||
|
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
|
|
||||||
import { Observable } from 'rxjs/Observable';
|
|
||||||
import { Subscription } from 'rxjs/Subscription';
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
import 'rxjs/add/operator/do';
|
import 'rxjs/add/operator/do';
|
||||||
import 'rxjs/add/operator/map';
|
import 'rxjs/add/operator/map';
|
||||||
import 'rxjs/add/operator/let';
|
import 'rxjs/add/operator/let';
|
||||||
|
|
||||||
import { AppState, getDeviceName, runningInElectron, showAddonMenu, updatingFirmware } from '../../store';
|
import { AppState, getSideMenuPageState } from '../../store';
|
||||||
import { MacroActions } from '../../store/actions';
|
import { MacroActions } from '../../store/actions';
|
||||||
import { getKeymaps, getMacros } from '../../store/reducers/user-configuration';
|
|
||||||
import * as util from '../../util';
|
import * as util from '../../util';
|
||||||
import { RenameUserConfigurationAction } from '../../store/actions/user-config';
|
import { RenameUserConfigurationAction } from '../../store/actions/user-config';
|
||||||
|
import { SideMenuPageState } from '../../models/side-menu-page-state';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
animations: [
|
animations: [
|
||||||
@@ -30,24 +37,19 @@ import { RenameUserConfigurationAction } from '../../store/actions/user-config';
|
|||||||
],
|
],
|
||||||
selector: 'side-menu',
|
selector: 'side-menu',
|
||||||
templateUrl: './side-menu.component.html',
|
templateUrl: './side-menu.component.html',
|
||||||
styleUrls: ['./side-menu.component.scss']
|
styleUrls: ['./side-menu.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class SideMenuComponent implements AfterContentInit, OnDestroy {
|
export class SideMenuComponent implements AfterContentInit, OnInit, OnDestroy {
|
||||||
showAddonMenu$: Observable<boolean>;
|
state: SideMenuPageState;
|
||||||
runInElectron$: Observable<boolean>;
|
|
||||||
updatingFirmware$: Observable<boolean>;
|
|
||||||
|
|
||||||
deviceName$: Observable<string>;
|
|
||||||
deviceNameSubscription: Subscription;
|
|
||||||
keymaps$: Observable<Keymap[]>;
|
|
||||||
macros$: Observable<Macro[]>;
|
|
||||||
animation: { [key: string]: 'active' | 'inactive' };
|
animation: { [key: string]: 'active' | 'inactive' };
|
||||||
deviceNameValue: string;
|
|
||||||
updatingFirmware = false;
|
|
||||||
updatingFirmwareSubscription: Subscription;
|
|
||||||
@ViewChild('deviceName') deviceName: ElementRef;
|
@ViewChild('deviceName') deviceName: ElementRef;
|
||||||
|
|
||||||
constructor(private store: Store<AppState>, private renderer: Renderer2) {
|
private stateSubscription: Subscription;
|
||||||
|
|
||||||
|
constructor(private store: Store<AppState>,
|
||||||
|
private renderer: Renderer2,
|
||||||
|
private cdRef: ChangeDetectorRef) {
|
||||||
this.animation = {
|
this.animation = {
|
||||||
device: 'active',
|
device: 'active',
|
||||||
configuration: 'active',
|
configuration: 'active',
|
||||||
@@ -55,29 +57,13 @@ export class SideMenuComponent implements AfterContentInit, OnDestroy {
|
|||||||
macro: 'active',
|
macro: 'active',
|
||||||
addon: 'active'
|
addon: 'active'
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
this.keymaps$ = store.let(getKeymaps())
|
ngOnInit(): void {
|
||||||
.map(keymaps => keymaps.slice()) // Creating a new array reference, because the sort is working in place
|
this.stateSubscription = this.store.select(getSideMenuPageState).subscribe(data => {
|
||||||
.do((keymaps: Keymap[]) => {
|
this.state = data;
|
||||||
keymaps.sort((first: Keymap, second: Keymap) => first.name.localeCompare(second.name));
|
|
||||||
});
|
|
||||||
|
|
||||||
this.macros$ = store.let(getMacros())
|
|
||||||
.map(macros => macros.slice()) // Creating a new array reference, because the sort is working in place
|
|
||||||
.do((macros: Macro[]) => {
|
|
||||||
macros.sort((first: Macro, second: Macro) => first.name.localeCompare(second.name));
|
|
||||||
});
|
|
||||||
|
|
||||||
this.showAddonMenu$ = this.store.select(showAddonMenu);
|
|
||||||
this.runInElectron$ = this.store.select(runningInElectron);
|
|
||||||
this.deviceName$ = store.select(getDeviceName);
|
|
||||||
this.deviceNameSubscription = this.deviceName$.subscribe(name => {
|
|
||||||
this.deviceNameValue = name;
|
|
||||||
this.setDeviceName();
|
this.setDeviceName();
|
||||||
});
|
this.cdRef.markForCheck();
|
||||||
this.updatingFirmware$ = store.select(updatingFirmware);
|
|
||||||
this.updatingFirmwareSubscription = this.updatingFirmware$.subscribe(updating => {
|
|
||||||
this.updatingFirmware = updating;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,12 +72,13 @@ export class SideMenuComponent implements AfterContentInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.deviceNameSubscription.unsubscribe();
|
if (this.stateSubscription) {
|
||||||
this.updatingFirmwareSubscription.unsubscribe();
|
this.stateSubscription.unsubscribe();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleHide(event: Event, type: string) {
|
toggleHide(event: Event, type: string) {
|
||||||
if (this.updatingFirmware) {
|
if (this.state.updatingFirmware) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +106,7 @@ export class SideMenuComponent implements AfterContentInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
editDeviceName(name: string): void {
|
editDeviceName(name: string): void {
|
||||||
if (!util.isValidName(name) || name.trim() === this.deviceNameValue) {
|
if (!util.isValidName(name) || name.trim() === this.state.deviceName) {
|
||||||
this.setDeviceName();
|
this.setDeviceName();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -135,7 +122,7 @@ export class SideMenuComponent implements AfterContentInit, OnDestroy {
|
|||||||
|
|
||||||
private setDeviceName(): void {
|
private setDeviceName(): void {
|
||||||
if (this.deviceName) {
|
if (this.deviceName) {
|
||||||
this.renderer.setProperty(this.deviceName.nativeElement, 'value', this.deviceNameValue);
|
this.renderer.setProperty(this.deviceName.nativeElement, 'value', this.state.deviceName);
|
||||||
this.calculateHeaderTextWidth(this.deviceName.nativeElement.value);
|
this.calculateHeaderTextWidth(this.deviceName.nativeElement.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { AfterViewInit, Component, EventEmitter, forwardRef, Input, Output, OnDestroy, ViewChild } from '@angular/core';
|
import { AfterViewInit, Component, EventEmitter, forwardRef, Input, Output, OnDestroy, ViewChild } from '@angular/core';
|
||||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||||
import { NouisliderComponent } from 'ng2-nouislider/src/nouislider';
|
import { NouisliderComponent } from 'ng2-nouislider';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { Observer } from 'rxjs/Observer';
|
import { Observer } from 'rxjs/Observer';
|
||||||
import 'rxjs/add/operator/debounceTime';
|
import 'rxjs/add/operator/debounceTime';
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" [attr.viewBox]="viewBox" height="100%" width="100%">
|
<svg xmlns="http://www.w3.org/2000/svg" [attr.viewBox]="viewBox" height="100%" width="100%">
|
||||||
<svg:g svg-module *ngFor="let module of modules; let i = index"
|
<svg:g svg-module *ngFor="let module of modules; let i = index"
|
||||||
[coverages]="module.coverages"
|
[coverages]="module.coverages"
|
||||||
[keyboardKeys]="module.keyboardKeys"
|
[keyboardKeys]="module.keyboardKeys"
|
||||||
[keybindAnimationEnabled]="keybindAnimationEnabled"
|
[keybindAnimationEnabled]="keybindAnimationEnabled"
|
||||||
[capturingEnabled]="capturingEnabled"
|
[capturingEnabled]="capturingEnabled"
|
||||||
[attr.transform]="module.attributes.transform"
|
[attr.transform]="module.attributes.transform"
|
||||||
[keyActions]="moduleConfig[i].keyActions"
|
[keyActions]="moduleConfig[i].keyActions"
|
||||||
[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.index, $event.keyTarget)"
|
||||||
(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.index, $event.captured)"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
|
<editable-text *ngIf="showDescription"
|
||||||
|
[ngModel]="description"
|
||||||
|
(ngModelChange)="descriptionChanged.emit($event)"
|
||||||
|
placeholder="No description provided for this keymap."></editable-text>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 854 B After Width: | Height: | Size: 1.0 KiB |
@@ -1,5 +1,10 @@
|
|||||||
:host {
|
:host {
|
||||||
display: flex;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
editable-text {
|
||||||
|
padding-left: 2em;
|
||||||
|
padding-right: 2em;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|||||||
@@ -31,9 +31,12 @@ export class SvgKeyboardComponent implements OnInit {
|
|||||||
@Input() selected: boolean;
|
@Input() selected: boolean;
|
||||||
@Input() halvesSplit: boolean;
|
@Input() halvesSplit: boolean;
|
||||||
@Input() keyboardLayout = KeyboardLayout.ANSI;
|
@Input() keyboardLayout = KeyboardLayout.ANSI;
|
||||||
|
@Input() description: string;
|
||||||
|
@Input() showDescription = false;
|
||||||
@Output() keyClick = new EventEmitter();
|
@Output() keyClick = new EventEmitter();
|
||||||
@Output() keyHover = new EventEmitter();
|
@Output() keyHover = new EventEmitter();
|
||||||
@Output() capture = new EventEmitter();
|
@Output() capture = new EventEmitter();
|
||||||
|
@Output() descriptionChanged = new EventEmitter<string>();
|
||||||
|
|
||||||
modules: SvgModule[];
|
modules: SvgModule[];
|
||||||
viewBox: string;
|
viewBox: string;
|
||||||
|
|||||||
@@ -7,9 +7,11 @@
|
|||||||
[selectedKey]="selectedKey"
|
[selectedKey]="selectedKey"
|
||||||
[halvesSplit]="halvesSplit"
|
[halvesSplit]="halvesSplit"
|
||||||
[keyboardLayout]="keyboardLayout"
|
[keyboardLayout]="keyboardLayout"
|
||||||
|
[description]="keymap.description"
|
||||||
(keyClick)="onKeyClick($event.moduleId, $event.keyId, $event.keyTarget)"
|
(keyClick)="onKeyClick($event.moduleId, $event.keyId, $event.keyTarget)"
|
||||||
(keyHover)="onKeyHover($event.moduleId, $event.event, $event.over, $event.keyId)"
|
(keyHover)="onKeyHover($event.moduleId, $event.event, $event.over, $event.keyId)"
|
||||||
(capture)="onCapture($event.moduleId, $event.keyId, $event.captured)"
|
(capture)="onCapture($event.moduleId, $event.keyId, $event.captured)"
|
||||||
|
(descriptionChanged)="onDescriptionChanged($event)"
|
||||||
></keyboard-slider>
|
></keyboard-slider>
|
||||||
<popover tabindex="0" [visible]="popoverShown" [keyPosition]="keyPosition" [wrapPosition]="wrapPosition" [defaultKeyAction]="popoverInitKeyAction"
|
<popover tabindex="0" [visible]="popoverShown" [keyPosition]="keyPosition" [wrapPosition]="wrapPosition" [defaultKeyAction]="popoverInitKeyAction"
|
||||||
[currentKeymap]="keymap" [currentLayer]="currentLayer" (cancel)="hidePopover()" (remap)="onRemap($event)"></popover>
|
[currentKeymap]="keymap" [currentLayer]="currentLayer" (cancel)="hidePopover()" (remap)="onRemap($event)"></popover>
|
||||||
|
|||||||
@@ -2,14 +2,16 @@ import {
|
|||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
Component,
|
Component,
|
||||||
ElementRef,
|
ElementRef,
|
||||||
Renderer,
|
EventEmitter,
|
||||||
HostBinding,
|
HostBinding,
|
||||||
HostListener,
|
HostListener,
|
||||||
Input,
|
Input,
|
||||||
OnChanges,
|
OnChanges,
|
||||||
OnInit,
|
OnInit,
|
||||||
ViewChild,
|
Output,
|
||||||
SimpleChanges
|
Renderer,
|
||||||
|
SimpleChanges,
|
||||||
|
ViewChild
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
|
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
@@ -25,10 +27,10 @@ import {
|
|||||||
KeystrokeAction,
|
KeystrokeAction,
|
||||||
Layer,
|
Layer,
|
||||||
LayerName,
|
LayerName,
|
||||||
SecondaryRoleAction,
|
|
||||||
MouseAction,
|
MouseAction,
|
||||||
MouseActionParam,
|
MouseActionParam,
|
||||||
PlayMacroAction,
|
PlayMacroAction,
|
||||||
|
SecondaryRoleAction,
|
||||||
SwitchKeymapAction,
|
SwitchKeymapAction,
|
||||||
SwitchLayerAction
|
SwitchLayerAction
|
||||||
} from 'uhk-common';
|
} from 'uhk-common';
|
||||||
@@ -38,6 +40,7 @@ import { AppState } from '../../../store';
|
|||||||
import { KeymapActions } from '../../../store/actions';
|
import { KeymapActions } from '../../../store/actions';
|
||||||
import { PopoverComponent } from '../../popover';
|
import { PopoverComponent } from '../../popover';
|
||||||
import { KeyboardLayout } from '../../../keyboard/keyboard-layout.enum';
|
import { KeyboardLayout } from '../../../keyboard/keyboard-layout.enum';
|
||||||
|
import { ChangeKeymapDescription } from '../../../models/ChangeKeymapDescription';
|
||||||
|
|
||||||
interface NameValuePair {
|
interface NameValuePair {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -56,6 +59,7 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges {
|
|||||||
@Input() tooltipEnabled: boolean = false;
|
@Input() tooltipEnabled: boolean = false;
|
||||||
@Input() halvesSplit: boolean;
|
@Input() halvesSplit: boolean;
|
||||||
@Input() keyboardLayout: KeyboardLayout.ANSI;
|
@Input() keyboardLayout: KeyboardLayout.ANSI;
|
||||||
|
@Output() descriptionChanged = new EventEmitter<ChangeKeymapDescription>();
|
||||||
|
|
||||||
@ViewChild(PopoverComponent, { read: ElementRef }) popover: ElementRef;
|
@ViewChild(PopoverComponent, { read: ElementRef }) popover: ElementRef;
|
||||||
|
|
||||||
@@ -237,6 +241,13 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges {
|
|||||||
return this.currentLayer;
|
return this.currentLayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onDescriptionChanged(description: string): void {
|
||||||
|
this.descriptionChanged.emit({
|
||||||
|
description,
|
||||||
|
abbr: this.keymap.abbreviation
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private getKeyActionContent(keyAction: KeyAction): Observable<NameValuePair[]> {
|
private getKeyActionContent(keyAction: KeyAction): Observable<NameValuePair[]> {
|
||||||
if (keyAction instanceof KeystrokeAction) {
|
if (keyAction instanceof KeystrokeAction) {
|
||||||
const keystrokeAction: KeystrokeAction = keyAction;
|
const keystrokeAction: KeystrokeAction = keyAction;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Store } from '@ngrx/store';
|
|||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
|
||||||
import { Notification } from 'uhk-common';
|
import { Notification } from 'uhk-common';
|
||||||
import { AppState, getUndoableNotification } from '../../store/index';
|
import { AppState, getUndoableNotification } from '../../store';
|
||||||
import { DismissUndoNotificationAction, UndoLastAction } from '../../store/actions/app';
|
import { DismissUndoNotificationAction, UndoLastAction } from '../../store/actions/app';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { AfterViewInit, Directive, ElementRef } from '@angular/core';
|
||||||
|
|
||||||
|
@Directive({
|
||||||
|
selector: '[autofocus]'
|
||||||
|
})
|
||||||
|
export class Autofocus implements AfterViewInit {
|
||||||
|
constructor(private el: ElementRef) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit() {
|
||||||
|
this.el.nativeElement.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export interface ChangeKeymapDescription {
|
||||||
|
abbr: string;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
5
packages/uhk-web/src/app/models/privilage-page-sate.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export interface PrivilagePageSate {
|
||||||
|
showWhatWillThisDo: boolean;
|
||||||
|
showWhatWillThisDoContent: boolean;
|
||||||
|
permissionSetupFailed: boolean;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export interface RestoreConfigurationState {
|
||||||
|
restoringUserConfiguration: boolean;
|
||||||
|
hasBackupUserConfiguration: boolean;
|
||||||
|
}
|
||||||
11
packages/uhk-web/src/app/models/side-menu-page-state.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { Keymap, Macro } from 'uhk-common';
|
||||||
|
|
||||||
|
export interface SideMenuPageState {
|
||||||
|
showAddonMenu: boolean;
|
||||||
|
runInElectron: boolean;
|
||||||
|
updatingFirmware: boolean;
|
||||||
|
deviceName: string;
|
||||||
|
keymaps: Keymap[];
|
||||||
|
macros: Macro[];
|
||||||
|
restoreUserConfiguration: boolean;
|
||||||
|
}
|
||||||
@@ -94,7 +94,7 @@ export class CaptureService {
|
|||||||
this.mapping.set(88, 27); // X
|
this.mapping.set(88, 27); // X
|
||||||
this.mapping.set(89, 28); // Y
|
this.mapping.set(89, 28); // Y
|
||||||
this.mapping.set(90, 29); // Z
|
this.mapping.set(90, 29); // Z
|
||||||
this.mapping.set(93, 118); // Menu
|
this.mapping.set(93, 101); // Menu
|
||||||
this.mapping.set(96, 98); // Num pad 0
|
this.mapping.set(96, 98); // Num pad 0
|
||||||
this.mapping.set(97, 89); // Num pad 1
|
this.mapping.set(97, 89); // Num pad 1
|
||||||
this.mapping.set(98, 90); // Num pad 2
|
this.mapping.set(98, 90); // Num pad 2
|
||||||
|
|||||||