44 Commits

Author SHA1 Message Date
Róbert Kiss
b53751b408 chore(kboot): add more logging (#1008)
* chore(kboot): add more logging

* fix: add uncaughtException handler

* fix: wait to prevent race condition

* fix: don't close device after success left keyboard connection

* revert: remove extra delay

* revert: add back the waiting

* fix: always initialize new KBoot instance when try to configure I2C

* fix: increase the wait time between 2 IC2 reconnection

* fix: timing and usb reconnection

* fix: dont close kboot device

* feat: append the WithKboot to the firmware upgrade methods

* feat: revert back the blhost functionality
2019-09-13 10:17:44 +02:00
Róbert Kiss
8a7f30dbb1 chore: upgrade angular => 8.2.6 and cli => 8.3.4 (#1038) 2019-09-12 21:02:45 +02:00
László Monda
3b67e4d71d Update README.md 2019-09-11 22:16:51 +02:00
Róbert Kiss
d0626405a9 fix: es6 module loading (#1036)
The modification helps to handle correctly the ES6 default exports.
The firmware upgrade run correctly in the electron version and
kboot-firmware-upgrade.ts script
2019-09-09 22:14:34 +02:00
Róbert Kiss
df040fb78e chore: upgrade electron-builder => 20.44.4 and updater => 4.1.2 (#1035) 2019-09-09 20:31:12 +02:00
Róbert Kiss
ea4ca7c39c chore: upgrade npm-run-all => 4.1.5 (#1034) 2019-09-07 08:43:29 +02:00
Róbert Kiss
c477f9bcdc chore: upgrade check-node-version => 4.0.1 (#1033) 2019-09-06 20:48:20 +02:00
Róbert Kiss
abe740cf61 chore: remove old webpack dependencies (#1032) 2019-09-04 20:58:39 +02:00
Róbert Kiss
1003e7b14b chore: upgrade jsonfile => 5.0.0 (#1031) 2019-09-04 19:19:28 +02:00
Róbert Kiss
fef24613e4 feat: show macro usage count (#1030)
* feat: show macro usage count

* feat: show macro reference count only when ALT key hold down

* fix: the macro reference help text
2019-09-03 21:42:27 +02:00
László Monda
9844645409 Upgrade to firmware 8.6.0 2019-08-29 23:22:20 +02:00
László Monda
6814c8e126 Merge branch 'master' of github.com:UltimateHackingKeyboard/agent 2019-08-25 13:48:10 +02:00
Róbert Kiss
d87d770042 chore: rebuild the root package-lock.json to refresh deps of deps (#1029) 2019-08-25 13:46:50 +02:00
László Monda
5dc2e6f47b Merge branch 'master' of github.com:UltimateHackingKeyboard/agent 2019-08-24 16:18:56 +02:00
Róbert Kiss
9f8926e34b chore: rebuild the uhk-web package-lock.json to refresh deps of deps (#1028) 2019-08-24 14:03:58 +02:00
Róbert Kiss
0bd1152a32 chore: upgrade copyfiles => 2.1.1 (#1027) 2019-08-23 23:19:00 +02:00
Róbert Kiss
4a1e88ed83 chore: upgrade angular => 8.2.3 (#1026) 2019-08-23 22:48:43 +02:00
Róbert Kiss
9db719a54b chore: upgrade electron-rebuild => 1.8.6 (#1025) 2019-08-23 22:11:11 +02:00
dgyimesi
49d31f90f7 feat: support more mouse buttons (#936)
* feat: support more mouse buttons (#834)

* Remove unused style.

* Retrigger CI

* fix: more button click and texts

* fix: the mouse button 4-8 naming

* feat: allow extra mouse buttons if userConfig version >= 4.1.1

* fix: version comparison

* fix: read correctly the right module informations
2019-08-23 22:00:01 +02:00
László Monda
d364ac85a6 Merge branch 'master' of github.com:UltimateHackingKeyboard/agent 2019-08-23 21:32:39 +02:00
Róbert Kiss
fae83a4148 chore: upgrade @types/decompress => 4.2.3 (#1023) 2019-08-23 20:30:51 +02:00
Róbert Kiss
ac76674469 chore: add convert-user-config-to-bin npm script (#1022)
usage of the script
`$ npm run convert-user-config-to-bin -- <path of the bin file>`
2019-08-23 19:33:14 +02:00
László Monda
6867ef45f6 Merge branch 'master' of github.com:UltimateHackingKeyboard/agent 2019-08-21 21:18:51 +02:00
Róbert Kiss
239c989cbe feat: Make the UHK of the web build split instead of merged (#1021) 2019-08-21 21:15:32 +02:00
László Monda
bfa8343aa5 Merge branch 'master' of github.com:UltimateHackingKeyboard/agent 2019-08-21 21:03:09 +02:00
Róbert Kiss
0914a1496b fix: confirmation popover titles (#1019) 2019-08-20 16:02:29 +02:00
László Monda
a8c2866f95 Merge branch 'master' of github.com:UltimateHackingKeyboard/agent 2019-08-20 15:39:52 +02:00
Róbert Kiss
79f467603a feat: scroll to the end of the firmware log when success of faild panel visible (#1018) 2019-08-20 15:33:28 +02:00
Róbert Kiss
c4269d4cf1 chore: use preserveWhitespaces = true in electron renderer (#1017)
The `npm run server:electron` build result much more simmilar to the production build
2019-08-20 15:19:00 +02:00
László Monda
d15e08430f Merge branch 'master' of github.com:UltimateHackingKeyboard/agent 2019-08-20 13:21:16 +02:00
Róbert Kiss
ee28065046 chore: upgrade angular => 8.2.2 (#996)
* chore: upgrade angular => 8.2.2

Summary:
- upgrade angular => 8.2.2
- setup the { static: false/true } for the ViewChild
- use alignment-baseline="middle" in svg text to align correct the texts

* fix: keymap popover crash
2019-08-20 12:54:23 +02:00
László Monda
a64a44fe41 Update NPM_UPDATES.md 2019-08-18 22:52:09 +02:00
László Monda
fa5f5cdc5d Merge branch 'master' of github.com:UltimateHackingKeyboard/agent 2019-08-18 21:59:16 +02:00
Róbert Kiss
4147243565 chore: upgrade electron => 5.0.9 (#1014)
Summary:
- Chromium: 73.0.3683.119
- Node.js: 12.0.0
- V8 engine: 7.3.492.27
2019-08-18 13:27:20 +02:00
Róbert Kiss
905007a597 chore: upgrade node-hid => 0.7.9 (#1011) 2019-08-14 17:10:39 +02:00
László Monda
c3fec647b6 Update ISSUE_TEMPLATE 2019-08-14 17:06:53 +02:00
László Monda
5f5aff71a5 Create NPM_UPDATES.md 2019-08-14 17:04:19 +02:00
László Monda
f65bf80c74 Merge branch 'master' of github.com:UltimateHackingKeyboard/agent 2019-08-03 12:51:19 +02:00
Róbert Kiss
f6bef928fe chore(usb): add kboot-firmware-upgrade script (#1006) 2019-08-02 02:51:07 +02:00
László Monda
b691f866c5 Merge branch 'master' of github.com:UltimateHackingKeyboard/agent 2019-08-01 23:48:43 +02:00
Róbert Kiss
5ab5ad5f0c feat: ESC cancel the keymap description editing (#1007) 2019-07-31 10:03:29 +02:00
László Monda
4e09f95653 Merge branch 'master' of github.com:UltimateHackingKeyboard/agent 2019-07-30 22:24:00 +02:00
László Monda
37a67805ce Merge branch 'master' of github.com:UltimateHackingKeyboard/agent 2019-07-28 21:34:55 +02:00
László Monda
735aae03d9 Update changelog. 2019-07-28 21:10:47 +02:00
101 changed files with 10654 additions and 12916 deletions

2
.nvmrc
View File

@@ -1 +1 @@
10.11.0
12.0.0

View File

@@ -13,7 +13,9 @@ Firmware: 8.5.**4** [[release](https://github.com/UltimateHackingKeyboard/firmwa
- Implement the Kinetis bootloader protocol natively instead of relying on blhost.
- Fix device recovery mode.
- Correctly display whether the UHK is detected.
- Animate keyboard splitting, merging, and the presence of the left half.
- Don't disable input in the key action popover after adding a layer switch action, deleting it, and trying to edit it on its layer.
- Provide reasonable default mouse settings for Macs.
- Don't change tab immediately upon closing the key action popover.
- Fix UI glitch that occurrs when hitting Tab after updating keymap description.
- Make the Agent icon slightly smaller to be consistent with most application icons.

View File

@@ -6,3 +6,5 @@ Before submitting a new issue, make sure to do the following:
3. Use Agent to update to the latest firmware:
https://github.com/UltimateHackingKeyboard/firmware/releases/latest
4. Try to reproduce the issue, and only report it if it still persists.
`npm audit` related issues will be closed due to https://github.com/UltimateHackingKeyboard/agent/blob/master/NPM_UPDATES.md

8
NPM_UPDATES.md Normal file
View File

@@ -0,0 +1,8 @@
We get requests from time to time to update our NPM dependencies because they contain vulnerabilities according to `npm audit`. Such issues will be closed without further consideration due to the following reasons:
1. Usually, the affected packages are not runtime dependencies of Agent, but devDependencies which are only needed for developing Agent.
2. Often times, 3rd party packages are affected by vulnerabilities which we cannot fix.
3. We can't just blindly update all of the packages because that'd likely break Agent as it has happened in the past. Each of the updates must be carefully tested, and we don't have the manpower to do it on a daily basis.
4. Sometimes `npm audit` signals false vulnerabilities.
We routinely update our dependencies on a best effort basis.

View File

@@ -12,7 +12,7 @@ Agent is the configuration application of the [Ultimate Hacking Keyboard](https:
### Step 1: Build Dependencies
You'll need Node.js LTS. Use your OS package manager to install it. [Check the NodeJS site for more info.](https://nodejs.org/en/download/package-manager/ "Installing Node.js via package manager") Mac OS users can simply `brew install node` to get both. Should you need multiple Node.js versions on the same computer, use Node Version Manager for [Mac/Linux](https://github.com/creationix/nvm) or for [Windows](https://github.com/coreybutler/nvm-windows)
You'll need Node.js 12. Use your OS package manager to install it. [Check the NodeJS site for more info.](https://nodejs.org/en/download/package-manager/ "Installing Node.js via package manager") Mac OS users can simply `brew install node` to get both. Should you need multiple Node.js versions on the same computer, use Node Version Manager for [Mac/Linux](https://github.com/creationix/nvm) or for [Windows](https://github.com/coreybutler/nvm-windows)
You'll also need `libusb`.
On debian-based linux distros, `apt-get install libusb-dev libudev-dev g++` is sufficient.

View File

@@ -7,7 +7,7 @@ environment:
secure: 3IebpEKmC39codi1wT6dXx8mql4/mCL1JzZ7lir7GQ5MWRnCxlED2OXbiKHHigDV
CSC_LINK: c:\projects\uhk-agent\scripts\certs\windows-cert.p12
matrix:
- nodejs_version: "10.11.0"
- nodejs_version: "12.0.0"
cache:
- node_modules -> package.json

11863
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,9 +4,9 @@
"author": "Ultimate Gadget Laboratories",
"main": "electron/dist/electron-main.js",
"version": "1.2.13",
"firmwareVersion": "8.5.4",
"deviceProtocolVersion": "4.4.0",
"userConfigVersion": "4.0.1",
"firmwareVersion": "8.6.0",
"deviceProtocolVersion": "4.5.0",
"userConfigVersion": "4.1.1",
"hardwareConfigVersion": "1.0.0",
"description": "Agent is the configuration application of the Ultimate Hacking Keyboard.",
"repository": {
@@ -15,11 +15,11 @@
},
"license": "GPL-3.0",
"engines": {
"node": ">=10.2.1 <11.0.0",
"npm": ">=6.4.0 <7.0.0"
"node": ">=12.0.0 <13.0.0",
"npm": ">=6.9.0 <7.0.0"
},
"devDependencies": {
"@types/decompress": "4.2.0",
"@types/decompress": "4.2.3",
"@types/electron-devtools-installer": "2.0.2",
"@types/electron-settings": "3.0.0",
"@types/file-saver": "0.0.1",
@@ -27,47 +27,42 @@
"@types/jasmine": "3.3.12",
"@types/jasminewd2": "2.0.3",
"@types/jquery": "3.3.29",
"@types/jsonfile": "4.0.1",
"@types/jsonfile": "5.0.0",
"@types/lodash": "4.14.136",
"@types/node": "8.0.53",
"@types/node-hid": "0.7.0",
"@types/node-hid": "0.7.2",
"@types/request": "2.0.8",
"@types/semver": "5.5.0",
"@types/tmp": "0.0.33",
"autoprefixer": "6.5.3",
"buffer": "5.0.6",
"check-node-version": "^3.2.0",
"check-node-version": "4.0.1",
"copy-webpack-plugin": "5.0.0",
"copyfiles": "^2.0.0",
"copyfiles": "2.1.1",
"core-js": "2.4.1",
"cross-env": "5.0.5",
"decompress": "4.2.0",
"decompress-tarbz2": "4.1.1",
"devtron": "1.4.0",
"electron": "4.2.8",
"electron-builder": "20.34.0",
"electron": "5.0.9",
"electron-builder": "20.44.4",
"electron-debug": "1.5.0",
"electron-devtools-installer": "2.2.3",
"electron-log": "2.2.16",
"electron-rebuild": "1.8.5",
"electron-rebuild": "1.8.6",
"electron-settings": "3.1.4",
"electron-updater": "2.21.4",
"exports-loader": "0.6.3",
"file-loader": "0.10.0",
"electron-updater": "4.1.2",
"fs-extra": "8.1.0",
"gh-pages": "2.0.1",
"html-webpack-plugin": "3.2.0",
"jasmine": "3.4.0",
"jasmine-core": "3.4.0",
"jasmine-node": "3.0.0",
"jasmine-ts": "0.3.0",
"jsonfile": "4.0.0",
"jsonfile": "5.0.0",
"lerna": "3.16.4",
"lodash": "4.17.15",
"node-hid": "0.7.8",
"npm-run-all": "4.0.2",
"node-hid": "0.7.9",
"npm-run-all": "4.1.5",
"nrf-intel-hex": "1.3.0",
"postcss-url": "8.0.0",
"pre-commit": "1.2.2",
"request": "2.88.0",
"rimraf": "2.6.1",
@@ -96,11 +91,13 @@
"server:electron": "lerna exec --scope uhk-web npm run server:renderer",
"electron": "lerna exec --scope uhk-agent npm start",
"electron:spe": "lerna exec --scope uhk-agent npm run electron:spe",
"electron:kboot": "lerna exec --scope uhk-agent npm run electron:kboot",
"pack": "node ./scripts/release.js",
"sprites": "node ./scripts/generate-svg-sprites",
"release": "node ./scripts/release.js",
"clean": "lerna exec rimraf ./node_modules ./dist && rimraf ./node_modules ./dist ./tmp",
"predeploy-gh-pages": "lerna run build:web --scope=uhk-web",
"deploy-gh-pages": "gh-pages -d packages/uhk-web/dist"
"deploy-gh-pages": "gh-pages -d packages/uhk-web/dist",
"convert-user-config-to-bin": "node -r ts-node/register ./packages/usb/user-config-json-to-bin.ts"
}
}

View File

@@ -24,13 +24,16 @@
}
},
"bindings": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.1.tgz",
"integrity": "sha512-i47mqjF9UbjxJhxGf+pZ6kSxrnI3wBLlnGI2ArWJ4r0VrvDS7ZYXkprq/pLaBWYq4GM0r4zdHY+NNRqEMU7uew=="
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
"requires": {
"file-uri-to-path": "1.0.0"
}
},
"bl": {
"version": "1.2.2",
"resolved": "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
"resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
"integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
"requires": {
"readable-stream": "^2.3.5",
@@ -69,9 +72,9 @@
}
},
"chownr": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
"integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g=="
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.2.tgz",
"integrity": "sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A=="
},
"code-point-at": {
"version": "1.1.0",
@@ -137,6 +140,11 @@
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="
},
"file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
},
"fs-constants": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
@@ -173,9 +181,9 @@
"integrity": "sha512-dDlJhYk8BAmH1HDncTjCt6xOm2+kT+MxGhRKB+mUoF8nocDzPAgZPEWTRI9QgkGvbDkbJgCqyxweGlIV0yhbUQ=="
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"ini": {
"version": "1.3.5",
@@ -202,12 +210,12 @@
},
"minimist": {
"version": "1.2.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
},
"mkdirp": {
"version": "0.5.1",
"resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"requires": {
"minimist": "0.0.8"
@@ -215,7 +223,7 @@
"dependencies": {
"minimist": {
"version": "0.0.8",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
}
}
@@ -226,9 +234,9 @@
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
},
"nan": {
"version": "2.12.1",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz",
"integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw=="
"version": "2.14.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
"integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg=="
},
"napi-build-utils": {
"version": "1.0.1",
@@ -236,21 +244,21 @@
"integrity": "sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA=="
},
"node-abi": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.5.1.tgz",
"integrity": "sha512-oDbFc7vCFx0RWWCweTer3hFm1u+e60N5FtGnmRV6QqvgATGFH/XRR6vqWIeBVosCYCqt6YdIr2L0exLZuEdVcQ==",
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.11.0.tgz",
"integrity": "sha512-kuy/aEg75u40v378WRllQ4ZexaXJiCvB68D2scDXclp/I4cRq6togpbOoKhmN07tns9Zldu51NNERo0wehfX9g==",
"requires": {
"semver": "^5.4.1"
}
},
"node-hid": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/node-hid/-/node-hid-0.7.4.tgz",
"integrity": "sha512-gvgNDPoszObn7avIDYMUvVv1T0xQB4/CZFJWckra/LXAc0qHYho4M1LCnCKlLIocL2R5/3qGv0J4AjRMdwgjxg==",
"version": "0.7.9",
"resolved": "https://registry.npmjs.org/node-hid/-/node-hid-0.7.9.tgz",
"integrity": "sha512-vJnonTqmq3frCyTumJqG4g2IZcny3ynkfmbfDfQ90P3ZhRzcWYS/Um1ux6HFmAxmkaQnrZqIYHcGpL7kdqY8jA==",
"requires": {
"bindings": "^1.3.0",
"nan": "^2.10.0",
"prebuild-install": "^5.2.1"
"bindings": "^1.5.0",
"nan": "^2.13.2",
"prebuild-install": "^5.3.0"
}
},
"noop-logger": {
@@ -289,13 +297,13 @@
},
"os-homedir": {
"version": "1.0.2",
"resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
},
"prebuild-install": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.2.2.tgz",
"integrity": "sha512-4e8VJnP3zJdZv/uP0eNWmr2r9urp4NECw7Mt1OSAi3rcLrbBRxGiAkfUFtre2MhQ5wfREAjRV+K1gubvs/GPsA==",
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.0.tgz",
"integrity": "sha512-aaLVANlj4HgZweKttFNUVNRxDukytuIuxeK2boIMHjagNJCiVKWFsKF4tCE3ql3GbrD2tExPQ7/pwtEJcHNZeg==",
"requires": {
"detect-libc": "^1.0.3",
"expand-template": "^2.0.3",
@@ -303,7 +311,7 @@
"minimist": "^1.2.0",
"mkdirp": "^0.5.1",
"napi-build-utils": "^1.0.1",
"node-abi": "^2.2.0",
"node-abi": "^2.7.0",
"noop-logger": "^0.1.1",
"npmlog": "^4.0.1",
"os-homedir": "^1.0.1",
@@ -316,9 +324,9 @@
}
},
"process-nextick-args": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"pump": {
"version": "2.0.1",
@@ -342,7 +350,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"requires": {
"core-util-is": "~1.0.0",
@@ -360,9 +368,9 @@
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"semver": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
"integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg=="
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
},
"set-blocking": {
"version": "2.0.0",
@@ -391,7 +399,7 @@
},
"string-width": {
"version": "1.0.2",
"resolved": "http://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"requires": {
"code-point-at": "^1.0.0",
@@ -401,7 +409,7 @@
},
"string_decoder": {
"version": "1.1.1",
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
@@ -409,7 +417,7 @@
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"requires": {
"ansi-regex": "^2.0.0"
@@ -516,9 +524,9 @@
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"xtend": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
}
}
}

View File

@@ -9,15 +9,11 @@
"url": "git@github.com:UltimateHackingKeyboard/agent.git"
},
"license": "GPL-3.0",
"engines": {
"node": ">=8.12.0 <9.0.0",
"npm": ">=6.4.1 <7.0.0"
},
"dependencies": {
"debug": "^4.1.1",
"byte-data": "^16.0.3",
"tslib": "^1.10.0",
"node-hid": ">= 0.7.3"
"node-hid": ">= 0.7.9"
},
"peer-dependencies": {},
"scripts": {

View File

@@ -12,15 +12,19 @@ export class KBoot {
}
open(): void {
logger('Open peripheral');
this.peripheral.open();
}
close(): void {
logger('Close peripheral');
this.peripheral.close();
}
// ================= Read properties ==================
async getProperty(property: Properties, memoryId = MemoryIds.Internal): Promise<CommandResponse> {
logger('Start read memory %o', { property, memoryId });
const command: CommandOption = {
command: Commands.GetProperty,
params: [
@@ -32,14 +36,17 @@ export class KBoot {
const response = await this.peripheral.sendCommand(command);
if (response.tag !== ResponseTags.Property) {
logger('Response tag is not property response: %d', property);
throw new Error('Response tag is not property response');
}
if (response.code === ResponseCodes.UnknownProperty) {
logger('Unknown property %d', response.code);
throw new Error('Unknown property!');
}
if (response.code !== ResponseCodes.Success) {
logger('Unknown error %d', response.code);
throw new Error(`Unknown error. Error code:${response.code}`);
}
@@ -47,6 +54,8 @@ export class KBoot {
}
async getBootloaderVersion(): Promise<BootloaderVersion> {
logger('Start to read Bootloader Version');
const response = await this.getProperty(Properties.BootloaderVersion);
const version: BootloaderVersion = {
@@ -64,7 +73,9 @@ export class KBoot {
// ================= End read properties ==================
async flashSecurityDisable(key: number[]): Promise<void> {
logger('Start flash security disable %o', { key });
if (key.length !== 8) {
logger('Error: Flash security key must be 8 byte. %o', key);
throw new Error('Flash security key must be 8 byte');
}
@@ -76,15 +87,18 @@ export class KBoot {
const response = await this.peripheral.sendCommand(command);
if (response.tag !== ResponseTags.Generic) {
logger('Response tag is not generic response: %d', response.tag);
throw new Error('Response tag is not generic response');
}
if (response.code !== ResponseCodes.Success) {
logger('Can not disable flash security: %d', response.code);
throw new Error(`Can not disable flash security`);
}
}
async flashEraseRegion(startAddress: number, count: number): Promise<void> {
logger('Start flash erase region');
const command: CommandOption = {
command: Commands.FlashEraseRegion,
params: [
@@ -96,15 +110,18 @@ export class KBoot {
const response = await this.peripheral.sendCommand(command);
if (response.tag !== ResponseTags.Generic) {
logger('Response tag is not generic response: %d', response.tag);
throw new Error('Response tag is not generic response');
}
if (response.code !== ResponseCodes.Success) {
throw new Error(`Can not disable flash security`);
logger('Can not flash erase region: %d', response.code);
throw new Error(`Can not flash erase region`);
}
}
async flashEraseAllUnsecure(): Promise<void> {
logger('Start flash erase all unsecure');
const command: CommandOption = {
command: Commands.FlashEraseAllUnsecure,
params: []
@@ -113,19 +130,23 @@ export class KBoot {
const response = await this.peripheral.sendCommand(command);
if (response.tag !== ResponseTags.Generic) {
logger('Response tag is not generic response: %d', response.tag);
throw new Error('Response tag is not generic response');
}
if (response.code !== ResponseCodes.Success) {
throw new Error(`Can not disable flash security`);
logger('Can not flash erase all unsecure: %d', response.code);
throw new Error(`Can not flash erase all unsecure`);
}
}
async readMemory(startAddress: number, count: number): Promise<any> {
logger('Start read memory %o', { startAddress, count });
return this.peripheral.readMemory(startAddress, count);
}
async writeMemory(options: DataOption): Promise<void> {
logger('Start write memory %o', { options });
return this.peripheral.writeMemory(options);
}
@@ -133,6 +154,7 @@ export class KBoot {
* Reset the bootloader
*/
async reset(): Promise<void> {
logger('Start reset the bootloader');
const command: CommandOption = {
command: Commands.Reset,
params: []
@@ -154,10 +176,12 @@ export class KBoot {
}
if (response.tag !== ResponseTags.Generic) {
logger('Response tag is not generic response: %d', response.tag);
throw new Error('Response tag is not generic response');
}
if (response.code !== ResponseCodes.Success) {
logger('Unknown error %d', response.code);
throw new Error(`Unknown error. Error code:${response.code}`);
}
}
@@ -168,8 +192,9 @@ export class KBoot {
* @param [speed=64] - Speed of the I2C
*/
async configureI2c(address: number, speed = 64): Promise<void> {
logger('Start configure I2C', { address, speed });
if (address > 127) {
logger('Only 7-bit i2c address is supported');
throw new Error('Only 7-bit i2c address is supported');
}
@@ -184,10 +209,12 @@ export class KBoot {
const response = await this.peripheral.sendCommand(command);
if (response.tag !== ResponseTags.Generic) {
logger('Response tag is not generic response: %d', response.tag);
throw new Error('Response tag is not generic response');
}
if (response.code !== ResponseCodes.Success) {
logger('Unknown error %d', response.code);
throw new Error(`Unknown error. Error code:${response.code}`);
}
}

View File

@@ -55,6 +55,8 @@ export class UsbPeripheral implements Peripheral {
close(): void {
if (this._device) {
this._device.close();
this._device.removeAllListeners('data');
this._device.removeAllListeners('error');
this._device = undefined;
}
}
@@ -222,6 +224,7 @@ export class UsbPeripheral implements Peripheral {
}
private _readFromBuffer(bufferName: string, byte: number, timeout: number): Promise<Buffer> {
logger('start read from buffer %o', { bufferName, byte, timeout });
return new Promise<Buffer>(async (resolve, reject) => {
const startTime = new Date();
while (startTime.getTime() + timeout > new Date().getTime()) {
@@ -266,6 +269,7 @@ export class UsbPeripheral implements Peripheral {
}
private async _getNextCommandResponse(): Promise<CommandResponse> {
logger('Start read next command response');
const response = await this._readFromCommandStream();
const commandResponse = decodeCommandResponse(response);
logger('next command response: %o', commandResponse);

View File

@@ -32,9 +32,9 @@
}
},
"base64-js": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz",
"integrity": "sha1-EQHpVE9KdrG8OybUUsqW16NeeXg="
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
"integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
},
"bindings": {
"version": "1.5.0",
@@ -54,24 +54,42 @@
}
},
"buffer": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz",
"integrity": "sha1-pyyTb3e5a/UvX357RnGAYoVR3vs=",
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.0.tgz",
"integrity": "sha512-Xpgy0IwHK2N01ncykXTy6FpCWuM+CJSHoPVBLyNqyrWxsedpLvwsYUhf0ME3WRFNUhos0dMamz9cOS/xRDtU5g==",
"requires": {
"base64-js": "0.0.8",
"ieee754": "^1.1.4",
"isarray": "^1.0.0"
"base64-js": "^1.0.2",
"ieee754": "^1.1.4"
}
},
"buffer-alloc": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
"integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==",
"requires": {
"buffer-alloc-unsafe": "^1.1.0",
"buffer-fill": "^1.0.0"
}
},
"buffer-alloc-unsafe": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
"integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg=="
},
"buffer-crc32": {
"version": "0.2.13",
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
"integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI="
},
"buffer-fill": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
"integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw="
},
"chownr": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
"integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g=="
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.2.tgz",
"integrity": "sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A=="
},
"code-point-at": {
"version": "1.1.0",
@@ -231,9 +249,9 @@
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="
},
"fd-slicer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz",
"integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
"integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
"requires": {
"pend": "~1.2.0"
}
@@ -267,6 +285,11 @@
}
}
},
"fs-constants": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
},
"gauge": {
"version": "2.7.4",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
@@ -297,9 +320,9 @@
"integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4="
},
"graceful-fs": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.1.tgz",
"integrity": "sha512-b9usnbDGnD928gJB3LrCmxoibr3VE4U2SMo5PBuBnokWyDADTqDPXg4YpwKF1trpH+UbGp7QLicO3+aWEy0+mw=="
},
"graceful-readlink": {
"version": "1.0.1",
@@ -312,14 +335,14 @@
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
},
"ieee754": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.11.tgz",
"integrity": "sha512-VhDzCKN7K8ufStx/CLj5/PDTMgph+qwN5Pkd5i0sGnVwk56zJ0lkT8Qzi1xqWLS0Wp29DgDtNeS7v8/wMoZeHg=="
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
"integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"ini": {
"version": "1.3.5",
@@ -350,9 +373,9 @@
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"make-dir": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.2.0.tgz",
"integrity": "sha512-aNUAa4UMg/UougV25bbrU4ZaaKNjJ/3/xnvg/twpmKROPdKZPZ9wGgI0opdZzO8q/zUFawoUuixuOv33eZ61Iw==",
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
"integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
"requires": {
"pify": "^3.0.0"
},
@@ -400,17 +423,17 @@
"integrity": "sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA=="
},
"node-abi": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.8.0.tgz",
"integrity": "sha512-1/aa2clS0pue0HjckL62CsbhWWU35HARvBDXcJtYKbYR7LnIutmpxmXbuDMV9kEviD2lP/wACOgWmmwljghHyQ==",
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.11.0.tgz",
"integrity": "sha512-kuy/aEg75u40v378WRllQ4ZexaXJiCvB68D2scDXclp/I4cRq6togpbOoKhmN07tns9Zldu51NNERo0wehfX9g==",
"requires": {
"semver": "^5.4.1"
}
},
"node-hid": {
"version": "0.7.8",
"resolved": "https://registry.npmjs.org/node-hid/-/node-hid-0.7.8.tgz",
"integrity": "sha512-79Z9hw/pqIDp0kxvb353ivGgslo4i0hYQTcCqfRFxIJSO2gF9VtPla5uQY/9jTcDlON5O5YaqxbdH+8bs+m+1Q==",
"version": "0.7.9",
"resolved": "https://registry.npmjs.org/node-hid/-/node-hid-0.7.9.tgz",
"integrity": "sha512-vJnonTqmq3frCyTumJqG4g2IZcny3ynkfmbfDfQ90P3ZhRzcWYS/Um1ux6HFmAxmkaQnrZqIYHcGpL7kdqY8jA==",
"requires": {
"bindings": "^1.5.0",
"nan": "^2.13.2",
@@ -508,9 +531,9 @@
}
},
"process-nextick-args": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"pump": {
"version": "2.0.1",
@@ -544,12 +567,19 @@
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
},
"dependencies": {
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
}
}
},
"safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
"integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
},
"seek-bzip": {
"version": "1.0.5",
@@ -560,9 +590,9 @@
}
},
"semver": {
"version": "5.7.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA=="
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
},
"set-blocking": {
"version": "2.0.0",
@@ -605,6 +635,13 @@
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
},
"dependencies": {
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
}
}
},
"strip-ansi": {
@@ -656,13 +693,16 @@
}
},
"tar-stream": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.5.tgz",
"integrity": "sha512-mQdgLPc/Vjfr3VWqWbfxW8yQNiJCbAZ+Gf6GDu1Cy0bdb33ofyiNGBtAY96jHFhDuivCwgW1H9DgTON+INiXgg==",
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz",
"integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==",
"requires": {
"bl": "^1.0.0",
"buffer-alloc": "^1.2.0",
"end-of-stream": "^1.0.0",
"readable-stream": "^2.0.0",
"fs-constants": "^1.0.0",
"readable-stream": "^2.3.0",
"to-buffer": "^1.1.1",
"xtend": "^4.0.0"
}
},
@@ -698,6 +738,11 @@
"os-tmpdir": "~1.0.2"
}
},
"to-buffer": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz",
"integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg=="
},
"tslib": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
@@ -717,12 +762,12 @@
"integrity": "sha1-XAgOXWYcu+OCWdLnCjxyU+hziB0="
},
"unbzip2-stream": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.2.5.tgz",
"integrity": "sha512-izD3jxT8xkzwtXRUZjtmRwKnZoeECrfZ8ra/ketwOcusbZEp4mjULMnJOCfTDZBgGQAAY1AJ/IgxcwkavcX9Og==",
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz",
"integrity": "sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg==",
"requires": {
"buffer": "^3.0.1",
"through": "^2.3.6"
"buffer": "^5.2.1",
"through": "^2.3.8"
}
},
"util-deprecate": {
@@ -749,17 +794,17 @@
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"xtend": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
},
"yauzl": {
"version": "2.9.1",
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.9.1.tgz",
"integrity": "sha1-qBmB6nCleUYTOIPwKcWCGok1mn8=",
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
"integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
"requires": {
"buffer-crc32": "~0.2.3",
"fd-slicer": "~1.0.1"
"fd-slicer": "~1.1.0"
}
}
}

View File

@@ -17,7 +17,7 @@
"command-line-args": "4.0.7",
"decompress": "4.2.0",
"decompress-bzip2": "4.0.0",
"node-hid": "0.7.8",
"node-hid": "0.7.9",
"sudo-prompt": "7.0.0",
"tmp": "0.0.33",
"tslib": "1.10.0",
@@ -29,6 +29,7 @@
"scripts": {
"start": "cross-env DEBUG=kboot* electron ./dist/electron-main.js",
"electron:spe": "electron ./dist/electron-main.js --spe",
"electron:kboot": "cross-env DEBUG=kboot* electron ./dist/electron-main.js --useKboot",
"build": "webpack && npm run install:build-deps && npm run build:usb && npm run download-firmware && npm run copy-to-tmp-folder",
"build:usb": "electron-rebuild -w node-hid -p -m ./dist",
"lint": "tslint --project tsconfig.json",

View File

@@ -11,6 +11,7 @@ import * as commandLineArgs from 'command-line-args';
import { UhkHidDevice, UhkOperations } from 'uhk-usb';
// import { ElectronDataStorageRepositoryService } from './services/electron-datastorage-repository.service';
import { CommandLineArgs, LogRegExps } from 'uhk-common';
import { UhkBlhost } from 'uhk-usb';
import { DeviceService } from './services/device.service';
import { logger } from './services/logger.service';
import { AppUpdateService } from './services/app-update.service';
@@ -22,7 +23,8 @@ import { loadWindowState, saveWindowState } from './util/window';
const optionDefinitions = [
{name: 'addons', type: Boolean},
{name: 'spe', type: Boolean} // simulate privilege escalation error
{name: 'spe', type: Boolean}, // simulate privilege escalation error
{name: 'useKboot', type: Boolean} // If it is true use kboot package instead of blhost for firmware upgrade
];
const options: CommandLineArgs = commandLineArgs(optionDefinitions);
@@ -36,6 +38,7 @@ let win: Electron.BrowserWindow;
autoUpdater.logger = logger;
let deviceService: DeviceService;
let uhkBlhost: UhkBlhost;
let uhkHidDeviceService: UhkHidDevice;
let uhkOperations: UhkOperations;
let appUpdateService: AppUpdateService;
@@ -100,8 +103,9 @@ function createWindow() {
setMenu(win);
uhkHidDeviceService = new UhkHidDevice(logger, options, packagesDir);
uhkOperations = new UhkOperations(logger, uhkHidDeviceService, packagesDir);
deviceService = new DeviceService(logger, win, uhkHidDeviceService, uhkOperations, packagesDir);
uhkBlhost = new UhkBlhost(logger, packagesDir);
uhkOperations = new UhkOperations(logger, uhkBlhost, uhkHidDeviceService, packagesDir);
deviceService = new DeviceService(logger, win, uhkHidDeviceService, uhkOperations, packagesDir, options);
appUpdateService = new AppUpdateService(logger, win, app);
appService = new AppService(logger, win, deviceService, options, uhkHidDeviceService);
sudoService = new SudoService(logger, options);

View File

@@ -1,4 +1,4 @@
import { app, BrowserWindow, Menu, systemPreferences } from 'electron';
import { app, BrowserWindow, Menu, MenuItemConstructorOptions, systemPreferences } from 'electron';
import * as isDev from 'electron-is-dev';
export const setMenu = (win: BrowserWindow): void => {
@@ -8,7 +8,7 @@ export const setMenu = (win: BrowserWindow): void => {
return;
}
const template = [
const template: MenuItemConstructorOptions[] = [
{
label: app.getName(),
submenu: [

View File

@@ -14,6 +14,6 @@
"npm": ">=5.1.0 <6.0.0"
},
"dependencies": {
"node-hid": "0.7.8"
"node-hid": "0.7.9"
}
}

View File

@@ -1,6 +1,7 @@
import { ipcMain } from 'electron';
import { isEqual } from 'lodash';
import {
CommandLineArgs,
ConfigurationReply,
DeviceConnectionState,
FirmwareUpgradeIpcResponse,
@@ -41,7 +42,8 @@ export class DeviceService {
private win: Electron.BrowserWindow,
private device: UhkHidDevice,
private operations: UhkOperations,
private rootDir: string) {
private rootDir: string,
private options: CommandLineArgs) {
this.startPollUhkDevice();
this.uhkDevicePoller()
.catch(error => {
@@ -182,15 +184,25 @@ export class DeviceService {
const packageJson = await getPackageJsonFromPathAsync(firmwarePathData.packageJsonPath);
this.logService.debug('New firmware version:', packageJson.firmwareVersion);
await this.operations.updateRightFirmware(firmwarePathData.rightFirmwarePath);
await this.operations.updateLeftModule(firmwarePathData.leftFirmwarePath);
if (this.options.useKboot) {
await this.operations.updateRightFirmwareWithKboot(firmwarePathData.rightFirmwarePath);
await this.operations.updateLeftModuleWithKboot(firmwarePathData.leftFirmwarePath);
} else {
await this.operations.updateRightFirmwareWithBlhost(firmwarePathData.rightFirmwarePath);
await this.operations.updateLeftModuleWithBlhost(firmwarePathData.leftFirmwarePath);
}
} else {
const packageJsonPath = path.join(this.rootDir, 'packages/firmware/package.json');
const packageJson = await getPackageJsonFromPathAsync(packageJsonPath);
this.logService.debug('New firmware version:', packageJson.firmwareVersion);
await this.operations.updateRightFirmware();
await this.operations.updateLeftModule();
if (this.options.useKboot) {
await this.operations.updateRightFirmwareWithKboot();
await this.operations.updateLeftModuleWithKboot();
} else {
await this.operations.updateRightFirmwareWithBlhost();
await this.operations.updateLeftModuleWithBlhost();
}
}
response.success = true;
@@ -220,7 +232,11 @@ export class DeviceService {
try {
await this.stopPollUhkDevice();
await this.operations.updateRightFirmware();
if (this.options.useKboot) {
await this.operations.updateRightFirmwareWithKboot();
} else {
await this.operations.updateRightFirmwareWithBlhost();
}
response.modules = await this.getHardwareModules(false);
response.success = true;
@@ -270,19 +286,21 @@ export class DeviceService {
while (true) {
if (this._pollerAllowed) {
this._uhkDevicePolling = true;
try {
const state = await this.device.getDeviceConnectionStateAsync();
if (!isEqual(state, savedState)) {
savedState = state;
this.win.webContents.send(IpcEvents.device.deviceConnectionStateChanged, state);
this.logService.info('[DeviceService] Device connection state changed to:', state);
const state = await this.device.getDeviceConnectionStateAsync();
if (!isEqual(state, savedState)) {
savedState = state;
this.win.webContents.send(IpcEvents.device.deviceConnectionStateChanged, state);
this.logService.info('[DeviceService] Device connection state changed to:', state);
}
} catch (err) {
this.logService.error('[DeviceService] Device connection state query error', err);
}
this._uhkDevicePolling = false;
}
this._uhkDevicePolling = false;
await snooze(250);
}
}

View File

@@ -15,7 +15,12 @@ export enum MouseActionParam {
scrollLeft,
scrollRight,
accelerate,
decelerate
decelerate,
button4,
button5,
button6,
button7,
button8
}
export class MouseAction extends KeyAction {

View File

@@ -7,4 +7,8 @@ export interface CommandLineArgs {
* simulate privilege escalation error
*/
spe?: boolean;
/**
* If it is true use kboot package instead of blhost for firmware upgrade
*/
useKboot?: boolean;
}

View File

@@ -1,6 +1,7 @@
import { HardwareModuleInfo } from './hardware-module-info';
import { LeftModuleInfo } from './left-module-info';
import { RightModuleInfo } from './right-module-info';
export interface HardwareModules {
leftModuleInfo?: HardwareModuleInfo;
rightModuleInfo?: HardwareModuleInfo;
leftModuleInfo?: LeftModuleInfo;
rightModuleInfo?: RightModuleInfo;
}

View File

@@ -6,8 +6,9 @@ export * from './app-start-info';
export * from './configuration-reply';
export * from './version-information';
export * from './device-connection-state';
export * from './left-module-info';
export * from './hardware-modules';
export * from './hardware-module-info';
export * from './right-module-info';
export * from './save-user-configuration-data';
export * from './udev-rules-info';
export * from './update-firmware-data';

View File

@@ -1,4 +1,4 @@
export interface HardwareModuleInfo {
export interface LeftModuleInfo {
firmwareVersion?: string;
moduleProtocolVersion?: string;
}

View File

@@ -0,0 +1,7 @@
export interface RightModuleInfo {
deviceProtocolVersion?: string;
hardwareConfigVersion?: string;
firmwareVersion?: string;
moduleProtocolVersion?: string;
userConfigVersion?: string;
}

View File

@@ -60,9 +60,9 @@
"integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw="
},
"chownr": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
"integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g=="
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.2.tgz",
"integrity": "sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A=="
},
"code-point-at": {
"version": "1.1.0",
@@ -151,9 +151,9 @@
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"ini": {
"version": "1.3.5",
@@ -209,17 +209,17 @@
"integrity": "sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA=="
},
"node-abi": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.8.0.tgz",
"integrity": "sha512-1/aa2clS0pue0HjckL62CsbhWWU35HARvBDXcJtYKbYR7LnIutmpxmXbuDMV9kEviD2lP/wACOgWmmwljghHyQ==",
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.11.0.tgz",
"integrity": "sha512-kuy/aEg75u40v378WRllQ4ZexaXJiCvB68D2scDXclp/I4cRq6togpbOoKhmN07tns9Zldu51NNERo0wehfX9g==",
"requires": {
"semver": "^5.4.1"
}
},
"node-hid": {
"version": "0.7.8",
"resolved": "https://registry.npmjs.org/node-hid/-/node-hid-0.7.8.tgz",
"integrity": "sha512-79Z9hw/pqIDp0kxvb353ivGgslo4i0hYQTcCqfRFxIJSO2gF9VtPla5uQY/9jTcDlON5O5YaqxbdH+8bs+m+1Q==",
"version": "0.7.9",
"resolved": "https://registry.npmjs.org/node-hid/-/node-hid-0.7.9.tgz",
"integrity": "sha512-vJnonTqmq3frCyTumJqG4g2IZcny3ynkfmbfDfQ90P3ZhRzcWYS/Um1ux6HFmAxmkaQnrZqIYHcGpL7kdqY8jA==",
"requires": {
"bindings": "^1.5.0",
"nan": "^2.13.2",
@@ -294,9 +294,9 @@
}
},
"process-nextick-args": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"pump": {
"version": "2.0.1",
@@ -338,9 +338,9 @@
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"semver": {
"version": "5.7.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA=="
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
},
"set-blocking": {
"version": "2.0.0",
@@ -476,9 +476,9 @@
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"xtend": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
}
}
}

View File

@@ -12,7 +12,7 @@
},
"dependencies": {
"kboot": "0.0.0",
"node-hid": "0.7.8",
"node-hid": "0.7.9",
"nrf-intel-hex": "1.3.0",
"tslib": "1.10.0",
"uhk-common": "1.0.0"

View File

@@ -71,9 +71,9 @@ export enum EnumerationNameToProductId {
}
export enum ModuleSlotToI2cAddress {
leftHalf = 0x10,
leftModule = 0x20,
rightModule = 0x30
leftHalf = '0x10',
leftModule = '0x20',
rightModule = '0x30'
}
export enum ModuleSlotToId {

View File

@@ -1,4 +1,5 @@
export * from './constants';
export * from './uhk-blhost';
export * from './uhk-hid-device';
export * from './uhk-operations';
export * from './util';

View File

@@ -0,0 +1,89 @@
import * as path from 'path';
import { spawn } from 'child_process';
import { LogService } from 'uhk-common';
import { retry } from './util';
export class UhkBlhost {
private blhostPath: string;
constructor(private logService: LogService,
private rootDir: string) {
}
public async runBlhostCommand(params: Array<string>): Promise<void> {
const self = this;
return new Promise<void>((resolve, reject) => {
const blhostPath = this.getBlhostPath();
self.logService.debug(`[blhost] RUN: ${blhostPath} ${params.join(' ')}`);
const childProcess = spawn(`"${blhostPath}"`, params, {shell: true});
let finished = false;
childProcess.stdout.on('data', data => {
self.logService.debug(`[blhost] STDOUT: ${data}`);
});
childProcess.stderr.on('data', data => {
self.logService.error(`[blhost] STDERR: ${data}`);
});
childProcess.on('close', code => {
self.logService.debug(`[blhost] CLOSE_CODE: ${code}`);
finish(code);
});
childProcess.on('exit', code => {
self.logService.debug(`[blhost] EXIT_CODE: ${code}`);
finish(code);
});
childProcess.on('error', err => {
self.logService.debug(`[blhost] ERROR: ${err}`);
});
function finish(code) {
if (finished) {
return;
}
finished = true;
self.logService.debug(`[blhost] FINISHED: ${code}`);
if (code !== 0) {
return reject(new Error(`blhost error code:${code}`));
}
resolve();
}
});
}
public async runBlhostCommandRetry(params: Array<string>, maxTry = 100): Promise<void> {
return await retry(async () => await this.runBlhostCommand(params), maxTry, this.logService);
}
private getBlhostPath(): string {
if (this.blhostPath) {
return this.blhostPath;
}
let blhostPath;
switch (process.platform) {
case 'linux':
blhostPath = 'linux/x86_64/blhost';
break;
case 'darwin':
blhostPath = 'mac/blhost';
break;
case 'win32':
blhostPath = 'win/blhost.exe';
break;
default:
throw new Error(`Could not find blhost path. Unknown platform:${process.platform}`);
}
this.blhostPath = path.join(this.rootDir, `packages/blhost/${blhostPath}`);
return this.blhostPath;
}
}

View File

@@ -208,7 +208,7 @@ export class UhkHidDevice {
while (new Date().getTime() - startTime.getTime() < 20000) {
const devs = devices();
this.logService.silly('[UhkHidDevice] reenumeration devices', devs);
this.logService.debug('[UhkHidDevice] reenumeration devices', devs);
const inBootloaderMode = devs.some((x: Device) =>
x.vendorId === Constants.VENDOR_ID &&
@@ -219,7 +219,7 @@ export class UhkHidDevice {
return;
}
this.logService.silly(`[UhkHidDevice] Could not find reenumerated device: ${reenumMode}. Waiting...`);
this.logService.debug(`[UhkHidDevice] Could not find reenumerated device: ${reenumMode}. Waiting...`);
await snooze(100);
if (!jumped) {
@@ -232,7 +232,7 @@ export class UhkHidDevice {
device.close();
jumped = true;
} else {
this.logService.silly(`[UhkHidDevice] USB[T]: Enumerate device is not ready yet}`);
this.logService.debug(`[UhkHidDevice] USB[T]: Enumerate device is not ready yet}`);
}
}
}
@@ -249,7 +249,7 @@ export class UhkHidDevice {
if (command === KbootCommands.idle) {
transfer = Buffer.from([UsbCommand.SendKbootCommandToModule, command]);
} else {
transfer = Buffer.from([UsbCommand.SendKbootCommandToModule, command, module]);
transfer = Buffer.from([UsbCommand.SendKbootCommandToModule, command, Number.parseInt(module, 16)]);
}
await retry(async () => await this.write(transfer), maxTry, this.logService);
}

View File

@@ -1,4 +1,4 @@
import { HardwareModuleInfo, LogService, UhkBuffer } from 'uhk-common';
import { LeftModuleInfo, LogService, RightModuleInfo, UhkBuffer } from 'uhk-common';
import { DataOption, KBoot, Properties, UsbPeripheral } from 'kboot';
import {
@@ -13,6 +13,7 @@ import {
import * as path from 'path';
import * as fs from 'fs';
import * as os from 'os';
import { UhkBlhost } from './uhk-blhost';
import { UhkHidDevice } from './uhk-hid-device';
import { readBootloaderFirmwareFromHexFileAsync, snooze, waitForDevice } from './util';
import { ConfigBufferId, convertBufferToIntArray, DevicePropertyIds, getTransferBuffers, UsbCommand } from '../index';
@@ -20,11 +21,67 @@ import { LoadConfigurationsResult } from './models/load-configurations-result';
export class UhkOperations {
constructor(private logService: LogService,
private blhost: UhkBlhost,
private device: UhkHidDevice,
private rootDir: string) {
}
public async updateRightFirmware(firmwarePath = this.getFirmwarePath()) {
public async updateRightFirmwareWithBlhost(firmwarePath = this.getFirmwarePath()) {
this.logService.debug(`[UhkOperations] Operating system: ${os.type()} ${os.release()} ${os.arch()}`);
this.logService.debug('[UhkOperations] Start flashing right firmware');
const prefix = [`--usb 0x1d50,0x${EnumerationNameToProductId.bootloader.toString(16)}`];
await this.device.reenumerate(EnumerationModes.Bootloader);
this.device.close();
await this.blhost.runBlhostCommand([...prefix, 'flash-security-disable', '0403020108070605']);
await this.blhost.runBlhostCommand([...prefix, 'flash-erase-region', '0xc000', '475136']);
await this.blhost.runBlhostCommand([...prefix, 'flash-image', `"${firmwarePath}"`]);
await this.blhost.runBlhostCommand([...prefix, 'reset']);
this.logService.debug('[UhkOperations] Right firmware successfully flashed');
}
public async updateLeftModuleWithBlhost(firmwarePath = this.getLeftModuleFirmwarePath()) {
this.logService.debug('[UhkOperations] Start flashing left module firmware');
const prefix = [`--usb 0x1d50,0x${EnumerationNameToProductId.buspal.toString(16)}`];
const buspalPrefix = [...prefix, `--buspal i2c,${ModuleSlotToI2cAddress.leftHalf}`];
await this.device.reenumerate(EnumerationModes.NormalKeyboard);
this.device.close();
await snooze(1000);
await this.device.sendKbootCommandToModule(ModuleSlotToI2cAddress.leftHalf, KbootCommands.ping, 100);
await snooze(1000);
await this.device.jumpToBootloaderModule(ModuleSlotToId.leftHalf);
this.device.close();
const leftModuleBricked = await this.waitForKbootIdle();
if (!leftModuleBricked) {
const msg = '[UhkOperations] Couldn\'t connect to the left keyboard half.';
this.logService.error(msg);
throw new Error(msg);
}
await this.device.reenumerate(EnumerationModes.Buspal);
this.device.close();
await this.blhost.runBlhostCommandRetry([...buspalPrefix, 'get-property', '1']);
await this.blhost.runBlhostCommand([...buspalPrefix, 'flash-erase-all-unsecure']);
await this.blhost.runBlhostCommand([...buspalPrefix, 'write-memory', '0x0', `"${firmwarePath}"`]);
await this.blhost.runBlhostCommand([...prefix, 'reset']);
await snooze(1000);
await this.device.reenumerate(EnumerationModes.NormalKeyboard);
this.device.close();
await snooze(1000);
await this.device.sendKbootCommandToModule(ModuleSlotToI2cAddress.leftHalf, KbootCommands.reset, 100);
this.device.close();
await snooze(1000);
await this.device.sendKbootCommandToModule(ModuleSlotToI2cAddress.leftHalf, KbootCommands.idle);
this.device.close();
this.logService.debug('[UhkOperations] Left firmware successfully flashed');
this.logService.debug('[UhkOperations] Both left and right firmwares successfully flashed');
}
public async updateRightFirmwareWithKboot(firmwarePath = this.getFirmwarePath()) {
this.logService.debug(`[UhkOperations] Operating system: ${os.type()} ${os.release()} ${os.arch()}`);
this.logService.debug('[UhkOperations] Start flashing right firmware');
@@ -58,9 +115,10 @@ export class UhkOperations {
this.logService.debug('[UhkOperations] Right firmware successfully flashed');
}
public async updateLeftModule(firmwarePath = this.getLeftModuleFirmwarePath()) {
public async updateLeftModuleWithKboot(firmwarePath = this.getLeftModuleFirmwarePath()) {
this.logService.debug('[UhkOperations] Start flashing left module firmware');
const i2cAddressOfLeftModule = Number.parseInt(ModuleSlotToI2cAddress.leftHalf, 16);
await this.device.reenumerate(EnumerationModes.NormalKeyboard);
this.device.close();
await snooze(1000);
@@ -86,28 +144,31 @@ export class UhkOperations {
while (true) {
try {
this.logService.debug('[UhkOperations] Try to connect to the LEFT keyboard');
await kboot.configureI2c(ModuleSlotToI2cAddress.leftHalf);
await kboot.configureI2c(i2cAddressOfLeftModule);
await kboot.getProperty(Properties.BootloaderVersion);
break;
} catch {
if (tryCount > 100) {
throw new Error('Can not connect to the LEFT keyboard');
}
} finally {
kboot.close();
await snooze(2000);
}
await snooze(100);
tryCount++;
}
// https://github.com/node-hid/node-hid/issues/230
this.logService.debug('[UhkOperations] Wait 1 sec to prevent node-hid race condition');
await snooze(1000);
this.logService.debug('[UhkOperations] Flash erase all on LEFT keyboard');
await kboot.configureI2c(ModuleSlotToI2cAddress.leftHalf);
await kboot.configureI2c(i2cAddressOfLeftModule);
await kboot.flashEraseAllUnsecure();
this.logService.debug('[UhkOperations] Read LEFT firmware from file');
const configData = fs.readFileSync(firmwarePath);
this.logService.debug('[UhkOperations] Write memory');
await kboot.configureI2c(ModuleSlotToI2cAddress.leftHalf);
await kboot.configureI2c(i2cAddressOfLeftModule);
await kboot.writeMemory({ startAddress: 0, data: configData });
this.logService.debug('[UhkOperations] Reset LEFT keyboard');
@@ -248,7 +309,7 @@ export class UhkOperations {
return false;
}
public async getLeftModuleVersionInfo(): Promise<HardwareModuleInfo> {
public async getLeftModuleVersionInfo(): Promise<LeftModuleInfo> {
try {
this.logService.debug('[DeviceOperation] USB[T]: Read left module version information');
@@ -277,7 +338,7 @@ export class UhkOperations {
};
}
public async getRightModuleVersionInfo(): Promise<HardwareModuleInfo> {
public async getRightModuleVersionInfo(): Promise<RightModuleInfo> {
this.logService.debug('[DeviceOperation] USB[T]: Read right module version information');
const command = Buffer.from([UsbCommand.GetProperty, DevicePropertyIds.ProtocolVersions]);
@@ -287,7 +348,11 @@ export class UhkOperations {
uhkBuffer.readUInt8();
return {
firmwareVersion: `${uhkBuffer.readUInt16()}.${uhkBuffer.readUInt16()}.${uhkBuffer.readUInt16()}`
firmwareVersion: `${uhkBuffer.readUInt16()}.${uhkBuffer.readUInt16()}.${uhkBuffer.readUInt16()}`,
deviceProtocolVersion: `${uhkBuffer.readUInt16()}.${uhkBuffer.readUInt16()}.${uhkBuffer.readUInt16()}`,
moduleProtocolVersion: `${uhkBuffer.readUInt16()}.${uhkBuffer.readUInt16()}.${uhkBuffer.readUInt16()}`,
userConfigVersion: `${uhkBuffer.readUInt16()}.${uhkBuffer.readUInt16()}.${uhkBuffer.readUInt16()}`,
hardwareConfigVersion: `${uhkBuffer.readUInt16()}.${uhkBuffer.readUInt16()}.${uhkBuffer.readUInt16()}`
};
}

View File

@@ -1,7 +1,7 @@
import { Device, devices } from 'node-hid';
import { readFile } from 'fs-extra';
import { EOL } from 'os';
import MemoryMap from 'nrf-intel-hex';
import * as MemoryMap from 'nrf-intel-hex';
import { LogService } from 'uhk-common';
import { Constants, UsbCommand } from './constants';
@@ -126,7 +126,9 @@ export const getFileContentAsync = async (filePath: string): Promise<Array<strin
export const readBootloaderFirmwareFromHexFileAsync = async (hexFilePath: string): Promise<Map<any, any>> => {
const fileContent = await readFile(hexFilePath, { encoding: 'utf8' });
const memoryMap = MemoryMap.fromHex(fileContent);
const fromHex = MemoryMap.fromHex ? MemoryMap.fromHex : MemoryMap.default.fromHex;
const memoryMap = fromHex(fileContent);
return memoryMap;
};

File diff suppressed because it is too large Load Diff

View File

@@ -19,29 +19,28 @@
},
"private": true,
"devDependencies": {
"@angular/animations": "7.2.15",
"@angular-builders/custom-webpack": "7.3.1",
"@angular/cli": "7.3.9",
"@angular/common": "7.2.15",
"@angular/compiler": "7.2.15",
"@angular/compiler-cli": "7.2.15",
"@angular/core": "7.2.15",
"@angular-devkit/build-angular": "0.13.9",
"@angular-devkit/build-optimizer": "0.13.9",
"@angular-devkit/core": "7.3.9",
"@angular/forms": "7.2.15",
"@angular/http": "7.2.15",
"@angular/language-service": "7.2.15",
"@angular/platform-browser": "7.2.15",
"@angular/platform-browser-dynamic": "7.2.15",
"@angular/router": "7.2.15",
"@ngtools/webpack": "7.3.9",
"@ngrx/effects": "7.4.0",
"@ngrx/router-store": "7.4.0",
"@ngrx/store": "7.4.0",
"@ngrx/store-devtools": "7.4.0",
"@angular/animations": "8.2.6",
"@angular-builders/custom-webpack": "8.2.0",
"@angular/cli": "8.3.4",
"@angular/common": "8.2.6",
"@angular/compiler": "8.2.6",
"@angular/compiler-cli": "8.2.6",
"@angular/core": "8.2.6",
"@angular-devkit/build-angular": "0.803.4",
"@angular-devkit/build-optimizer": "0.803.4",
"@angular-devkit/core": "8.3.4",
"@angular/forms": "8.2.6",
"@angular/language-service": "8.2.6",
"@angular/platform-browser": "8.2.6",
"@angular/platform-browser-dynamic": "8.2.6",
"@angular/router": "8.2.6",
"@ngtools/webpack": "8.3.4",
"@ngrx/effects": "8.2.0",
"@ngrx/router-store": "8.2.0",
"@ngrx/store": "8.2.0",
"@ngrx/store-devtools": "8.2.0",
"@ngrx/store-log-monitor": "3.0.2",
"angular-confirmation-popover": "4.2.0",
"angular-confirmation-popover": "4.2.1",
"angular-notifier": "4.1.1",
"bootstrap": "3.4.1",
"codelyzer": "4.5.0",
@@ -56,19 +55,18 @@
"karma-jasmine": "1.1.2",
"karma-jasmine-html-reporter": "1.3.1",
"ng2-dragula": "2.1.1",
"ng2-nouislider": "1.7.13",
"ngx-clipboard": "10.0.0",
"ngx-select-ex": "3.6.8",
"ngrx-store-freeze": "0.1.9",
"nouislider": "13.1.1",
"ng2-nouislider": "1.8.2",
"ngx-clipboard": "12.2.0",
"ngx-select-ex": "3.7.0",
"ngrx-store-freeze": "0.2.4",
"nouislider": "14.0.2",
"protractor": "5.4.0",
"reselect": "3.0.1",
"rxjs": "6.4.0",
"rxjs": "6.5.2",
"semver": "5.6.0",
"ts-keycode-enum": "^1.0.6",
"uhk-common": "1.0.0",
"xml-loader": "1.2.1",
"zone.js": "0.8.26"
"zone.js": "0.10.0"
},
"dependencies": {
"classlist.js": "1.1.20150312",

View File

@@ -16,6 +16,7 @@ import {
} from './store';
import { ProgressButtonState } from './store/reducers/progress-button-state';
import { UpdateInfo } from './models/update-info';
import { KeyUpAction, KeyDownAction } from './store/actions/app';
@Component({
selector: 'main-app',
@@ -95,6 +96,13 @@ export class MainAppComponent implements OnDestroy {
this.enableUsbStackTest();
event.preventDefault();
}
this.store.dispatch(new KeyDownAction(event));
}
@HostListener('document:keyup', ['$event'])
onKeyUp(event: KeyboardEvent) {
this.store.dispatch(new KeyUpAction(event));
}
updateApp() {

View File

@@ -1,7 +1,7 @@
import { Component, Input, ViewChild, ElementRef, OnInit } from '@angular/core';
import { Component, Input, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
import { Store } from '@ngrx/store';
import { AppState } from '../../../../store/index';
import { AppState } from '../../../../store';
import { UHKContributor } from '../../../../models/uhk-contributor';
@@ -10,9 +10,9 @@ import { UHKContributor } from '../../../../models/uhk-contributor';
templateUrl: './contributor-badge.component.html',
styleUrls: ['./contributor-badge.component.scss']
})
export class ContributorBadgeComponent implements OnInit {
export class ContributorBadgeComponent implements AfterViewInit {
@Input() contributor: UHKContributor;
@ViewChild('badge') badge: ElementRef;
@ViewChild('badge', { static: false }) badge: ElementRef;
get name(): string {
return this.contributor.login;
@@ -29,7 +29,7 @@ export class ContributorBadgeComponent implements OnInit {
constructor(private store: Store<AppState>) {
}
ngOnInit(): void {
ngAfterViewInit(): void {
(this.badge.nativeElement as HTMLImageElement).src = URL.createObjectURL(this.contributor.avatar);
}
}

View File

@@ -20,6 +20,7 @@
<li>Right click on a key: Capture key</li>
<li>Hold Shift while clicking on a key: Remap on all keymaps</li>
<li>Hold Alt while clicking on a key: Remap on all layers</li>
<li>Hold Alt to see macro reference counts in the side menu</li>
</ul>
</div>
</div>

View File

@@ -30,7 +30,7 @@ export class AutoGrowInputComponent implements ControlValueAccessor {
@Input() maxParentWidthPercent = 1;
@Input() css: string;
@ViewChild('inputControl') inputControl: ElementRef;
@ViewChild('inputControl', { static: true }) inputControl: ElementRef;
disabled: boolean;

View File

@@ -21,7 +21,7 @@
<li>
<button class="btn btn-danger"
mwlConfirmationPopover
title="Are you sure?"
popoverTitle="Are you sure?"
placement="bottom"
confirmText="Yes"
cancelText="No"

View File

@@ -27,7 +27,7 @@
label="Choose firmware file and flash it"></file-upload>
</p>
<div *ngIf="firmwareUpgradeFailed$ | async"
<div *ngIf="firmwareUpgradeFailed"
class="alert alert-danger"
role="alert">
<p>Firmware update failed. Disconnect every USB device from your computer (including USB hubs, KVM switches, USB dongles, and everything else), then connect only your UHK and retry.</p>
@@ -35,7 +35,7 @@
<p>If you've tried the above and the update still keeps failing, please <a class="link-github" [href]="firmwareGithubIssueUrl" externalUrl>create a GitHub issue</a>, and attach the update log.</p>
</div>
<div *ngIf="firmwareUpgradeSuccess$ | async"
<div *ngIf="firmwareUpgradeSuccess"
class="alert alert-success"
role="alert">
<p>Firmware update succeeded.</p>

View File

@@ -1,4 +1,4 @@
import { Component, OnDestroy } from '@angular/core';
import { Component, OnDestroy, ViewChild } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable, Subscription } from 'rxjs';
import { Constants, HardwareModules, VersionInformation } from 'uhk-common';
@@ -17,6 +17,7 @@ import {
import { UpdateFirmwareAction, UpdateFirmwareWithAction } from '../../../store/actions/device';
import { XtermLog } from '../../../models/xterm-log';
import { UploadFileData } from '../../../models/upload-file-data';
import { XtermComponent } from '../../xterm/xterm.component';
@Component({
selector: 'device-firmware',
@@ -30,30 +31,41 @@ export class DeviceFirmwareComponent implements OnDestroy {
flashFirmwareButtonDisbabled$: Observable<boolean>;
xtermLog$: Observable<Array<XtermLog>>;
getAgentVersionInfo$: Observable<VersionInformation>;
hardwareModulesSubscription: Subscription;
hardwareModules: HardwareModules;
runningOnNotSupportedWindows$: Observable<boolean>;
firmwareUpgradeAllowed$: Observable<boolean>;
firmwareUpgradeFailed$: Observable<boolean>;
firmwareUpgradeSuccess$: Observable<boolean>;
firmwareGithubIssueUrl: string;
firmwareUpgradeFailed: boolean;
firmwareUpgradeSuccess: boolean;
@ViewChild(XtermComponent, { static: false })
xtermRef: XtermComponent;
private subscription = new Subscription();
constructor(private store: Store<AppState>) {
this.flashFirmwareButtonDisbabled$ = store.select(flashFirmwareButtonDisbabled);
this.xtermLog$ = store.select(xtermLog);
this.getAgentVersionInfo$ = store.select(getAgentVersionInfo);
this.hardwareModulesSubscription = store.select(getHardwareModules).subscribe(data => {
this.subscription.add(store.select(getHardwareModules).subscribe(data => {
this.hardwareModules = data;
});
}));
this.runningOnNotSupportedWindows$ = store.select(runningOnNotSupportedWindows);
this.firmwareUpgradeAllowed$ = store.select(firmwareUpgradeAllowed);
this.firmwareUpgradeFailed$ = store.select(firmwareUpgradeFailed);
this.firmwareUpgradeSuccess$ = store.select(firmwareUpgradeSuccess);
this.subscription.add(store.select(firmwareUpgradeFailed).subscribe(data => {
this.firmwareUpgradeFailed = data;
this.scrollToTheEndOfTheLogs();
}));
this.subscription.add(store.select(firmwareUpgradeSuccess).subscribe(data => {
this.firmwareUpgradeSuccess = data;
this.scrollToTheEndOfTheLogs();
}));
this.firmwareGithubIssueUrl = Constants.FIRMWARE_GITHUB_ISSUE_URL;
}
ngOnDestroy(): void {
this.hardwareModulesSubscription.unsubscribe();
this.subscription.unsubscribe();
}
onUpdateFirmware(): void {
@@ -63,4 +75,10 @@ export class DeviceFirmwareComponent implements OnDestroy {
changeFile(data: UploadFileData): void {
this.store.dispatch(new UpdateFirmwareWithAction(data.data));
}
private scrollToTheEndOfTheLogs(): void {
if (this.xtermRef) {
this.xtermRef.scrollToTheEnd();
}
}
}

View File

@@ -4,7 +4,7 @@
</h1>
<button class="btn btn-danger mouse-speed-reset-button"
mwlConfirmationPopover
title="Are you sure?"
popoverTitle="Are you sure?"
placement="bottom"
confirmText="Yes"
cancelText="No"
@@ -12,7 +12,7 @@
</button>
<button class="btn btn-danger mouse-speed-reset-button"
mwlConfirmationPopover
title="Are you sure?"
popoverTitle="Are you sure?"
placement="bottom"
confirmText="Yes"
cancelText="No"

View File

@@ -15,6 +15,7 @@
<textarea class="text-editor"
[(ngModel)]="text"
autofocus
(keydown.escape)="cancelEditText()"
(keydown.control.enter)="keydownEnter()"
(keydown.alt.enter)="keydownEnter()"></textarea>
<div class="pull-right buttons">

View File

@@ -39,8 +39,8 @@ export class KeymapHeaderComponent implements OnChanges {
@Input() deletable: boolean;
@Output() downloadClick = new EventEmitter<void>();
@ViewChild('name') keymapName: ElementRef;
@ViewChild('abbr') keymapAbbr: ElementRef;
@ViewChild('name', { static: true }) keymapName: ElementRef;
@ViewChild('abbr', { static: true }) keymapAbbr: ElementRef;
starTitle: string;
trashTitle: string = DEFAULT_TRASH_TITLE;

View File

@@ -31,7 +31,8 @@ export class MacroActionEditorComponent implements OnInit {
@Output() save = new EventEmitter<MacroAction>();
@Output() cancel = new EventEmitter<void>();
@ViewChild('tab') selectedTab: MacroTextTabComponent | MacroKeyTabComponent | MacroMouseTabComponent | MacroDelayTabComponent;
// tslint:disable-next-line:max-line-length
@ViewChild('tab', { static: false }) selectedTab: MacroTextTabComponent | MacroKeyTabComponent | MacroMouseTabComponent | MacroDelayTabComponent;
editableMacroAction: MacroAction;
activeTab: TabName;

View File

@@ -1,10 +1,8 @@
import {
ChangeDetectionStrategy,
Component,
ElementRef,
Input,
OnInit,
ViewChild
OnInit
} from '@angular/core';
import { DelayMacroAction } from 'uhk-common';
@@ -21,7 +19,6 @@ const INITIAL_DELAY = 0.5; // In seconds
})
export class MacroDelayTabComponent extends MacroBaseComponent implements OnInit {
@Input() macroAction: DelayMacroAction;
@ViewChild('macroDelayInput') input: ElementRef;
presets: number[] = [0.1, 0.5, 1, 5, 10];

View File

@@ -21,8 +21,7 @@ enum TabName {
})
export class MacroKeyTabComponent extends MacroBaseComponent implements OnInit {
@Input() macroAction: KeyMacroAction;
@ViewChild('tab') selectedTab: Tab;
@ViewChild('keypressTab') keypressTab: KeypressTabComponent;
@ViewChild('keypressTab', { static: true }) keypressTab: KeypressTabComponent;
/* tslint:disable:variable-name: It is an enum type. So it can start with uppercase. */
TabName = TabName;

View File

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

View File

@@ -20,7 +20,7 @@ const NON_ASCII_REGEXP = /[^\x00-\x7F]/g;
})
export class MacroTextTabComponent extends MacroBaseComponent implements OnInit, AfterViewInit {
@Input() macroAction: TextMacroAction;
@ViewChild('macroTextInput') input: ElementRef;
@ViewChild('macroTextInput', { static: false } ) input: ElementRef;
constructor() { super(); }

View File

@@ -26,7 +26,7 @@ import * as util from '../../../util';
export class MacroHeaderComponent implements AfterViewInit, OnChanges {
@Input() macro: Macro;
@Input() isNew: boolean;
@ViewChild('macroName') macroName: ElementRef;
@ViewChild('macroName', { static: true }) macroName: ElementRef;
constructor(private store: Store<AppState>, private renderer: Renderer2) { }

View File

@@ -46,7 +46,6 @@ export class MacroListComponent {
newMacro: Macro = undefined;
showNew: boolean = false;
private activeEdit: number = undefined;
private dragIndex: number;
constructor(
private mapper: MapperService,
@@ -59,16 +58,18 @@ export class MacroListComponent {
}
});
dragulaService.drag('macroActions').subscribe((value: any) => {
this.dragIndex = +value[1].getAttribute('data-index');
});
dragulaService.drop('macroActions').subscribe(value => {
if (value.el) {
let newIndex = this.macroItems.length - 1;
if (value.sibling) {
newIndex = (+value.sibling.getAttribute('data-index') - 1);
}
dragulaService.drop('macroActions').subscribe((value: any) => {
if (value[4]) {
this.reorder.emit({
macroId: this.macro.id,
oldIndex: this.dragIndex,
newIndex: +value[4].getAttribute('data-index')
oldIndex: +value.el.getAttribute('data-index'),
newIndex
});
}
});

View File

@@ -38,6 +38,7 @@
></layer-tab>
<mouse-tab #tab *ngSwitchCase="tabName.Mouse" class="popover-content"
[defaultKeyAction]="defaultKeyAction"
[extraMouseButtonsSupported]="extraMouseButtonsSupported$ | async"
(validAction)="setKeyActionValidState($event)"
></mouse-tab>
<macro-tab #tab *ngSwitchCase="tabName.Macro" class="popover-content"

View File

@@ -30,7 +30,7 @@ import {
import { Tab } from './tab';
import { AppState, getKeymaps, macroPlaybackSupported } from '../../store';
import { AppState, extraMouseButtonsSupported, getKeymaps, macroPlaybackSupported } from '../../store';
import { KeyActionRemap } from '../../models/key-action-remap';
import { RemapInfo } from '../../models/remap-info';
@@ -98,8 +98,8 @@ export class PopoverComponent implements OnChanges {
@Output() cancel = new EventEmitter<any>();
@Output() remap = new EventEmitter<KeyActionRemap>();
@ViewChild('tab') selectedTab: Tab;
@ViewChild('popover') popoverHost: ElementRef;
@ViewChild('tab', { static: false }) selectedTab: Tab;
@ViewChild('popover', { static: false }) popoverHost: ElementRef;
tabName = TabName;
keyActionValid: boolean;
@@ -145,6 +145,7 @@ export class PopoverComponent implements OnChanges {
}
];
macroPlaybackSupported$: Observable<boolean>;
extraMouseButtonsSupported$: Observable<boolean>;
private readonly currentKeymap$ = new BehaviorSubject<Keymap>(undefined);
@@ -158,6 +159,7 @@ export class PopoverComponent implements OnChanges {
keymaps.filter((keymap: Keymap) => currentKeymap.abbreviation !== keymap.abbreviation))
);
this.macroPlaybackSupported$ = store.select(macroPlaybackSupported);
this.extraMouseButtonsSupported$ = store.select(extraMouseButtonsSupported);
}
ngOnChanges(change: SimpleChanges) {

View File

@@ -80,6 +80,27 @@
[class.btn-primary]="mouseActionParam === MouseActionParam.rightClick"
(click)="setMouseActionParam(MouseActionParam.rightClick)">Right</button>
</div>
<div class="additional-keys" *ngIf="extraMouseButtonsSupported">
<div class="btn-group col-xs-12" role="group">
<button type="button" class="btn btn-default col-xs-4"
[class.btn-primary]="mouseActionParam === MouseActionParam.button4"
(click)="setMouseActionParam(MouseActionParam.button4)">Button 4</button>
<button type="button" class="btn btn-default col-xs-4"
[class.btn-primary]="mouseActionParam === MouseActionParam.button5"
(click)="setMouseActionParam(MouseActionParam.button5)">Button 5</button>
<button type="button" class="btn btn-default col-xs-4"
[class.btn-primary]="mouseActionParam === MouseActionParam.button6"
(click)="setMouseActionParam(MouseActionParam.button6)">Button 6</button>
</div>
<div class="btn-group col-xs-12" role="group">
<button type="button" class="btn btn-default col-xs-6"
[class.btn-primary]="mouseActionParam === MouseActionParam.button7"
(click)="setMouseActionParam(MouseActionParam.button7)">Button 7</button>
<button type="button" class="btn btn-default col-xs-6"
[class.btn-primary]="mouseActionParam === MouseActionParam.button8"
(click)="setMouseActionParam(MouseActionParam.button8)">Button 8</button>
</div>
</div>
</div>
<div *ngSwitchCase="3" class="mouse__config mouse__config--speed text-center">
<div class="help-text--mouse-speed text-left">
@@ -104,4 +125,4 @@
</div>
<div *ngSwitchDefault>
</div>
</div>
</div>

View File

@@ -54,6 +54,32 @@
}
}
.mouse__config--click {
.additional-keys {
display: inline-block;
margin-top: 1rem;
.btn-group:first-child {
.btn {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
}
.btn-group:last-child {
.btn {
border-top: 0;
border-top-left-radius: 0;
border-top-right-radius: 0;
&:last-child {
right: 1px;
}
}
}
}
}
.mouse__config--speed {
.btn-default {
font-size: 25px;

View File

@@ -11,6 +11,7 @@ import { Tab } from '../tab';
})
export class MouseTabComponent extends Tab implements OnChanges {
@Input() defaultKeyAction: KeyAction;
@Input() extraMouseButtonsSupported: boolean;
/* tslint:disable:variable-name: It is an enum type. So it can start with uppercase. */
MouseActionParam = MouseActionParam;
@@ -62,6 +63,11 @@ export class MouseTabComponent extends Tab implements OnChanges {
case MouseActionParam.leftClick:
case MouseActionParam.middleClick:
case MouseActionParam.rightClick:
case MouseActionParam.button4:
case MouseActionParam.button5:
case MouseActionParam.button6:
case MouseActionParam.button7:
case MouseActionParam.button8:
this.selectedPageIndex = 2;
break;
case MouseActionParam.decelerate:

View File

@@ -91,6 +91,12 @@
<div class="sidebar__level-2" [routerLinkActive]="['active']">
<a [routerLink]="['/macro', macro.id]"
[class.disabled]="state.updatingFirmware">{{macro.name}}</a>
<span *ngIf="state.macroUsageCountVisible"
class="sidebar__macro_count badge"
title="This is the number of times the macro is used across all keymaps."
data-toggle="tooltip"
data-placement="bottom"
data-container="body">{{ macro.usageCount }}</span>
</div>
</li>
</ul>

View File

@@ -148,6 +148,12 @@ ul {
right: 19px;
top: 3px;
}
&__macro_count {
position: absolute;
right: 11px;
top: 1px;
}
}
.menu--bottom {

View File

@@ -2,10 +2,9 @@ import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ElementRef,
OnDestroy, OnInit,
Renderer2,
ViewChild
OnDestroy,
OnInit,
Renderer2
} from '@angular/core';
import { animate, state, style, transition, trigger } from '@angular/animations';
@@ -38,7 +37,6 @@ import { SideMenuPageState } from '../../models/side-menu-page-state';
export class SideMenuComponent implements OnInit, OnDestroy {
state: SideMenuPageState;
animation: { [key: string]: 'active' | 'inactive' };
@ViewChild('deviceName') deviceName: ElementRef;
private stateSubscription: Subscription;

View File

@@ -28,7 +28,7 @@ export interface SliderProps {
]
})
export class SliderWrapperComponent implements AfterViewInit, ControlValueAccessor, OnDestroy {
@ViewChild(NouisliderComponent) slider: NouisliderComponent;
@ViewChild(NouisliderComponent, { static: false }) slider: NouisliderComponent;
@Input() label: string;
@Input() tooltip: string;
@Input() min: number;

View File

@@ -91,6 +91,7 @@ export class SvgKeyboardComponent {
this.modules = [];
this.viewBox = '-520 582 1100 470';
this.moduleAnimationStates = [];
this.moduleVisibilityAnimationStates = [];
}
ngOnInit() {

View File

@@ -1,8 +1,4 @@
:host {
/deep/ text {
dominant-baseline: central;
}
cursor: pointer;
outline: none;

View File

@@ -79,7 +79,7 @@ export class SvgKeyboardKeyComponent implements OnChanges {
@Output() keyClick = new EventEmitter<SvgKeyClickEvent>();
@Output() capture = new EventEmitter<SvgKeyCaptureEvent>();
@ViewChild('svgRec') svgRec: ElementRef<HTMLElement>;
@ViewChild('svgRec', { static: false }) svgRec: ElementRef<HTMLElement>;
enumLabelTypes = LabelTypes;

View File

@@ -25,17 +25,17 @@
</svg>
<svg viewBox="0 0 100 100" [attr.width]="control.width" [attr.height]="control.height" [attr.x]="control.x" [attr.y]="control.y"
preserveAspectRatio="none" [class.disabled]="control.disabled">
<svg:text [attr.text-anchor]="'middle'" [attr.x]="50" [attr.y]="50">C</svg:text>
<svg:text text-anchor="middle" alignment-baseline="middle" x="50" y="55">C</svg:text>
</svg>
<svg viewBox="0 0 100 100" [attr.width]="option.width" [attr.height]="option.height" [attr.x]="option.x" [attr.y]="option.y"
preserveAspectRatio="none" [class.disabled]="option.disabled">
<svg:use *ngIf="modifierIconNames.option" [attr.xlink:href]="modifierIconNames.option" />
<svg:text *ngIf="!modifierIconNames.option" [attr.text-anchor]="'middle'" [attr.x]="50" [attr.y]="50">A</svg:text>
<svg:text *ngIf="!modifierIconNames.option" text-anchor="middle" alignment-baseline="middle" x="50" y="55">A</svg:text>
</svg>
<svg viewBox="0 0 100 100" [attr.width]="command.width" [attr.height]="command.height" [attr.x]="command.x" [attr.y]="command.y"
preserveAspectRatio="none" [class.disabled]="command.disabled">
<svg:use *ngIf="modifierIconNames.command" [attr.xlink:href]="modifierIconNames.command" />
<svg:text *ngIf="!modifierIconNames.command" [attr.text-anchor]="'middle'" [attr.x]="50" [attr.y]="50">S</svg:text>
<svg:text *ngIf="!modifierIconNames.command" text-anchor="middle" alignment-baseline="middle" x="50" y="55">S</svg:text>
</svg>
</svg>
<svg:g svg-secondary-role

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -5,12 +5,12 @@
[attr.y]="0"
[attr.text-anchor]="'middle'"
[attr.font-size]="25">
<tspan dy="34"> Click </tspan>
<tspan dy="45"> Click </tspan>
</svg:text>
<svg:text
[attr.x]="50"
[attr.y]="0"
[attr.text-anchor]="'middle'"
[attr.font-size]="25">
<tspan dy="70"> {{ button }} </tspan>
</svg:text>
<tspan dy="80"> {{ button }} </tspan>
</svg:text>

Before

Width:  |  Height:  |  Size: 403 B

After

Width:  |  Height:  |  Size: 404 B

View File

@@ -28,6 +28,26 @@ export class SvgMouseKeyComponent implements OnChanges {
this.type = 'click';
this.param = 'Middle';
break;
case MouseActionParam.button4:
this.type = 'click';
this.param = 'Button 4';
break;
case MouseActionParam.button5:
this.type = 'click';
this.param = 'Button 5';
break;
case MouseActionParam.button6:
this.type = 'click';
this.param = 'Button 6';
break;
case MouseActionParam.button7:
this.type = 'click';
this.param = 'Button 7';
break;
case MouseActionParam.button8:
this.type = 'click';
this.param = 'Button 8';
break;
case MouseActionParam.scrollDown:
this.type = 'scroll';
this.param = 'down';

View File

@@ -4,6 +4,6 @@
[attr.y]="0"
[attr.text-anchor]="'middle'"
[attr.font-size]="24">
<tspan dy="34"> Move </tspan>
<tspan dy="45"> Move </tspan>
</svg:text>
<svg:use [attr.xlink:href]="directionIcon" width="30" height="30" x="35" y="55"></svg:use>
<svg:use [attr.xlink:href]="directionIcon" width="30" height="30" x="35" y="55"></svg:use>

Before

Width:  |  Height:  |  Size: 332 B

After

Width:  |  Height:  |  Size: 333 B

View File

@@ -4,6 +4,6 @@
[attr.y]="0"
[attr.text-anchor]="'middle'"
[attr.font-size]="24">
<tspan dy="34"> Scroll </tspan>
<tspan dy="45"> Scroll </tspan>
</svg:text>
<svg:use [attr.xlink:href]="directionIcon" width="30" height="30" x="35" y="55"></svg:use>
<svg:use [attr.xlink:href]="directionIcon" width="30" height="30" x="35" y="55"></svg:use>

Before

Width:  |  Height:  |  Size: 334 B

After

Width:  |  Height:  |  Size: 335 B

View File

@@ -5,12 +5,12 @@
[attr.y]="0"
[attr.text-anchor]="'middle'"
[attr.font-size]="25">
<tspan dy="34"> Speed </tspan>
<tspan dy="45"> Speed </tspan>
</svg:text>
<svg:text
[attr.x]="50"
[attr.y]="0"
[attr.text-anchor]="'middle'"
[attr.font-size]="30">
<tspan dy="70"> {{ sign }} </tspan>
</svg:text>
<tspan dy="80"> {{ sign }} </tspan>
</svg:text>

Before

Width:  |  Height:  |  Size: 400 B

After

Width:  |  Height:  |  Size: 401 B

View File

@@ -1,8 +1,9 @@
<svg:text
[attr.x]="0"
[attr.x]="textX"
[attr.y]="textY"
[attr.text-anchor]="'middle'">
<tspan [attr.x]="spanX" dy="0">{{ text }}</tspan>
text-anchor="middle"
alignment-baseline="middle">
{{ text }}
</svg:text>
<svg:g svg-secondary-role
*ngIf="secondaryText"

Before

Width:  |  Height:  |  Size: 316 B

After

Width:  |  Height:  |  Size: 304 B

View File

@@ -14,8 +14,8 @@ export class SvgOneLineTextKeyComponent implements OnChanges {
@Input() text: string;
@Input() secondaryText: string;
textX: number;
textY: number;
spanX: number;
secondaryTextY: number;
secondaryHeight: number;
@@ -34,8 +34,8 @@ export class SvgOneLineTextKeyComponent implements OnChanges {
secondaryYModifier = 5;
}
this.textX = this.width / 2;
this.textY = this.height / 2 - textYModifier;
this.spanX = this.width / 2;
this.secondaryHeight = this.height / 4;
this.secondaryTextY = this.height - this.secondaryHeight - SECONDARY_ROLE_BOTTOM_MARGIN - secondaryYModifier;

View File

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

Before

Width:  |  Height:  |  Size: 667 B

After

Width:  |  Height:  |  Size: 715 B

View File

@@ -0,0 +1,3 @@
text {
dominant-baseline: text-bottom;
}

View File

@@ -1,12 +1,10 @@
import {
ChangeDetectionStrategy,
Component,
ElementRef,
Input,
OnChanges,
OnInit,
SimpleChanges,
ViewChild
SimpleChanges
} from '@angular/core';
import { getContentWidth } from '../../../../util';
@@ -18,6 +16,7 @@ const SECONDARY_STYLE: CSSStyleDeclaration = {
@Component({
selector: 'g[svg-secondary-role]',
templateUrl: './svg-secondary-role.component.html',
styleUrls: ['./svg-secondary-role.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class SvgSecondaryRoleComponent implements OnInit, OnChanges {
@@ -26,8 +25,6 @@ export class SvgSecondaryRoleComponent implements OnInit, OnChanges {
@Input() y: number;
@Input() text: string;
@ViewChild('secondary') svgElement: ElementRef;
viewBox: string;
textY: number;
transform: string;

View File

@@ -5,8 +5,9 @@
[attr.y]="useY">
</svg:use>
<svg:text
[attr.x]="0"
[attr.x]="textX"
[attr.y]="textY"
[attr.text-anchor]="'middle'">
<tspan [attr.x]="spanX">{{ abbreviation }}</tspan>
</svg:text>
text-anchor="middle"
alignment-baseline="middle">
{{ abbreviation }}
</svg:text>

Before

Width:  |  Height:  |  Size: 313 B

After

Width:  |  Height:  |  Size: 305 B

View File

@@ -18,7 +18,7 @@ export class SvgSwitchKeymapKeyComponent implements OnInit {
useX: number;
useY: number;
textY: number;
spanX: number;
textX: number;
constructor(private mapperService: MapperService) { }
@@ -30,6 +30,6 @@ export class SvgSwitchKeymapKeyComponent implements OnInit {
this.useX = this.width * 3 / 8;
this.useY = this.height / 5;
this.textY = this.height * 2 / 3;
this.spanX = this.width / 2;
this.textX = this.width / 2;
}
}

View File

@@ -1,9 +1,10 @@
<svg:text
[attr.x]="0"
<svg:text
[attr.x]="textX"
[attr.y]="textY"
[attr.text-anchor]="textAnchor">
<tspan [attr.x]="spanX">{{ text }}</tspan>
</svg:text>
[attr.text-anchor]="textAnchor"
alignment-baseline="middle">
{{ text }}
</svg:text>
<svg:use [attr.xlink:href]="icon"
[attr.width]="useWidth"
[attr.height]="useHeight"

Before

Width:  |  Height:  |  Size: 484 B

After

Width:  |  Height:  |  Size: 482 B

View File

@@ -21,7 +21,7 @@ export class SvgTextIconKeyComponent implements OnChanges {
useY: number;
textY: number;
textAnchor: string;
spanX: number;
textX: number;
secondaryTextY: number;
secondaryHeight: number;
@@ -46,7 +46,7 @@ export class SvgTextIconKeyComponent implements OnChanges {
this.useY = (this.width > 2 * this.height) ? this.height / 3 : this.height / 2;
this.textY = ((this.width > 2 * this.height) ? this.height / 2 : this.height / 3) - textYModifier;
this.textAnchor = (this.width > 2 * this.height) ? 'end' : 'middle';
this.spanX = (this.width > 2 * this.height) ? 0.6 * this.width : this.width / 2;
this.textX = (this.width > 2 * this.height) ? 0.6 * this.width : this.width / 2;
this.secondaryHeight = this.height / 4;
this.secondaryTextY = this.height - this.secondaryHeight - SECONDARY_ROLE_BOTTOM_MARGIN - secondaryYModifier;

View File

@@ -1,12 +1,12 @@
<svg:text
[attr.x]="0"
[attr.y]="textY"
[attr.text-anchor]="'middle'">
text-anchor="middle"
alignment-baseline="middle">
<tspan
*ngFor="let text of texts; let index = index"
[attr.x]="spanX"
[attr.y]="spanYs[index]"
dy="0"
>{{ text }}</tspan>
</svg:text>
<svg:g svg-secondary-role

Before

Width:  |  Height:  |  Size: 474 B

After

Width:  |  Height:  |  Size: 474 B

View File

@@ -27,13 +27,11 @@ export class SvgTwoLineTextKeyComponent implements OnChanges {
}
calculatePositions(): void {
let textYModifier = 0;
let secondaryYModifier = 0;
this.secondaryHeight = 0;
let textContainerHeight = this.height;
if (this.secondaryText) {
textYModifier = this.height / 5;
secondaryYModifier = 0;
this.secondaryHeight = this.height / 4;
textContainerHeight -= this.secondaryHeight;
@@ -43,7 +41,7 @@ export class SvgTwoLineTextKeyComponent implements OnChanges {
this.spanX = this.width / 2;
this.spanYs = [];
for (let i = 0; i < this.texts.length; ++i) {
this.spanYs.push((0.75 - i * 0.5) * textContainerHeight);
this.spanYs.push((0.85 - i * 0.5) * textContainerHeight);
}
this.secondaryTextY = this.height - this.secondaryHeight - SECONDARY_ROLE_BOTTOM_MARGIN - secondaryYModifier;

View File

@@ -73,7 +73,7 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges {
@Output() descriptionChanged = new EventEmitter<ChangeKeymapDescription>();
@ViewChild(PopoverComponent, { read: ElementRef }) popover: ElementRef;
@ViewChild(PopoverComponent, { read: ElementRef, static: false }) popover: ElementRef;
popoverShown: boolean;
keyEditConfig: { moduleId: number, keyId: number };
@@ -218,7 +218,7 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges {
return;
}
const el: Element = event.target as Element || event.srcElement;
const el = event.target as Element;
const position: ClientRect = el.getBoundingClientRect();
let posLeft: number = this.tooltipData.posLeft;
let posTop: number = this.tooltipData.posTop;

View File

@@ -10,13 +10,11 @@ import { XtermLog } from '../../models/xterm-log';
export class XtermComponent implements OnChanges {
@Input() logs: Array<XtermLog> = [];
@ViewChild('scrollMe') divElement: ElementRef;
@ViewChild('scrollMe', { static: false }) divElement: ElementRef;
ngOnChanges(changes: SimpleChanges): void {
if (changes.logs && this.divElement && this.divElement.nativeElement) {
setTimeout(() => {
this.divElement.nativeElement.scrollTop = this.divElement.nativeElement.scrollHeight;
});
if (changes.logs) {
this.scrollToTheEnd();
}
}
@@ -24,4 +22,11 @@ export class XtermComponent implements OnChanges {
return this.logs.reduce((value, line) => value + line.message + '\n', '');
}
scrollToTheEnd(): void {
setTimeout(() => {
if (this.divElement && this.divElement.nativeElement) {
this.divElement.nativeElement.scrollTop = this.divElement.nativeElement.scrollHeight;
}
});
}
}

View File

@@ -1 +1,3 @@
export * from './last-edited-key';
export * from './macro-menu-item';
export * from './side-menu-page-state';

View File

@@ -0,0 +1,5 @@
export interface MacroMenuItem {
id: number;
name: string;
usageCount: number;
}

View File

@@ -1,4 +1,5 @@
import { Keymap, Macro } from 'uhk-common';
import { MacroMenuItem } from './macro-menu-item';
export interface SideMenuPageState {
showAddonMenu: boolean;
@@ -6,6 +7,7 @@ export interface SideMenuPageState {
updatingFirmware: boolean;
deviceName: string;
keymaps: Keymap[];
macros: Macro[];
macros: MacroMenuItem[];
restoreUserConfiguration: boolean;
macroUsageCountVisible: boolean;
}

View File

@@ -19,7 +19,9 @@ export enum ActionTypes {
SetupPermissionError = '[app] Setup permission error',
LoadAppStartInfo = '[app] Load app start info',
StartKeypressCapturing = '[app] Start keypress capturing',
StopKeypressCapturing = '[app] Stop keypress capturing'
StopKeypressCapturing = '[app] Stop keypress capturing',
KeyDown = '[app] Key down',
KeyUp = '[app] Key up'
}
export class AppBootstrappedAction implements Action {
@@ -110,6 +112,18 @@ export class StopKeypressCapturingAction implements Action {
type = ActionTypes.StopKeypressCapturing;
}
export class KeyDownAction implements Action {
readonly type = ActionTypes.KeyDown;
constructor(public payload: KeyboardEvent) {}
}
export class KeyUpAction implements Action {
readonly type = ActionTypes.KeyUp;
constructor(public payload: KeyboardEvent) {}
}
export type Actions
= AppStartedAction
| AppBootstrappedAction
@@ -127,4 +141,6 @@ export type Actions
| LoadAppStartInfoAction
| StartKeypressCapturingAction
| StopKeypressCapturingAction
| KeyDownAction
| KeyUpAction
;

View File

@@ -1,7 +1,7 @@
import { ActionReducerMap, createSelector, MetaReducer } from '@ngrx/store';
import { routerReducer, RouterReducerState } from '@ngrx/router-store';
import { storeFreeze } from 'ngrx-store-freeze';
import { HardwareModules, Keymap, UserConfiguration } from 'uhk-common';
import { HardwareModules, Keymap, UserConfiguration, PlayMacroAction } from 'uhk-common';
import * as fromUserConfig from './reducers/user-configuration';
import * as fromPreset from './reducers/preset';
@@ -16,6 +16,7 @@ import { environment } from '../../environments/environment';
import { RouterStateUrl } from './router-util';
import { PrivilagePageSate } from '../models/privilage-page-sate';
import { isVersionGte } from '../util';
import { SideMenuPageState, MacroMenuItem } from '../models';
// State interface for the application
export interface AppState {
@@ -67,6 +68,7 @@ export const deviceConfigurationLoaded = createSelector(appState, fromApp.device
export const getAgentVersionInfo = createSelector(appState, fromApp.getAgentVersionInfo);
export const getOperatingSystem = createSelector(appState, fromSelectors.getOperatingSystem);
export const keypressCapturing = createSelector(appState, fromApp.keypressCapturing);
export const getMacroUsageCountVisible = createSelector(appState, fromApp.macroUsageCountVisible);
export const runningOnNotSupportedWindows = createSelector(appState, fromApp.runningOnNotSupportedWindows);
export const contributors = (state: AppState) => state.contributors;
export const firmwareUpgradeAllowed = createSelector(runningOnNotSupportedWindows, notSupportedOs => !notSupportedOs);
@@ -123,25 +125,57 @@ export const getPrivilegePageState = createSelector(appState, getUpdateUdevRules
};
});
export const getMacroMenuItems = (userConfiguration: UserConfiguration): MacroMenuItem[] => {
const macroMap = userConfiguration.macros.reduce((map, macro) => {
return map.set(macro.id, {
id: macro.id,
name: macro.name,
usageCount: 0
});
}, new Map<number, MacroMenuItem>());
for (const keymap of userConfiguration.keymaps) {
for (const layer of keymap.layers) {
for (const module of layer.modules) {
for (const keyAction of module.keyActions) {
if (!(keyAction instanceof PlayMacroAction)) {
continue;
}
const menuItem = macroMap.get(keyAction.macroId);
menuItem.usageCount++;
}
}
}
}
return Array
.from(macroMap.values())
.sort((first: MacroMenuItem, second: MacroMenuItem) => first.name.localeCompare(second.name));
};
export const getSideMenuPageState = createSelector(
showAddonMenu,
runningInElectron,
updatingFirmware,
getUserConfiguration,
getRestoreUserConfiguration,
getMacroUsageCountVisible,
(showAddonMenuValue: boolean,
runningInElectronValue: boolean,
updatingFirmwareValue: boolean,
userConfiguration: UserConfiguration,
restoreUserConfiguration: boolean) => {
restoreUserConfiguration: boolean,
macroUsageCountVisible): SideMenuPageState => {
return {
showAddonMenu: showAddonMenuValue,
runInElectron: runningInElectronValue,
updatingFirmware: updatingFirmwareValue,
deviceName: userConfiguration.deviceName,
keymaps: userConfiguration.keymaps,
macros: userConfiguration.macros,
restoreUserConfiguration
macros: getMacroMenuItems(userConfiguration),
restoreUserConfiguration,
macroUsageCountVisible
};
}
);
@@ -157,3 +191,6 @@ export const layerDoubleTapSupported = createSelector(
return isVersionGte(hardwareModules.rightModuleInfo.firmwareVersion, '8.4.3');
}
);
export const extraMouseButtonsSupported = createSelector(getHardwareModules, (hardwareModules: HardwareModules): boolean => {
return isVersionGte(hardwareModules.rightModuleInfo.userConfigVersion, '4.1.1');
});

View File

@@ -30,6 +30,7 @@ export interface State {
platform?: string;
osVersion?: string;
keypressCapturing: boolean;
macroUsageCountVisible: boolean;
}
export const initialState: State = {
@@ -40,7 +41,8 @@ export const initialState: State = {
configLoading: true,
agentVersionInfo: getVersions(),
privilegeWhatWillThisDoClicked: false,
keypressCapturing: false
keypressCapturing: false,
macroUsageCountVisible: false
};
export function reducer(
@@ -156,7 +158,8 @@ export function reducer(
case App.ActionTypes.StartKeypressCapturing:
return {
...state,
keypressCapturing: true
keypressCapturing: true,
macroUsageCountVisible: false
};
case App.ActionTypes.StopKeypressCapturing:
@@ -165,6 +168,24 @@ export function reducer(
keypressCapturing: false
};
case App.ActionTypes.KeyDown: {
const event = (action as App.KeyDownAction).payload;
return {
...state,
macroUsageCountVisible: !state.keypressCapturing && !event.defaultPrevented && event.altKey
};
}
case App.ActionTypes.KeyUp: {
const event = (action as App.KeyDownAction).payload;
return {
...state,
macroUsageCountVisible: event.altKey
};
}
default:
return state;
}
@@ -197,3 +218,4 @@ export const runningOnNotSupportedWindows = (state: State): boolean => {
};
export const keypressCapturing = (state: State): boolean => state.keypressCapturing;
export const macroUsageCountVisible = (state: State): boolean => state.macroUsageCountVisible;

View File

@@ -49,7 +49,7 @@ export const initialState: State = {
log: [{ message: '', cssClass: XtermCssClass.standard }],
restoringUserConfiguration: false,
hasBackupUserConfiguration: false,
halvesInfo: { isLeftHalfConnected: true, areHalvesMerged: true }
halvesInfo: { isLeftHalfConnected: true, areHalvesMerged: false }
};
export function reducer(state = initialState, action: Action): State {

View File

@@ -446,16 +446,9 @@ export function reducer(
const userConfiguration: UserConfiguration = Object.assign(new UserConfiguration(), state.userConfiguration);
userConfiguration.macros = state.userConfiguration.macros.map((macro: Macro) => {
if (macro.id === payload.id) {
let newIndex: number = payload.newIndex;
// We need to reduce the new index for one when we are moving action down
if (newIndex > payload.oldIndex) {
--newIndex;
}
macro = new Macro(macro);
macro.macroActions.splice(
newIndex,
payload.newIndex,
0,
macro.macroActions.splice(payload.oldIndex, 1)[0]
);

View File

@@ -15,7 +15,7 @@ import { effects } from './store/effects';
BrowserModule,
SharedModule,
StoreModule.forRoot(reducers),
StoreRouterConnectingModule,
StoreRouterConnectingModule.forRoot(),
StoreDevtoolsModule.instrument({
maxAge: 10
}),

View File

@@ -8,4 +8,6 @@ if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(UhkRendererModule);
platformBrowserDynamic().bootstrapModule(UhkRendererModule, {
preserveWhitespaces: true
});

View File

@@ -5,7 +5,9 @@ import { WebModule } from './app/web.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(WebModule);
platformBrowserDynamic().bootstrapModule(WebModule, {
preserveWhitespaces: true
});

View File

@@ -22,7 +22,7 @@ import { effects } from '../app/store/effects';
SharedModule,
routing,
StoreModule.forRoot(reducers),
StoreRouterConnectingModule,
StoreRouterConnectingModule.forRoot(),
StoreDevtoolsModule.instrument({
maxAge: 10
}),

View File

@@ -3,7 +3,7 @@
"compilerOptions": {
"outDir": "./dist/out-tsc",
"baseUrl": "./",
"target": "es6",
"target": "es5", // Until https://github.com/electron/electron/issues/12011 not working without custom protocol
"types": ["node"],
"lib": [
"es2016",

View File

@@ -0,0 +1,26 @@
import * as path from 'path';
import { LogService } from 'uhk-common';
import { UhkHidDevice, UhkOperations } from 'uhk-usb';
const logService = new LogService();
const rootDir = path.join(__dirname, '../../tmp');
const uhkHidDevice = new UhkHidDevice(logService, {}, rootDir);
const uhkOperations = new UhkOperations(logService, uhkHidDevice, rootDir);
process.on('uncaughtException', error => {
console.error('uncaughtException', error);
process.exit(1);
});
process.on('unhandledRejection', (reason: any, promise: Promise<any>): void => {
console.error('unhandledRejection', { reason, promise });
});
uhkOperations
.updateRightFirmwareWithKboot()
.then(() => uhkOperations.updateLeftModuleWithKboot())
.then(() => console.log('Firmware upgrade finished'))
.catch(error => {
console.error(error);
process.exit(-1);
});

View File

@@ -37,9 +37,9 @@
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"base64-js": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz",
"integrity": "sha1-EQHpVE9KdrG8OybUUsqW16NeeXg="
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
"integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
},
"bindings": {
"version": "1.5.0",
@@ -68,20 +68,38 @@
}
},
"buffer": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz",
"integrity": "sha1-pyyTb3e5a/UvX357RnGAYoVR3vs=",
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.0.tgz",
"integrity": "sha512-Xpgy0IwHK2N01ncykXTy6FpCWuM+CJSHoPVBLyNqyrWxsedpLvwsYUhf0ME3WRFNUhos0dMamz9cOS/xRDtU5g==",
"requires": {
"base64-js": "0.0.8",
"ieee754": "^1.1.4",
"isarray": "^1.0.0"
"base64-js": "^1.0.2",
"ieee754": "^1.1.4"
}
},
"buffer-alloc": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
"integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==",
"requires": {
"buffer-alloc-unsafe": "^1.1.0",
"buffer-fill": "^1.0.0"
}
},
"buffer-alloc-unsafe": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
"integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg=="
},
"buffer-crc32": {
"version": "0.2.13",
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
"integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI="
},
"buffer-fill": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
"integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw="
},
"chalk": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz",
@@ -93,9 +111,9 @@
}
},
"chownr": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
"integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g=="
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.2.tgz",
"integrity": "sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A=="
},
"code-point-at": {
"version": "1.1.0",
@@ -103,11 +121,11 @@
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
},
"color-convert": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz",
"integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==",
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"requires": {
"color-name": "^1.1.1"
"color-name": "1.1.3"
}
},
"color-name": {
@@ -116,9 +134,9 @@
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"commander": {
"version": "2.15.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
"integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag=="
"version": "2.20.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
"integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ=="
},
"concat-map": {
"version": "0.0.1",
@@ -255,9 +273,9 @@
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="
},
"fd-slicer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz",
"integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
"integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
"requires": {
"pend": "~1.2.0"
}
@@ -272,6 +290,11 @@
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
},
"fs-constants": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -307,9 +330,9 @@
"integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4="
},
"glob": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
"integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
@@ -320,9 +343,9 @@
}
},
"graceful-fs": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.1.tgz",
"integrity": "sha512-b9usnbDGnD928gJB3LrCmxoibr3VE4U2SMo5PBuBnokWyDADTqDPXg4YpwKF1trpH+UbGp7QLicO3+aWEy0+mw=="
},
"graceful-readlink": {
"version": "1.0.1",
@@ -340,9 +363,9 @@
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
},
"ieee754": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.11.tgz",
"integrity": "sha512-VhDzCKN7K8ufStx/CLj5/PDTMgph+qwN5Pkd5i0sGnVwk56zJ0lkT8Qzi1xqWLS0Wp29DgDtNeS7v8/wMoZeHg=="
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
"integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="
},
"inflight": {
"version": "1.0.6",
@@ -354,9 +377,9 @@
}
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"ini": {
"version": "1.3.5",
@@ -364,9 +387,9 @@
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
},
"interpret": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz",
"integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ="
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz",
"integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw=="
},
"is-fullwidth-code-point": {
"version": "1.0.0",
@@ -392,9 +415,9 @@
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"make-dir": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.2.0.tgz",
"integrity": "sha512-aNUAa4UMg/UougV25bbrU4ZaaKNjJ/3/xnvg/twpmKROPdKZPZ9wGgI0opdZzO8q/zUFawoUuixuOv33eZ61Iw==",
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
"integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
"requires": {
"pify": "^3.0.0"
},
@@ -450,17 +473,17 @@
"integrity": "sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA=="
},
"node-abi": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.8.0.tgz",
"integrity": "sha512-1/aa2clS0pue0HjckL62CsbhWWU35HARvBDXcJtYKbYR7LnIutmpxmXbuDMV9kEviD2lP/wACOgWmmwljghHyQ==",
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.11.0.tgz",
"integrity": "sha512-kuy/aEg75u40v378WRllQ4ZexaXJiCvB68D2scDXclp/I4cRq6togpbOoKhmN07tns9Zldu51NNERo0wehfX9g==",
"requires": {
"semver": "^5.4.1"
}
},
"node-hid": {
"version": "0.7.8",
"resolved": "https://registry.npmjs.org/node-hid/-/node-hid-0.7.8.tgz",
"integrity": "sha512-79Z9hw/pqIDp0kxvb353ivGgslo4i0hYQTcCqfRFxIJSO2gF9VtPla5uQY/9jTcDlON5O5YaqxbdH+8bs+m+1Q==",
"version": "0.7.9",
"resolved": "https://registry.npmjs.org/node-hid/-/node-hid-0.7.9.tgz",
"integrity": "sha512-vJnonTqmq3frCyTumJqG4g2IZcny3ynkfmbfDfQ90P3ZhRzcWYS/Um1ux6HFmAxmkaQnrZqIYHcGpL7kdqY8jA==",
"requires": {
"bindings": "^1.5.0",
"nan": "^2.13.2",
@@ -517,9 +540,9 @@
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"path-parse": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
"integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME="
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
},
"pend": {
"version": "1.2.0",
@@ -568,9 +591,9 @@
}
},
"process-nextick-args": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"pump": {
"version": "2.0.1",
@@ -604,6 +627,13 @@
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
},
"dependencies": {
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
}
}
},
"rechoir": {
@@ -615,17 +645,17 @@
}
},
"resolve": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.0.tgz",
"integrity": "sha512-QdgZ5bjR1WAlpLaO5yHepFvC+o3rCr6wpfE2tpJNMkXdulf2jKomQBdNRQITF3ZKHNlT71syG98yQP03gasgnA==",
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz",
"integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==",
"requires": {
"path-parse": "^1.0.5"
"path-parse": "^1.0.6"
}
},
"safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
"integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
},
"seek-bzip": {
"version": "1.0.5",
@@ -646,9 +676,9 @@
}
},
"semver": {
"version": "5.7.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA=="
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
},
"set-blocking": {
"version": "2.0.0",
@@ -712,6 +742,13 @@
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
},
"dependencies": {
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
}
}
},
"strip-ansi": {
@@ -766,13 +803,16 @@
}
},
"tar-stream": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.5.tgz",
"integrity": "sha512-mQdgLPc/Vjfr3VWqWbfxW8yQNiJCbAZ+Gf6GDu1Cy0bdb33ofyiNGBtAY96jHFhDuivCwgW1H9DgTON+INiXgg==",
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz",
"integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==",
"requires": {
"bl": "^1.0.0",
"buffer-alloc": "^1.2.0",
"end-of-stream": "^1.0.0",
"readable-stream": "^2.0.0",
"fs-constants": "^1.0.0",
"readable-stream": "^2.3.0",
"to-buffer": "^1.1.1",
"xtend": "^4.0.0"
}
},
@@ -789,6 +829,11 @@
"os-tmpdir": "~1.0.2"
}
},
"to-buffer": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz",
"integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg=="
},
"tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
@@ -804,12 +849,12 @@
"dev": true
},
"unbzip2-stream": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.2.5.tgz",
"integrity": "sha512-izD3jxT8xkzwtXRUZjtmRwKnZoeECrfZ8ra/ketwOcusbZEp4mjULMnJOCfTDZBgGQAAY1AJ/IgxcwkavcX9Og==",
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz",
"integrity": "sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg==",
"requires": {
"buffer": "^3.0.1",
"through": "^2.3.6"
"buffer": "^5.2.1",
"through": "^2.3.8"
}
},
"util-deprecate": {
@@ -836,17 +881,17 @@
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"xtend": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
},
"yauzl": {
"version": "2.9.1",
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.9.1.tgz",
"integrity": "sha1-qBmB6nCleUYTOIPwKcWCGok1mn8=",
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
"integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
"requires": {
"buffer-crc32": "~0.2.3",
"fd-slicer": "~1.0.1"
"fd-slicer": "~1.1.0"
}
}
}

View File

@@ -13,7 +13,7 @@
"commander": "^2.11.0",
"decompress": "^4.2.0",
"decompress-tarbz2": "^4.1.1",
"node-hid": "0.7.8",
"node-hid": "0.7.9",
"shelljs": "^0.7.8",
"tmp": "0.0.33",
"uhk-common": "1.0.0",

View File

@@ -1,6 +1,3 @@
#!/usr/bin/env ts-node
///<reference path="./node_modules/@types/node/index.d.ts"/>
import { UhkBuffer, UserConfiguration } from 'uhk-common';
import * as fs from 'fs';

View File

@@ -8,6 +8,13 @@ const copyOptions = {
const promises = [];
promises.push(
fse.copy(
path.join(__dirname, '../packages/usb/blhost'),
path.join(__dirname, '../tmp/packages/blhost'),
copyOptions)
);
promises.push(
fse.copy(
path.join(__dirname, '../rules'),

Some files were not shown because too many files have changed in this diff Show More