Compare commits
44 Commits
chore-kboo
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b53751b408 | ||
|
|
8a7f30dbb1 | ||
|
|
3b67e4d71d | ||
|
|
d0626405a9 | ||
|
|
df040fb78e | ||
|
|
ea4ca7c39c | ||
|
|
c477f9bcdc | ||
|
|
abe740cf61 | ||
|
|
1003e7b14b | ||
|
|
fef24613e4 | ||
|
|
9844645409 | ||
|
|
6814c8e126 | ||
|
|
d87d770042 | ||
|
|
5dc2e6f47b | ||
|
|
9f8926e34b | ||
|
|
0bd1152a32 | ||
|
|
4a1e88ed83 | ||
|
|
9db719a54b | ||
|
|
49d31f90f7 | ||
|
|
d364ac85a6 | ||
|
|
fae83a4148 | ||
|
|
ac76674469 | ||
|
|
6867ef45f6 | ||
|
|
239c989cbe | ||
|
|
bfa8343aa5 | ||
|
|
0914a1496b | ||
|
|
a8c2866f95 | ||
|
|
79f467603a | ||
|
|
c4269d4cf1 | ||
|
|
d15e08430f | ||
|
|
ee28065046 | ||
|
|
a64a44fe41 | ||
|
|
fa5f5cdc5d | ||
|
|
4147243565 | ||
|
|
905007a597 | ||
|
|
c3fec647b6 | ||
|
|
5f5aff71a5 | ||
|
|
f65bf80c74 | ||
|
|
f6bef928fe | ||
|
|
b691f866c5 | ||
|
|
5ab5ad5f0c | ||
|
|
4e09f95653 | ||
|
|
37a67805ce | ||
|
|
735aae03d9 |
@@ -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.
|
||||
|
||||
@@ -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
@@ -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.
|
||||
@@ -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.
|
||||
|
||||
@@ -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
43
package.json
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
94
packages/kboot/package-lock.json
generated
@@ -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=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
161
packages/uhk-agent/package-lock.json
generated
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -14,6 +14,6 @@
|
||||
"npm": ">=5.1.0 <6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"node-hid": "0.7.8"
|
||||
"node-hid": "0.7.9"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,12 @@ export enum MouseActionParam {
|
||||
scrollLeft,
|
||||
scrollRight,
|
||||
accelerate,
|
||||
decelerate
|
||||
decelerate,
|
||||
button4,
|
||||
button5,
|
||||
button6,
|
||||
button7,
|
||||
button8
|
||||
}
|
||||
|
||||
export class MouseAction extends KeyAction {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export interface HardwareModuleInfo {
|
||||
export interface LeftModuleInfo {
|
||||
firmwareVersion?: string;
|
||||
moduleProtocolVersion?: string;
|
||||
}
|
||||
7
packages/uhk-common/src/models/right-module-info.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export interface RightModuleInfo {
|
||||
deviceProtocolVersion?: string;
|
||||
hardwareConfigVersion?: string;
|
||||
firmwareVersion?: string;
|
||||
moduleProtocolVersion?: string;
|
||||
userConfigVersion?: string;
|
||||
}
|
||||
42
packages/uhk-usb/package-lock.json
generated
@@ -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=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from './constants';
|
||||
export * from './uhk-blhost';
|
||||
export * from './uhk-hid-device';
|
||||
export * from './uhk-operations';
|
||||
export * from './util';
|
||||
|
||||
89
packages/uhk-usb/src/uhk-blhost.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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()}`
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
10254
packages/uhk-web/package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(); }
|
||||
|
||||
|
||||
@@ -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) { }
|
||||
|
||||
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -148,6 +148,12 @@ ul {
|
||||
right: 19px;
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
&__macro_count {
|
||||
position: absolute;
|
||||
right: 11px;
|
||||
top: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.menu--bottom {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -91,6 +91,7 @@ export class SvgKeyboardComponent {
|
||||
this.modules = [];
|
||||
this.viewBox = '-520 582 1100 470';
|
||||
this.moduleAnimationStates = [];
|
||||
this.moduleVisibilityAnimationStates = [];
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
:host {
|
||||
/deep/ text {
|
||||
dominant-baseline: central;
|
||||
}
|
||||
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 |
@@ -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>
|
||||
<tspan dy="80"> {{ button }} </tspan>
|
||||
</svg:text>
|
||||
|
Before Width: | Height: | Size: 403 B After Width: | Height: | Size: 404 B |
@@ -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';
|
||||
|
||||
@@ -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>
|
||||
|
Before Width: | Height: | Size: 332 B After Width: | Height: | Size: 333 B |
@@ -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>
|
||||
|
Before Width: | Height: | Size: 334 B After Width: | Height: | Size: 335 B |
@@ -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>
|
||||
<tspan dy="80"> {{ sign }} </tspan>
|
||||
</svg:text>
|
||||
|
Before Width: | Height: | Size: 400 B After Width: | Height: | Size: 401 B |
@@ -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 |
@@ -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;
|
||||
|
||||
@@ -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 |
@@ -0,0 +1,3 @@
|
||||
text {
|
||||
dominant-baseline: text-bottom;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
text-anchor="middle"
|
||||
alignment-baseline="middle">
|
||||
{{ abbreviation }}
|
||||
</svg:text>
|
||||
|
Before Width: | Height: | Size: 313 B After Width: | Height: | Size: 305 B |
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 |
@@ -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;
|
||||
|
||||
@@ -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 |
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
export * from './last-edited-key';
|
||||
export * from './macro-menu-item';
|
||||
export * from './side-menu-page-state';
|
||||
|
||||
5
packages/uhk-web/src/app/models/macro-menu-item.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface MacroMenuItem {
|
||||
id: number;
|
||||
name: string;
|
||||
usageCount: number;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
;
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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]
|
||||
);
|
||||
|
||||
@@ -15,7 +15,7 @@ import { effects } from './store/effects';
|
||||
BrowserModule,
|
||||
SharedModule,
|
||||
StoreModule.forRoot(reducers),
|
||||
StoreRouterConnectingModule,
|
||||
StoreRouterConnectingModule.forRoot(),
|
||||
StoreDevtoolsModule.instrument({
|
||||
maxAge: 10
|
||||
}),
|
||||
|
||||
@@ -8,4 +8,6 @@ if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(UhkRendererModule);
|
||||
platformBrowserDynamic().bootstrapModule(UhkRendererModule, {
|
||||
preserveWhitespaces: true
|
||||
});
|
||||
|
||||
@@ -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
|
||||
});
|
||||
|
||||
@@ -22,7 +22,7 @@ import { effects } from '../app/store/effects';
|
||||
SharedModule,
|
||||
routing,
|
||||
StoreModule.forRoot(reducers),
|
||||
StoreRouterConnectingModule,
|
||||
StoreRouterConnectingModule.forRoot(),
|
||||
StoreDevtoolsModule.instrument({
|
||||
maxAge: 10
|
||||
}),
|
||||
|
||||
@@ -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",
|
||||
|
||||
26
packages/usb/kboot-firmware-upgrade.ts
Normal 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);
|
||||
});
|
||||
201
packages/usb/package-lock.json
generated
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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'),
|
||||
|
||||