Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8bb645125d | ||
|
|
9471b31a5d | ||
|
|
ffa52757c9 | ||
|
|
ee53a0df9b | ||
|
|
8e20c85e07 | ||
|
|
65ea786358 | ||
|
|
1035837b3b | ||
|
|
18fc2e6b3f | ||
|
|
fc728697d7 | ||
|
|
cdf3caee9e | ||
|
|
0a4d3a002e | ||
|
|
d11c532ea4 | ||
|
|
1ff51697b1 | ||
|
|
ab8ae31324 | ||
|
|
daa0e723b1 | ||
|
|
609aba856a | ||
|
|
a6678bd537 | ||
|
|
6c4f580fc2 | ||
|
|
ea41661c65 | ||
|
|
c553c7b63b | ||
|
|
e5988aa800 | ||
|
|
ae319c607f | ||
|
|
5d23ad1c9e | ||
|
|
55eef50da7 | ||
|
|
653465f0e0 | ||
|
|
2cf8044987 | ||
|
|
3c056a7255 | ||
|
|
091796d13c | ||
|
|
eb97dd844f | ||
|
|
17693ec8fe | ||
|
|
7c7ce8f50f | ||
|
|
e294727ac5 | ||
|
|
f29d64c803 | ||
|
|
0385b0ce29 | ||
|
|
b526274cd7 | ||
|
|
88c16af4a9 | ||
|
|
05ac9a6832 | ||
|
|
04aa5236c2 | ||
|
|
ec98e4e1c6 | ||
|
|
bb9ece494c | ||
|
|
217e6776ac | ||
|
|
2286218980 | ||
|
|
3d9c83f9f4 | ||
|
|
14ed163238 | ||
|
|
c815de0718 | ||
|
|
6a46556d9e | ||
|
|
f8f820529f | ||
|
|
cac11155e7 | ||
|
|
d20870f11e | ||
|
|
10ceb6c79d | ||
|
|
b38b6fa294 | ||
|
|
94c1d35429 | ||
|
|
e33cef4e89 | ||
|
|
9b815ed9c1 | ||
|
|
1d4bb6113c | ||
|
|
136120b831 | ||
|
|
cd299c06d6 |
39
CHANGELOG.md
39
CHANGELOG.md
@@ -6,6 +6,43 @@ The format is loosely based on [Keep a Changelog](http://keepachangelog.com/en/1
|
|||||||
|
|
||||||
Every Agent version includes the most recent firmware version. See the [firmware changelog](https://github.com/UltimateHackingKeyboard/firmware/blob/master/CHANGELOG.md).
|
Every Agent version includes the most recent firmware version. See the [firmware changelog](https://github.com/UltimateHackingKeyboard/firmware/blob/master/CHANGELOG.md).
|
||||||
|
|
||||||
|
## [1.2.2] - 2018-05-27
|
||||||
|
|
||||||
|
Firmware: 8.2.**5** [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.2.5)] | Device Protocol: 4.3.**1** | User Config: 4.0.**1** | Hardware Config: 1.0.0
|
||||||
|
|
||||||
|
- Offer recovery for bricked right keyboard halfs.
|
||||||
|
- Detect when the hardware configuration of a device is invalid and display a notification.
|
||||||
|
- Check if the keyboard is in factory reset mode and if so, display a relevant instruction.
|
||||||
|
- Only allow ASCII characters in type text macro actions.
|
||||||
|
- Allow uploading the same file multiple times in a row.
|
||||||
|
- Only send auto update notification when the user initiates the update.
|
||||||
|
- Update the firmware versions on the firmware update page right after firmware updates.
|
||||||
|
- Add a lot of useful instructions to the firmware page to help users update the firmware.
|
||||||
|
- Add the operating system and initial device list to the firmware update log.
|
||||||
|
- Add copy to clipboard button to the top right corner of the firmware update terminal widget.
|
||||||
|
|
||||||
|
## [1.2.1] - 2018-05-12
|
||||||
|
|
||||||
|
Firmware: 8.2.**2** [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.2.2)] | Device Protocol: 4.3.0 | User Config: 4.0.**1** | Hardware Config: 1.0.0
|
||||||
|
|
||||||
|
- Match for the new USB usage page and usage number. This is critical for UHKs flashed with firmware >=8.2.2 to be recognized by Agent on OSX.
|
||||||
|
- Make the config serializer handle long media macro actions. `USERCONFIG:PATCH`
|
||||||
|
- Add note on the macro page explaining that the macro engine of the firmware is not ready yet.
|
||||||
|
- Add an example to the scancode tooltip to better explain users how to invoke non-US characters.
|
||||||
|
|
||||||
|
## [1.2.0] - 2018-04-20
|
||||||
|
|
||||||
|
Firmware: 8.**2.0** [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.2.0)] | Device Protocol: 4.**3.0** | User Config: 4.0.0 | Hardware Config: 1.0.0
|
||||||
|
|
||||||
|
- Tweak the default mouse speed. This was necessary because the last firmware version adjusted speed multipliers. The mouse speed can be reset via the "Reset speeds to default" button of the "Mouse speed" page.
|
||||||
|
- Make the newly added switch-keymap.js script utilize the new UsbCommandId_SwitchKeymap, allowing for programmatic keymap switching. `DEVICEPROTOCOL:MINOR`
|
||||||
|
|
||||||
|
## [1.1.5] - 2018-04-10
|
||||||
|
|
||||||
|
Firmware: 8.1.5 [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.1.5)] | Device Protocol: 4.2.0 | User Config: 4.0.0 | Hardware Config: 1.0.0
|
||||||
|
|
||||||
|
- Don't allow to run multiple instances of Agent at the same time, but rather focus the already existing Agent window.
|
||||||
|
|
||||||
## [1.1.4] - 2018-04-09
|
## [1.1.4] - 2018-04-09
|
||||||
|
|
||||||
Firmware: 8.1.5 [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.1.5)] | Device Protocol: 4.2.0 | User Config: 4.0.0 | Hardware Config: 1.0.0
|
Firmware: 8.1.5 [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.1.5)] | Device Protocol: 4.2.0 | User Config: 4.0.0 | Hardware Config: 1.0.0
|
||||||
@@ -50,7 +87,7 @@ Firmware: 8.1.**2** [[release](https://github.com/UltimateHackingKeyboard/firmwa
|
|||||||
|
|
||||||
## [1.1.0] - 2018-01-15
|
## [1.1.0] - 2018-01-15
|
||||||
|
|
||||||
Firmware: 8.**1**.0 [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.1.0)] | Device Protocol: 4.2.0 | User Config: 4.0.0 | Hardware Config: 1.0.0
|
Firmware: 8.**1**.0 [[release](https://github.com/UltimateHackingKeyboard/firmware/releases/tag/v8.1.0)] | Device Protocol: 4.**2.0** | User Config: 4.0.0 | Hardware Config: 1.0.0
|
||||||
|
|
||||||
- Only accept device, keymap, and macro names upon editing if their trimmed length is non-zero.
|
- Only accept device, keymap, and macro names upon editing if their trimmed length is non-zero.
|
||||||
- Add diagnostics USB scripts, most notably /packages/usb/{get-i2c-health,set-i2c-baud-rate}.js, some utilizing new device protocol commands and properties. `DEVICEPROTOCOL:MINOR`
|
- Add diagnostics USB scripts, most notably /packages/usb/{get-i2c-health,set-i2c-baud-rate}.js, some utilizing new device protocol commands and properties. `DEVICEPROTOCOL:MINOR`
|
||||||
|
|||||||
19
README.md
19
README.md
@@ -5,17 +5,8 @@
|
|||||||
|
|
||||||
Agent is the configuration application of the [Ultimate Hacking Keyboard](https://ultimatehackingkeyboard.com/).
|
Agent is the configuration application of the [Ultimate Hacking Keyboard](https://ultimatehackingkeyboard.com/).
|
||||||
|
|
||||||
[Give it a whirl!](http://ultimatehackingkeyboard.github.io/agent/)
|
* Try out the [web build of Agent](http://ultimatehackingkeyboard.github.io/agent/) in your browser. This is meant to be used for demonstration purposes.
|
||||||
|
* Download the [desktop build of Agent](https://github.com/UltimateHackingKeyboard/agent/releases) from our releases page. Use this if you have an actual UHK at hand, or else you won't get past the opening screen!
|
||||||
## Two builds to rule them all
|
|
||||||
|
|
||||||
It's worth mentioning that Agent has two builds.
|
|
||||||
|
|
||||||
The **electron build** is the desktop application which is meant to be used if you have an actual UHK at hand. It starts with an opening screen which detects your UHK. You cannot get past this screen without connecting a UHK via USB.
|
|
||||||
|
|
||||||
The **web build** is meant to be used for demonstration purposes, so people who don't yet own a UHK can get a feel of Agent and its capabilities in their browser. Eventually, WebUSB support will be added to the web build, making it able to communicate with the UHK. Given the sandboxed nature of browsers, the web build will always lack features that the electron build offers, so this won't make the electron build obsolete.
|
|
||||||
|
|
||||||
The two builds share code as much as possible.
|
|
||||||
|
|
||||||
## Building the electron application
|
## Building the electron application
|
||||||
|
|
||||||
@@ -33,9 +24,9 @@ For everyone else, use the appropriate package manager for your OS.
|
|||||||
```
|
```
|
||||||
git clone git@github.com:UltimateHackingKeyboard/agent.git
|
git clone git@github.com:UltimateHackingKeyboard/agent.git
|
||||||
cd agent
|
cd agent
|
||||||
npm install # to install Node dependencies
|
npm install
|
||||||
npm run build:electron # to build the agent
|
npm run build
|
||||||
npm run electron # to run the newly built agent
|
npm run electron
|
||||||
```
|
```
|
||||||
|
|
||||||
At this point, Agent should be running on your machine.
|
At this point, Agent should be running on your machine.
|
||||||
|
|||||||
2402
package-lock.json
generated
2402
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
22
package.json
22
package.json
@@ -3,10 +3,10 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"author": "Ultimate Gadget Laboratories",
|
"author": "Ultimate Gadget Laboratories",
|
||||||
"main": "electron/dist/electron-main.js",
|
"main": "electron/dist/electron-main.js",
|
||||||
"version": "1.1.4",
|
"version": "1.2.2",
|
||||||
"firmwareVersion": "8.1.5",
|
"firmwareVersion": "8.2.5",
|
||||||
"deviceProtocolVersion": "4.2.0",
|
"deviceProtocolVersion": "4.3.1",
|
||||||
"userConfigVersion": "4.0.0",
|
"userConfigVersion": "4.0.1",
|
||||||
"hardwareConfigVersion": "1.0.0",
|
"hardwareConfigVersion": "1.0.0",
|
||||||
"description": "Agent is the configuration application of the Ultimate Hacking Keyboard.",
|
"description": "Agent is the configuration application of the Ultimate Hacking Keyboard.",
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
"@types/electron-settings": "3.0.0",
|
"@types/electron-settings": "3.0.0",
|
||||||
"@types/fs-extra": "5.0.1",
|
"@types/fs-extra": "5.0.1",
|
||||||
"@types/jasmine": "2.6.0",
|
"@types/jasmine": "2.6.0",
|
||||||
|
"@types/jquery": "3.3.1",
|
||||||
"@types/jsonfile": "4.0.1",
|
"@types/jsonfile": "4.0.1",
|
||||||
"@types/node": "8.0.53",
|
"@types/node": "8.0.53",
|
||||||
"@types/node-hid": "0.5.2",
|
"@types/node-hid": "0.5.2",
|
||||||
@@ -30,8 +31,9 @@
|
|||||||
"@types/usb": "1.1.3",
|
"@types/usb": "1.1.3",
|
||||||
"autoprefixer": "6.5.3",
|
"autoprefixer": "6.5.3",
|
||||||
"buffer": "5.0.6",
|
"buffer": "5.0.6",
|
||||||
"copyfiles": "^2.0.0",
|
"check-node-version": "^3.2.0",
|
||||||
"copy-webpack-plugin": "4.0.1",
|
"copy-webpack-plugin": "4.0.1",
|
||||||
|
"copyfiles": "^2.0.0",
|
||||||
"core-js": "2.4.1",
|
"core-js": "2.4.1",
|
||||||
"cross-env": "5.0.5",
|
"cross-env": "5.0.5",
|
||||||
"decompress": "4.2.0",
|
"decompress": "4.2.0",
|
||||||
@@ -48,6 +50,7 @@
|
|||||||
"exports-loader": "0.6.3",
|
"exports-loader": "0.6.3",
|
||||||
"file-loader": "0.10.0",
|
"file-loader": "0.10.0",
|
||||||
"fs-extra": "5.0.0",
|
"fs-extra": "5.0.0",
|
||||||
|
"gh-pages": "1.1.0",
|
||||||
"jsonfile": "4.0.0",
|
"jsonfile": "4.0.0",
|
||||||
"lerna": "2.9.0",
|
"lerna": "2.9.0",
|
||||||
"mkdirp": "0.5.1",
|
"mkdirp": "0.5.1",
|
||||||
@@ -62,8 +65,8 @@
|
|||||||
"ts-loader": "2.3.1",
|
"ts-loader": "2.3.1",
|
||||||
"ts-node": "3.0.4",
|
"ts-node": "3.0.4",
|
||||||
"tslint": "5.9.1",
|
"tslint": "5.9.1",
|
||||||
"typescript": "2.5.2",
|
"typescript": "2.6.2",
|
||||||
"webpack": "2.4.1"
|
"webpack": "3.10.0"
|
||||||
},
|
},
|
||||||
"pre-commit": [
|
"pre-commit": [
|
||||||
"precommit-msg"
|
"precommit-msg"
|
||||||
@@ -83,6 +86,7 @@
|
|||||||
"lint:ts:test-serializer": "tslint --project ./packages/test-serializer/tsconfig.json",
|
"lint:ts:test-serializer": "tslint --project ./packages/test-serializer/tsconfig.json",
|
||||||
"lint:ts:uhk-usb": "tslint --project ./packages/uhk-usb/tsconfig.json",
|
"lint:ts:uhk-usb": "tslint --project ./packages/uhk-usb/tsconfig.json",
|
||||||
"lint:style": "stylelint \"packages/uhk-agent/src/**/*.scss\" \"packages/uhk-web/src/**/*.scss\" --syntax scss",
|
"lint:style": "stylelint \"packages/uhk-agent/src/**/*.scss\" \"packages/uhk-web/src/**/*.scss\" --syntax scss",
|
||||||
|
"prebuild": "check-node-version --package",
|
||||||
"build": "run-s build:common build:usb build:web build:electron",
|
"build": "run-s build:common build:usb build:web build:electron",
|
||||||
"build:web": "lerna exec --scope uhk-web npm run build",
|
"build:web": "lerna exec --scope uhk-web npm run build",
|
||||||
"build:electron": "cross-env AOT_BUILD=true run-s -sn build:electron:renderer build:electron:main",
|
"build:electron": "cross-env AOT_BUILD=true run-s -sn build:electron:renderer build:electron:main",
|
||||||
@@ -98,7 +102,9 @@
|
|||||||
"pack": "node ./scripts/release.js",
|
"pack": "node ./scripts/release.js",
|
||||||
"sprites": "node ./scripts/generate-svg-sprites",
|
"sprites": "node ./scripts/generate-svg-sprites",
|
||||||
"release": "node ./scripts/release.js",
|
"release": "node ./scripts/release.js",
|
||||||
"clean": "lerna exec rimraf ./node_modules ./dist"
|
"clean": "lerna exec rimraf ./node_modules ./dist && rimraf ./node_modules ./dist",
|
||||||
|
"predeploy-gh-pages": "run-s build:web",
|
||||||
|
"deploy-gh-pages": "gh-pages -d packages/uhk-web/dist"
|
||||||
},
|
},
|
||||||
"dependencies": {}
|
"dependencies": {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,25 @@ if (console.debug) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isSecondInstance = app.makeSingleInstance(function (commandLine, workingDirectory) {
|
||||||
|
// Someone tried to run a second instance, we should focus our window.
|
||||||
|
if (win) {
|
||||||
|
if (win.isMinimized()) {
|
||||||
|
win.restore();
|
||||||
|
}
|
||||||
|
win.focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isSecondInstance) {
|
||||||
|
app.quit();
|
||||||
|
}
|
||||||
|
|
||||||
function createWindow() {
|
function createWindow() {
|
||||||
|
if (isSecondInstance) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
logger.info('[Electron Main] Create new window.');
|
logger.info('[Electron Main] Create new window.');
|
||||||
let packagesDir;
|
let packagesDir;
|
||||||
if (isDev) {
|
if (isDev) {
|
||||||
@@ -133,13 +151,13 @@ app.on('ready', createWindow);
|
|||||||
|
|
||||||
// Quit when all windows are closed.
|
// Quit when all windows are closed.
|
||||||
app.on('window-all-closed', () => {
|
app.on('window-all-closed', () => {
|
||||||
app.quit();
|
|
||||||
});
|
|
||||||
|
|
||||||
app.on('will-quit', () => {
|
|
||||||
if (appUpdateService) {
|
if (appUpdateService) {
|
||||||
appUpdateService.saveFirtsRun();
|
appUpdateService.saveFirtsRun();
|
||||||
}
|
}
|
||||||
|
app.exit();
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on('will-quit', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
app.on('activate', () => {
|
app.on('activate', () => {
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ import { IpcEvents, LogService } from 'uhk-common';
|
|||||||
import { MainServiceBase } from './main-service-base';
|
import { MainServiceBase } from './main-service-base';
|
||||||
|
|
||||||
export class AppUpdateService extends MainServiceBase {
|
export class AppUpdateService extends MainServiceBase {
|
||||||
|
|
||||||
|
private sendAutoUpdateNotification = false;
|
||||||
|
|
||||||
constructor(protected logService: LogService,
|
constructor(protected logService: LogService,
|
||||||
protected win: Electron.BrowserWindow,
|
protected win: Electron.BrowserWindow,
|
||||||
private app: Electron.App) {
|
private app: Electron.App) {
|
||||||
@@ -24,16 +27,21 @@ export class AppUpdateService extends MainServiceBase {
|
|||||||
|
|
||||||
private initListeners() {
|
private initListeners() {
|
||||||
autoUpdater.on('checking-for-update', () => {
|
autoUpdater.on('checking-for-update', () => {
|
||||||
|
this.logService.debug('[AppUpdateService] checking for update');
|
||||||
this.sendIpcToWindow(IpcEvents.autoUpdater.checkingForUpdate);
|
this.sendIpcToWindow(IpcEvents.autoUpdater.checkingForUpdate);
|
||||||
});
|
});
|
||||||
|
|
||||||
autoUpdater.on('update-available', async (ev: any, info: UpdateInfo) => {
|
autoUpdater.on('update-available', async (ev: any, info: UpdateInfo) => {
|
||||||
|
this.logService.debug('[AppUpdateService] update available. Downloading started');
|
||||||
await autoUpdater.downloadUpdate();
|
await autoUpdater.downloadUpdate();
|
||||||
this.sendIpcToWindow(IpcEvents.autoUpdater.updateAvailable, info);
|
this.sendIpcToWindow(IpcEvents.autoUpdater.updateAvailable, info);
|
||||||
});
|
});
|
||||||
|
|
||||||
autoUpdater.on('update-not-available', (ev: any, info: UpdateInfo) => {
|
autoUpdater.on('update-not-available', (ev: any, info: UpdateInfo) => {
|
||||||
|
if (this.sendAutoUpdateNotification) {
|
||||||
|
this.logService.debug('[AppUpdateService] update not available');
|
||||||
this.sendIpcToWindow(IpcEvents.autoUpdater.updateNotAvailable, info);
|
this.sendIpcToWindow(IpcEvents.autoUpdater.updateNotAvailable, info);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
autoUpdater.on('error', (ev: any, err: string) => {
|
autoUpdater.on('error', (ev: any, err: string) => {
|
||||||
@@ -51,6 +59,7 @@ export class AppUpdateService extends MainServiceBase {
|
|||||||
});
|
});
|
||||||
|
|
||||||
autoUpdater.on('update-downloaded', (ev: any, info: UpdateInfo) => {
|
autoUpdater.on('update-downloaded', (ev: any, info: UpdateInfo) => {
|
||||||
|
this.logService.debug('[AppUpdateService] update downloaded');
|
||||||
this.sendIpcToWindow(IpcEvents.autoUpdater.autoUpdateDownloaded, info);
|
this.sendIpcToWindow(IpcEvents.autoUpdater.autoUpdateDownloaded, info);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -61,12 +70,15 @@ export class AppUpdateService extends MainServiceBase {
|
|||||||
|
|
||||||
ipcMain.on(IpcEvents.app.appStarted, () => {
|
ipcMain.on(IpcEvents.app.appStarted, () => {
|
||||||
if (this.checkForUpdateAtStartup()) {
|
if (this.checkForUpdateAtStartup()) {
|
||||||
|
this.sendAutoUpdateNotification = false;
|
||||||
|
this.logService.debug('[AppUpdateService] app started. Automatically check for update.');
|
||||||
this.checkForUpdate();
|
this.checkForUpdate();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on(IpcEvents.autoUpdater.checkForUpdate, () => {
|
ipcMain.on(IpcEvents.autoUpdater.checkForUpdate, () => {
|
||||||
this.logService.debug('[AppUpdateService] checkForUpdate request from renderer process');
|
this.logService.debug('[AppUpdateService] checkForUpdate request from renderer process');
|
||||||
|
this.sendAutoUpdateNotification = true;
|
||||||
this.checkForUpdate();
|
this.checkForUpdate();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -75,14 +87,22 @@ export class AppUpdateService extends MainServiceBase {
|
|||||||
if (isDev) {
|
if (isDev) {
|
||||||
const msg = '[AppUpdateService] Application update is not working in dev mode.';
|
const msg = '[AppUpdateService] Application update is not working in dev mode.';
|
||||||
this.logService.info(msg);
|
this.logService.info(msg);
|
||||||
|
|
||||||
|
if (this.sendAutoUpdateNotification) {
|
||||||
this.sendIpcToWindow(IpcEvents.autoUpdater.checkForUpdateNotAvailable, msg);
|
this.sendIpcToWindow(IpcEvents.autoUpdater.checkForUpdateNotAvailable, msg);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isFirstRun()) {
|
if (this.isFirstRun()) {
|
||||||
const msg = '[AppUpdateService] Application update is skipping at first run.';
|
const msg = '[AppUpdateService] Application update is skipping at first run.';
|
||||||
this.logService.info(msg);
|
this.logService.info(msg);
|
||||||
|
|
||||||
|
if (this.sendAutoUpdateNotification) {
|
||||||
this.sendIpcToWindow(IpcEvents.autoUpdater.checkForUpdateNotAvailable, msg);
|
this.sendIpcToWindow(IpcEvents.autoUpdater.checkForUpdateNotAvailable, msg);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,13 +22,14 @@ export class AppService extends MainServiceBase {
|
|||||||
|
|
||||||
private async handleAppStartInfo(event: Electron.Event) {
|
private async handleAppStartInfo(event: Electron.Event) {
|
||||||
this.logService.info('[AppService] getAppStartInfo');
|
this.logService.info('[AppService] getAppStartInfo');
|
||||||
|
const deviceConnectionState = this.uhkHidDeviceService.getDeviceConnectionState();
|
||||||
const response: AppStartInfo = {
|
const response: AppStartInfo = {
|
||||||
commandLineArgs: {
|
commandLineArgs: {
|
||||||
addons: this.options.addons || false
|
addons: this.options.addons || false
|
||||||
},
|
},
|
||||||
deviceConnected: this.uhkHidDeviceService.deviceConnected(),
|
deviceConnected: deviceConnectionState.connected,
|
||||||
hasPermission: this.uhkHidDeviceService.hasPermission()
|
hasPermission: deviceConnectionState.hasPermission,
|
||||||
|
bootloaderActive: deviceConnectionState.bootloaderActive
|
||||||
};
|
};
|
||||||
this.logService.info('[AppService] getAppStartInfo response:', response);
|
this.logService.info('[AppService] getAppStartInfo response:', response);
|
||||||
return event.sender.send(IpcEvents.app.getAppStartInfoReply, response);
|
return event.sender.send(IpcEvents.app.getAppStartInfoReply, response);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { ipcMain } from 'electron';
|
|||||||
import {
|
import {
|
||||||
ConfigurationReply,
|
ConfigurationReply,
|
||||||
DeviceConnectionState,
|
DeviceConnectionState,
|
||||||
|
FirmwareUpgradeIpcResponse,
|
||||||
getHardwareConfigFromDeviceResponse,
|
getHardwareConfigFromDeviceResponse,
|
||||||
HardwareModules,
|
HardwareModules,
|
||||||
IpcEvents,
|
IpcEvents,
|
||||||
@@ -10,7 +11,7 @@ import {
|
|||||||
mapObjectToUserConfigBinaryBuffer,
|
mapObjectToUserConfigBinaryBuffer,
|
||||||
SaveUserConfigurationData
|
SaveUserConfigurationData
|
||||||
} from 'uhk-common';
|
} from 'uhk-common';
|
||||||
import { snooze, UhkHidDevice, UhkOperations } from 'uhk-usb';
|
import { deviceConnectionStateComparer, snooze, UhkHidDevice, UhkOperations } from 'uhk-usb';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { Subscription } from 'rxjs/Subscription';
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
import { emptyDir } from 'fs-extra';
|
import { emptyDir } from 'fs-extra';
|
||||||
@@ -71,6 +72,15 @@ export class DeviceService {
|
|||||||
|
|
||||||
ipcMain.on(IpcEvents.device.startConnectionPoller, this.pollUhkDevice.bind(this));
|
ipcMain.on(IpcEvents.device.startConnectionPoller, this.pollUhkDevice.bind(this));
|
||||||
|
|
||||||
|
ipcMain.on(IpcEvents.device.recoveryDevice, (...args: any[]) => {
|
||||||
|
this.queueManager.add({
|
||||||
|
method: this.recoveryDevice,
|
||||||
|
bind: this,
|
||||||
|
params: args,
|
||||||
|
asynchronous: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
logService.debug('[DeviceService] init success');
|
logService.debug('[DeviceService] init success');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,10 +94,7 @@ export class DeviceService {
|
|||||||
try {
|
try {
|
||||||
await this.device.waitUntilKeyboardBusy();
|
await this.device.waitUntilKeyboardBusy();
|
||||||
const result = await this.operations.loadConfigurations();
|
const result = await this.operations.loadConfigurations();
|
||||||
const modules: HardwareModules = {
|
const modules: HardwareModules = await this.getHardwareModules(false);
|
||||||
leftModuleInfo: await this.operations.getLeftModuleVersionInfo(),
|
|
||||||
rightModuleInfo: await this.operations.getRightModuleVersionInfo()
|
|
||||||
};
|
|
||||||
|
|
||||||
const hardwareConfig = getHardwareConfigFromDeviceResponse(result.hardwareConfiguration);
|
const hardwareConfig = getHardwareConfigFromDeviceResponse(result.hardwareConfiguration);
|
||||||
const uniqueId = hardwareConfig.uniqueId;
|
const uniqueId = hardwareConfig.uniqueId;
|
||||||
@@ -110,16 +117,36 @@ export class DeviceService {
|
|||||||
event.sender.send(IpcEvents.device.loadConfigurationReply, JSON.stringify(response));
|
event.sender.send(IpcEvents.device.loadConfigurationReply, JSON.stringify(response));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async getHardwareModules(catchError: boolean): Promise<HardwareModules> {
|
||||||
|
try {
|
||||||
|
await this.device.waitUntilKeyboardBusy();
|
||||||
|
|
||||||
|
return {
|
||||||
|
leftModuleInfo: await this.operations.getLeftModuleVersionInfo(),
|
||||||
|
rightModuleInfo: await this.operations.getRightModuleVersionInfo()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
if (!catchError) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logService.error('[DeviceService] Read hardware modules information failed', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public close(): void {
|
public close(): void {
|
||||||
this.stopPollTimer();
|
this.stopPollTimer();
|
||||||
this.logService.info('[DeviceService] Device connection checker stopped.');
|
this.logService.info('[DeviceService] Device connection checker stopped.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateFirmware(event: Electron.Event, args?: Array<string>): Promise<void> {
|
public async updateFirmware(event: Electron.Event, args?: Array<string>): Promise<void> {
|
||||||
const response = new IpcResponse();
|
const response = new FirmwareUpgradeIpcResponse();
|
||||||
|
|
||||||
let firmwarePathData: TmpFirmware;
|
let firmwarePathData: TmpFirmware;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
this.device.resetDeviceCache();
|
||||||
this.stopPollTimer();
|
this.stopPollTimer();
|
||||||
|
|
||||||
if (args && args.length > 0) {
|
if (args && args.length > 0) {
|
||||||
@@ -133,10 +160,12 @@ export class DeviceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
response.success = true;
|
response.success = true;
|
||||||
|
response.modules = await this.getHardwareModules(false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const err = {message: error.message, stack: error.stack};
|
const err = {message: error.message, stack: error.stack};
|
||||||
this.logService.error('[DeviceService] updateFirmware error', err);
|
this.logService.error('[DeviceService] updateFirmware error', err);
|
||||||
|
|
||||||
|
response.modules = await this.getHardwareModules(true);
|
||||||
response.error = err;
|
response.error = err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,6 +173,35 @@ export class DeviceService {
|
|||||||
await emptyDir(firmwarePathData.tmpDirectory.name);
|
await emptyDir(firmwarePathData.tmpDirectory.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await snooze(500);
|
||||||
|
|
||||||
|
this.pollUhkDevice();
|
||||||
|
|
||||||
|
event.sender.send(IpcEvents.device.updateFirmwareReply, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async recoveryDevice(event: Electron.Event): Promise<void> {
|
||||||
|
const response = new FirmwareUpgradeIpcResponse();
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.stopPollTimer();
|
||||||
|
|
||||||
|
await this.operations.updateRightFirmware();
|
||||||
|
|
||||||
|
await snooze(500);
|
||||||
|
|
||||||
|
this.pollUhkDevice();
|
||||||
|
|
||||||
|
response.modules = await this.getHardwareModules(false);
|
||||||
|
response.success = true;
|
||||||
|
} catch (error) {
|
||||||
|
const err = {message: error.message, stack: error.stack};
|
||||||
|
this.logService.error('[DeviceService] updateFirmware error', err);
|
||||||
|
|
||||||
|
response.modules = await this.getHardwareModules(true);
|
||||||
|
response.error = err;
|
||||||
|
}
|
||||||
|
|
||||||
await snooze(500);
|
await snooze(500);
|
||||||
event.sender.send(IpcEvents.device.updateFirmwareReply, response);
|
event.sender.send(IpcEvents.device.updateFirmwareReply, response);
|
||||||
}
|
}
|
||||||
@@ -161,16 +219,11 @@ export class DeviceService {
|
|||||||
|
|
||||||
this.pollTimer$ = Observable.interval(1000)
|
this.pollTimer$ = Observable.interval(1000)
|
||||||
.startWith(0)
|
.startWith(0)
|
||||||
.map(() => this.device.deviceConnected())
|
.map(() => this.device.getDeviceConnectionState())
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged<DeviceConnectionState>(deviceConnectionStateComparer)
|
||||||
.do((connected: boolean) => {
|
.do((state: DeviceConnectionState) => {
|
||||||
const response: DeviceConnectionState = {
|
this.win.webContents.send(IpcEvents.device.deviceConnectionStateChanged, state);
|
||||||
connected,
|
this.logService.info('[DeviceService] Device connection state changed to:', state);
|
||||||
hasPermission: this.device.hasPermission()
|
|
||||||
};
|
|
||||||
|
|
||||||
this.win.webContents.send(IpcEvents.device.deviceConnectionStateChanged, response);
|
|
||||||
this.logService.info('[DeviceService] Device connection state changed to:', response);
|
|
||||||
})
|
})
|
||||||
.subscribe();
|
.subscribe();
|
||||||
}
|
}
|
||||||
|
|||||||
170
packages/uhk-common/package-lock.json
generated
170
packages/uhk-common/package-lock.json
generated
@@ -18,11 +18,11 @@
|
|||||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
|
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
|
||||||
},
|
},
|
||||||
"ansi-styles": {
|
"ansi-styles": {
|
||||||
"version": "3.2.0",
|
"version": "3.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||||
"integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
|
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"color-convert": "1.9.0"
|
"color-convert": "1.9.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"arrify": {
|
"arrify": {
|
||||||
@@ -36,9 +36,9 @@
|
|||||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
||||||
},
|
},
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.8",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
"integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
|
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"balanced-match": "1.0.0",
|
"balanced-match": "1.0.0",
|
||||||
"concat-map": "0.0.1"
|
"concat-map": "0.0.1"
|
||||||
@@ -55,13 +55,13 @@
|
|||||||
"integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0="
|
"integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0="
|
||||||
},
|
},
|
||||||
"chalk": {
|
"chalk": {
|
||||||
"version": "2.1.0",
|
"version": "2.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz",
|
||||||
"integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==",
|
"integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"ansi-styles": "3.2.0",
|
"ansi-styles": "3.2.1",
|
||||||
"escape-string-regexp": "1.0.5",
|
"escape-string-regexp": "1.0.5",
|
||||||
"supports-color": "4.4.0"
|
"supports-color": "5.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"cliui": {
|
"cliui": {
|
||||||
@@ -100,9 +100,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"color-convert": {
|
"color-convert": {
|
||||||
"version": "1.9.0",
|
"version": "1.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz",
|
||||||
"integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=",
|
"integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"color-name": "1.1.3"
|
"color-name": "1.1.3"
|
||||||
}
|
}
|
||||||
@@ -122,15 +122,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
|
||||||
"integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
|
"integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"lru-cache": "4.1.1",
|
"lru-cache": "4.1.2",
|
||||||
"shebang-command": "1.2.0",
|
"shebang-command": "1.2.0",
|
||||||
"which": "1.3.0"
|
"which": "1.3.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lru-cache": {
|
"lru-cache": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.2.tgz",
|
||||||
"integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==",
|
"integrity": "sha512-wgeVXhrDwAWnIF/yZARsFnMBtdFXOg1b8RIrhilp+0iDYN4mdQcNZElDZ0e4B64BhaxeQ5zN7PMyvu7we1kPeQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"pseudomap": "1.0.2",
|
"pseudomap": "1.0.2",
|
||||||
"yallist": "2.1.2"
|
"yallist": "2.1.2"
|
||||||
@@ -144,9 +144,9 @@
|
|||||||
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
|
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
|
||||||
},
|
},
|
||||||
"diff": {
|
"diff": {
|
||||||
"version": "3.4.0",
|
"version": "3.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/diff/-/diff-3.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
|
||||||
"integrity": "sha512-QpVuMTEoJMF7cKzi6bvWhRulU1fZqZnvyVQgNhPaxxuTYwyjn/j1v9falseQ/uXWwPnO56RBfwtg4h/EQXmucA=="
|
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA=="
|
||||||
},
|
},
|
||||||
"error-ex": {
|
"error-ex": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.1",
|
||||||
@@ -271,9 +271,9 @@
|
|||||||
"integrity": "sha1-3i1mE20ALhErpw8/EMMc98NQsto="
|
"integrity": "sha1-3i1mE20ALhErpw8/EMMc98NQsto="
|
||||||
},
|
},
|
||||||
"has-flag": {
|
"has-flag": {
|
||||||
"version": "2.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||||
"integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE="
|
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
|
||||||
},
|
},
|
||||||
"homedir-polyfill": {
|
"homedir-polyfill": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
@@ -284,9 +284,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"hosted-git-info": {
|
"hosted-git-info": {
|
||||||
"version": "2.5.0",
|
"version": "2.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz",
|
||||||
"integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg=="
|
"integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw=="
|
||||||
},
|
},
|
||||||
"inflight": {
|
"inflight": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
@@ -382,7 +382,7 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"jasmine": "2.8.0",
|
"jasmine": "2.8.0",
|
||||||
"ts-node": "3.3.0",
|
"ts-node": "3.3.0",
|
||||||
"typescript": "2.5.3",
|
"typescript": "2.8.1",
|
||||||
"yargs": "8.0.2"
|
"yargs": "8.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -432,29 +432,29 @@
|
|||||||
"integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI="
|
"integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI="
|
||||||
},
|
},
|
||||||
"make-error": {
|
"make-error": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.4.tgz",
|
||||||
"integrity": "sha1-Uq06M5zPEM5itAQLcI/nByRLi5Y="
|
"integrity": "sha512-0Dab5btKVPhibSalc9QGXb559ED7G7iLjFXBaj9Wq8O3vorueR5K5jaE3hkG6ZQINyhA/JgG6Qk4qdFQjsYV6g=="
|
||||||
},
|
},
|
||||||
"mem": {
|
"mem": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz",
|
||||||
"integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=",
|
"integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"mimic-fn": "1.1.0"
|
"mimic-fn": "1.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mimic-fn": {
|
"mimic-fn": {
|
||||||
"version": "1.1.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
|
||||||
"integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg="
|
"integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="
|
||||||
},
|
},
|
||||||
"minimatch": {
|
"minimatch": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"brace-expansion": "1.1.8"
|
"brace-expansion": "1.1.11"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minimist": {
|
"minimist": {
|
||||||
@@ -472,10 +472,10 @@
|
|||||||
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
|
||||||
"integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
|
"integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"hosted-git-info": "2.5.0",
|
"hosted-git-info": "2.6.0",
|
||||||
"is-builtin-module": "1.0.0",
|
"is-builtin-module": "1.0.0",
|
||||||
"semver": "5.4.1",
|
"semver": "5.5.0",
|
||||||
"validate-npm-package-license": "3.0.1"
|
"validate-npm-package-license": "3.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"npm-run-path": {
|
"npm-run-path": {
|
||||||
@@ -1942,18 +1942,26 @@
|
|||||||
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
|
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
|
||||||
},
|
},
|
||||||
"p-limit": {
|
"p-limit": {
|
||||||
"version": "1.1.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz",
|
||||||
"integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw="
|
"integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==",
|
||||||
|
"requires": {
|
||||||
|
"p-try": "1.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"p-locate": {
|
"p-locate": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
|
||||||
"integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
|
"integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"p-limit": "1.1.0"
|
"p-limit": "1.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"p-try": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M="
|
||||||
|
},
|
||||||
"parse-json": {
|
"parse-json": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
|
||||||
@@ -2030,9 +2038,9 @@
|
|||||||
"integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE="
|
"integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE="
|
||||||
},
|
},
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "5.4.1",
|
"version": "5.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
|
||||||
"integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg=="
|
"integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA=="
|
||||||
},
|
},
|
||||||
"set-blocking": {
|
"set-blocking": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
@@ -2076,22 +2084,32 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"spdx-correct": {
|
"spdx-correct": {
|
||||||
"version": "1.0.2",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz",
|
||||||
"integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=",
|
"integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"spdx-license-ids": "1.2.2"
|
"spdx-expression-parse": "3.0.0",
|
||||||
|
"spdx-license-ids": "3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"spdx-exceptions": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg=="
|
||||||
|
},
|
||||||
"spdx-expression-parse": {
|
"spdx-expression-parse": {
|
||||||
"version": "1.0.4",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
|
||||||
"integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw="
|
"integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
|
||||||
|
"requires": {
|
||||||
|
"spdx-exceptions": "2.1.0",
|
||||||
|
"spdx-license-ids": "3.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"spdx-license-ids": {
|
"spdx-license-ids": {
|
||||||
"version": "1.2.2",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz",
|
||||||
"integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc="
|
"integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA=="
|
||||||
},
|
},
|
||||||
"string-width": {
|
"string-width": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
@@ -2146,11 +2164,11 @@
|
|||||||
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
|
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
|
||||||
},
|
},
|
||||||
"supports-color": {
|
"supports-color": {
|
||||||
"version": "4.4.0",
|
"version": "5.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz",
|
||||||
"integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==",
|
"integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"has-flag": "2.0.0"
|
"has-flag": "3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ts-node": {
|
"ts-node": {
|
||||||
@@ -2159,14 +2177,14 @@
|
|||||||
"integrity": "sha1-wTxqMCTjC+EYDdUwOPwgkonUv2k=",
|
"integrity": "sha1-wTxqMCTjC+EYDdUwOPwgkonUv2k=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"arrify": "1.0.1",
|
"arrify": "1.0.1",
|
||||||
"chalk": "2.1.0",
|
"chalk": "2.3.2",
|
||||||
"diff": "3.4.0",
|
"diff": "3.5.0",
|
||||||
"make-error": "1.3.0",
|
"make-error": "1.3.4",
|
||||||
"minimist": "1.2.0",
|
"minimist": "1.2.0",
|
||||||
"mkdirp": "0.5.1",
|
"mkdirp": "0.5.1",
|
||||||
"source-map-support": "0.4.18",
|
"source-map-support": "0.4.18",
|
||||||
"tsconfig": "6.0.0",
|
"tsconfig": "6.0.0",
|
||||||
"v8flags": "3.0.1",
|
"v8flags": "3.0.2",
|
||||||
"yn": "2.0.0"
|
"yn": "2.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -2202,9 +2220,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "2.5.3",
|
"version": "2.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.8.1.tgz",
|
||||||
"integrity": "sha512-ptLSQs2S4QuS6/OD1eAKG+S5G8QQtrU5RT32JULdZQtM1L3WTi34Wsu48Yndzi8xsObRAB9RPt/KhA9wlpEF6w=="
|
"integrity": "sha512-Ao/f6d/4EPLq0YwzsQz8iXflezpTkQzqAyenTiw4kCUGr1uPiFLC3+fZ+gMZz6eeI/qdRUqvC+HxIJzUAzEFdg=="
|
||||||
},
|
},
|
||||||
"underscore": {
|
"underscore": {
|
||||||
"version": "1.6.0",
|
"version": "1.6.0",
|
||||||
@@ -2212,20 +2230,20 @@
|
|||||||
"integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag="
|
"integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag="
|
||||||
},
|
},
|
||||||
"v8flags": {
|
"v8flags": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.0.2.tgz",
|
||||||
"integrity": "sha1-3Oj8N5wX2fLJ6e142JzgAFKxt2s=",
|
"integrity": "sha512-6sgSKoFw1UpUPd3cFdF7QGnrH6tDeBgW1F3v9gy8gLY0mlbiBXq8soy8aQpY6xeeCjH5K+JvC62Acp7gtl7wWA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"homedir-polyfill": "1.0.1"
|
"homedir-polyfill": "1.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"validate-npm-package-license": {
|
"validate-npm-package-license": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz",
|
||||||
"integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=",
|
"integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"spdx-correct": "1.0.2",
|
"spdx-correct": "3.0.0",
|
||||||
"spdx-expression-parse": "1.0.4"
|
"spdx-expression-parse": "3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"walkdir": {
|
"walkdir": {
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "Common Library contains the common code for uhk-agent (electron-main) and web (electron-renderer) modules",
|
"description": "Common Library contains the common code for uhk-agent (electron-main) and web (electron-renderer) modules",
|
||||||
"main": "dist/index.js",
|
"main": "dist/src/index.js",
|
||||||
|
"types": "dist/src/index.d.ts",
|
||||||
"author": "Ultimate Gadget Laboratories",
|
"author": "Ultimate Gadget Laboratories",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ export class HardwareConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fromBinary(buffer: UhkBuffer): HardwareConfiguration {
|
fromBinary(buffer: UhkBuffer): HardwareConfiguration {
|
||||||
|
try {
|
||||||
this.signature = buffer.readString();
|
this.signature = buffer.readString();
|
||||||
this.majorVersion = buffer.readUInt8();
|
this.majorVersion = buffer.readUInt8();
|
||||||
this.minorVersion = buffer.readUInt8();
|
this.minorVersion = buffer.readUInt8();
|
||||||
@@ -51,6 +52,9 @@ export class HardwareConfiguration {
|
|||||||
this.isVendorModeOn = buffer.readBoolean();
|
this.isVendorModeOn = buffer.readBoolean();
|
||||||
this.isIso = buffer.readBoolean();
|
this.isIso = buffer.readBoolean();
|
||||||
return this;
|
return this;
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error('Please power cycle your keyboard (Invalid hardware configuration: Index out of bounds)');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toJsonObject(): any {
|
toJsonObject(): any {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export enum KeystrokeActionFlag {
|
|||||||
|
|
||||||
const KEYSTROKE_ACTION_FLAG_LENGTH = 3;
|
const KEYSTROKE_ACTION_FLAG_LENGTH = 3;
|
||||||
|
|
||||||
interface JsonObjectKeystrokeAction {
|
export interface JsonObjectKeystrokeAction {
|
||||||
keyActionType: string;
|
keyActionType: string;
|
||||||
scancode?: number;
|
scancode?: number;
|
||||||
modifierMask?: number;
|
modifierMask?: number;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { assertEnum, assertUInt8 } from '../../assert';
|
import { assertEnum, assertUInt8, assertUInt16 } from '../../assert';
|
||||||
import { UhkBuffer } from '../../uhk-buffer';
|
import { UhkBuffer } from '../../uhk-buffer';
|
||||||
import { KeyModifiers } from '../key-modifiers';
|
import { KeyModifiers } from '../key-modifiers';
|
||||||
import { MacroAction, MacroActionId, MacroKeySubAction, macroActionType } from './macro-action';
|
import { MacroAction, MacroActionId, MacroKeySubAction, macroActionType } from './macro-action';
|
||||||
import { KeystrokeType } from '../key-action';
|
import { KeystrokeType } from '../key-action';
|
||||||
|
|
||||||
interface JsObjectKeyMacroAction {
|
export interface JsObjectKeyMacroAction {
|
||||||
macroActionType: string;
|
macroActionType: string;
|
||||||
action: string;
|
action: string;
|
||||||
type?: string;
|
type?: string;
|
||||||
@@ -20,12 +20,24 @@ export class KeyMacroAction extends MacroAction {
|
|||||||
@assertEnum(KeystrokeType)
|
@assertEnum(KeystrokeType)
|
||||||
type: KeystrokeType;
|
type: KeystrokeType;
|
||||||
|
|
||||||
@assertUInt8
|
|
||||||
scancode: number;
|
|
||||||
|
|
||||||
@assertUInt8
|
@assertUInt8
|
||||||
modifierMask: number;
|
modifierMask: number;
|
||||||
|
|
||||||
|
@assertUInt16
|
||||||
|
private _scancode: number;
|
||||||
|
|
||||||
|
set scancode(scancode: number) {
|
||||||
|
this._scancode = scancode;
|
||||||
|
if (this.type !== KeystrokeType.shortMedia && this.type !== KeystrokeType.longMedia) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.type = scancode < 256 ? KeystrokeType.shortMedia : KeystrokeType.longMedia;
|
||||||
|
}
|
||||||
|
|
||||||
|
get scancode() {
|
||||||
|
return this._scancode;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(other?: KeyMacroAction) {
|
constructor(other?: KeyMacroAction) {
|
||||||
super();
|
super();
|
||||||
if (!other) {
|
if (!other) {
|
||||||
@@ -33,7 +45,7 @@ export class KeyMacroAction extends MacroAction {
|
|||||||
}
|
}
|
||||||
this.action = other.action;
|
this.action = other.action;
|
||||||
this.type = other.type;
|
this.type = other.type;
|
||||||
this.scancode = other.scancode;
|
this._scancode = other._scancode;
|
||||||
this.modifierMask = other.modifierMask;
|
this.modifierMask = other.modifierMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +57,7 @@ export class KeyMacroAction extends MacroAction {
|
|||||||
} else {
|
} else {
|
||||||
this.type = KeystrokeType[jsObject.type];
|
this.type = KeystrokeType[jsObject.type];
|
||||||
}
|
}
|
||||||
this.scancode = jsObject.scancode;
|
this._scancode = jsObject.scancode;
|
||||||
this.modifierMask = jsObject.modifierMask;
|
this.modifierMask = jsObject.modifierMask;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -58,7 +70,7 @@ export class KeyMacroAction extends MacroAction {
|
|||||||
this.type = keyMacroType & 0b11;
|
this.type = keyMacroType & 0b11;
|
||||||
keyMacroType >>= 2;
|
keyMacroType >>= 2;
|
||||||
if (keyMacroType & 0b10) {
|
if (keyMacroType & 0b10) {
|
||||||
this.scancode = buffer.readUInt8();
|
this._scancode = this.type === KeystrokeType.longMedia ? buffer.readUInt16() : buffer.readUInt8();
|
||||||
}
|
}
|
||||||
if (keyMacroType & 0b01) {
|
if (keyMacroType & 0b01) {
|
||||||
this.modifierMask = buffer.readUInt8();
|
this.modifierMask = buffer.readUInt8();
|
||||||
@@ -78,7 +90,7 @@ export class KeyMacroAction extends MacroAction {
|
|||||||
} else {
|
} else {
|
||||||
jsObject.type = KeystrokeType[this.type];
|
jsObject.type = KeystrokeType[this.type];
|
||||||
}
|
}
|
||||||
jsObject.scancode = this.scancode;
|
jsObject.scancode = this._scancode;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.hasModifiers()) {
|
if (this.hasModifiers()) {
|
||||||
@@ -98,15 +110,19 @@ export class KeyMacroAction extends MacroAction {
|
|||||||
|
|
||||||
buffer.writeUInt8(keyMacroType);
|
buffer.writeUInt8(keyMacroType);
|
||||||
if (this.hasScancode()) {
|
if (this.hasScancode()) {
|
||||||
|
if (this.type === KeystrokeType.longMedia) {
|
||||||
|
buffer.writeUInt16(this.scancode);
|
||||||
|
} else {
|
||||||
buffer.writeUInt8(this.scancode);
|
buffer.writeUInt8(this.scancode);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (this.hasModifiers()) {
|
if (this.hasModifiers()) {
|
||||||
buffer.writeUInt8(this.modifierMask);
|
buffer.writeUInt8(this.modifierMask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toString(): string {
|
toString(): string {
|
||||||
return `<KeyMacroAction action="${this.action}" scancode="${this.scancode}" modifierMask="${this.modifierMask}">`;
|
return `<KeyMacroAction action="${this.action}" scancode="${this._scancode}" modifierMask="${this.modifierMask}">`;
|
||||||
}
|
}
|
||||||
|
|
||||||
isModifierActive(modifier: KeyModifiers): boolean {
|
isModifierActive(modifier: KeyModifiers): boolean {
|
||||||
@@ -114,7 +130,7 @@ export class KeyMacroAction extends MacroAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hasScancode(): boolean {
|
hasScancode(): boolean {
|
||||||
return !!this.scancode;
|
return !!this._scancode;
|
||||||
}
|
}
|
||||||
|
|
||||||
hasModifiers(): boolean {
|
hasModifiers(): boolean {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export enum MouseButtons {
|
|||||||
Right = 1 << 2
|
Right = 1 << 2
|
||||||
}
|
}
|
||||||
|
|
||||||
interface JsObjectMouseButtonMacroAction {
|
export interface JsObjectMouseButtonMacroAction {
|
||||||
macroActionType: string;
|
macroActionType: string;
|
||||||
action: string;
|
action: string;
|
||||||
mouseButtonsMask?: number;
|
mouseButtonsMask?: number;
|
||||||
|
|||||||
@@ -4,4 +4,5 @@ export interface AppStartInfo {
|
|||||||
commandLineArgs: CommandLineArgs;
|
commandLineArgs: CommandLineArgs;
|
||||||
deviceConnected: boolean;
|
deviceConnected: boolean;
|
||||||
hasPermission: boolean;
|
hasPermission: boolean;
|
||||||
|
bootloaderActive: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
export interface DeviceConnectionState {
|
export interface DeviceConnectionState {
|
||||||
connected: boolean;
|
connected: boolean;
|
||||||
hasPermission: boolean;
|
hasPermission: boolean;
|
||||||
|
bootloaderActive: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
|
import { HardwareModules } from './hardware-modules';
|
||||||
|
|
||||||
export class IpcResponse {
|
export class IpcResponse {
|
||||||
success: boolean;
|
success: boolean;
|
||||||
error?: { message: string };
|
error?: { message: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class FirmwareUpgradeIpcResponse extends IpcResponse {
|
||||||
|
modules?: HardwareModules;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
export namespace Constants {
|
export namespace Constants {
|
||||||
export const AGENT_GITHUB_URL = 'https://github.com/UltimateHackingKeyboard/agent';
|
export const AGENT_GITHUB_URL = 'https://github.com/UltimateHackingKeyboard/agent';
|
||||||
|
export const FIRMWARE_GITHUB_ISSUE_URL = 'https://github.com/UltimateHackingKeyboard/agent/issues/567';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
import { HardwareConfiguration, UhkBuffer, UserConfiguration } from '../../index';
|
import { HardwareConfiguration, UhkBuffer, UserConfiguration } from '../config-serializer';
|
||||||
|
|
||||||
export const getHardwareConfigFromDeviceResponse = (json: string): HardwareConfiguration => {
|
export const getHardwareConfigFromDeviceResponse = (json: string): HardwareConfiguration => {
|
||||||
const data = JSON.parse(json);
|
const data = JSON.parse(json);
|
||||||
const hardwareConfig = new HardwareConfiguration();
|
const hardwareConfig = new HardwareConfiguration();
|
||||||
hardwareConfig.fromBinary(UhkBuffer.fromArray(data));
|
hardwareConfig.fromBinary(UhkBuffer.fromArray(data));
|
||||||
|
|
||||||
if (hardwareConfig.uniqueId > 0) {
|
if (hardwareConfig.signature === 'FTY') {
|
||||||
return hardwareConfig;
|
throw Error('The device is in factory reset mode. Power-cycle the device to use it with Agent!');
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
if (hardwareConfig.signature !== 'UHK') {
|
||||||
|
throw Error('Please power cycle your keyboard (Invalid hardware configuration: Invalid signature)');
|
||||||
|
}
|
||||||
|
|
||||||
|
return hardwareConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getUserConfigFromDeviceResponse = (json: string): UserConfiguration => {
|
export const getUserConfigFromDeviceResponse = (json: string): UserConfiguration => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
class App {
|
export class App {
|
||||||
public static readonly appStarted = 'app-started';
|
public static readonly appStarted = 'app-started';
|
||||||
public static readonly getAppStartInfo = 'app-get-start-info';
|
public static readonly getAppStartInfo = 'app-get-start-info';
|
||||||
public static readonly getAppStartInfoReply = 'app-get-start-info-reply';
|
public static readonly getAppStartInfoReply = 'app-get-start-info-reply';
|
||||||
@@ -6,7 +6,7 @@ class App {
|
|||||||
public static readonly openUrl = 'open-url';
|
public static readonly openUrl = 'open-url';
|
||||||
}
|
}
|
||||||
|
|
||||||
class AutoUpdate {
|
export class AutoUpdate {
|
||||||
public static readonly checkingForUpdate = 'checking-for-update';
|
public static readonly checkingForUpdate = 'checking-for-update';
|
||||||
public static readonly updateAvailable = 'update-available';
|
public static readonly updateAvailable = 'update-available';
|
||||||
public static readonly updateNotAvailable = 'update-not-available';
|
public static readonly updateNotAvailable = 'update-not-available';
|
||||||
@@ -18,7 +18,7 @@ class AutoUpdate {
|
|||||||
public static readonly checkForUpdateNotAvailable = 'check-for-update-not-available';
|
public static readonly checkForUpdateNotAvailable = 'check-for-update-not-available';
|
||||||
}
|
}
|
||||||
|
|
||||||
class Device {
|
export class Device {
|
||||||
public static readonly setPrivilegeOnLinux = 'set-privilege-on-linux';
|
public static readonly setPrivilegeOnLinux = 'set-privilege-on-linux';
|
||||||
public static readonly setPrivilegeOnLinuxReply = 'set-privilege-on-linux-reply';
|
public static readonly setPrivilegeOnLinuxReply = 'set-privilege-on-linux-reply';
|
||||||
public static readonly deviceConnectionStateChanged = 'device-connection-state-changed';
|
public static readonly deviceConnectionStateChanged = 'device-connection-state-changed';
|
||||||
@@ -29,6 +29,7 @@ class Device {
|
|||||||
public static readonly updateFirmware = 'device-update-firmware';
|
public static readonly updateFirmware = 'device-update-firmware';
|
||||||
public static readonly updateFirmwareReply = 'device-update-firmware-reply';
|
public static readonly updateFirmwareReply = 'device-update-firmware-reply';
|
||||||
public static readonly startConnectionPoller = 'device-start-connection-poller';
|
public static readonly startConnectionPoller = 'device-start-connection-poller';
|
||||||
|
public static readonly recoveryDevice = 'device-recovery';
|
||||||
}
|
}
|
||||||
|
|
||||||
export class IpcEvents {
|
export class IpcEvents {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"outDir": "./dist",
|
"outDir": "./dist",
|
||||||
"declaration": false,
|
"declaration": true,
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
|
|||||||
5
packages/uhk-usb/package-lock.json
generated
5
packages/uhk-usb/package-lock.json
generated
@@ -144,6 +144,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||||
},
|
},
|
||||||
|
"lodash-es": {
|
||||||
|
"version": "4.17.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.10.tgz",
|
||||||
|
"integrity": "sha512-iesFYPmxYYGTcmQK0sL8bX3TGHyM6b2qREaB4kamHfQyfPJP0xgoGxp19nsH16nsfquLdiyKyX3mQkfiSGV8Rg=="
|
||||||
|
},
|
||||||
"mimic-response": {
|
"mimic-response": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.0.tgz",
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"@types/node": "8.0.28"
|
"@types/node": "8.0.28"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"lodash-es": "^4.17.10",
|
||||||
"node-hid": "0.5.7",
|
"node-hid": "0.5.7",
|
||||||
"uhk-common": "1.0.0"
|
"uhk-common": "1.0.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
export namespace Constants {
|
export namespace Constants {
|
||||||
export const VENDOR_ID = 0x1D50;
|
export const VENDOR_ID = 0x1D50;
|
||||||
export const PRODUCT_ID = 0x6122;
|
export const PRODUCT_ID = 0x6122;
|
||||||
|
export const BOOTLOADER_ID = 0x6120;
|
||||||
export const MAX_PAYLOAD_SIZE = 64;
|
export const MAX_PAYLOAD_SIZE = 64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
import { isEqual } from 'lodash';
|
||||||
import { Device, devices, HID } from 'node-hid';
|
import { Device, devices, HID } from 'node-hid';
|
||||||
import { CommandLineArgs, LogService } from 'uhk-common';
|
import { CommandLineArgs, DeviceConnectionState, LogService } from 'uhk-common';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ConfigBufferId,
|
ConfigBufferId,
|
||||||
@@ -12,7 +13,7 @@ import {
|
|||||||
ModuleSlotToId,
|
ModuleSlotToId,
|
||||||
UsbCommand
|
UsbCommand
|
||||||
} from './constants';
|
} from './constants';
|
||||||
import { bufferToString, getTransferData, retry, snooze } from './util';
|
import { bufferToString, getTransferData, isUhkDevice, retry, snooze } from './util';
|
||||||
|
|
||||||
export const BOOTLOADER_TIMEOUT_MS = 5000;
|
export const BOOTLOADER_TIMEOUT_MS = 5000;
|
||||||
|
|
||||||
@@ -24,6 +25,7 @@ export class UhkHidDevice {
|
|||||||
* Internal variable that represent the USB UHK device
|
* Internal variable that represent the USB UHK device
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
private _prevDevices = {};
|
||||||
private _device: HID;
|
private _device: HID;
|
||||||
private _hasPermission = false;
|
private _hasPermission = false;
|
||||||
|
|
||||||
@@ -48,12 +50,16 @@ export class UhkHidDevice {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.deviceConnected()) {
|
const dev = devices().find((x: Device) => isUhkDevice(x) || x.productId === Constants.BOOTLOADER_ID);
|
||||||
|
|
||||||
|
if (!dev) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._hasPermission = this.getDevice() !== null;
|
const device = new HID(dev.path);
|
||||||
this.close();
|
device.close();
|
||||||
|
|
||||||
|
this._hasPermission = true;
|
||||||
|
|
||||||
return this._hasPermission;
|
return this._hasPermission;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -67,15 +73,24 @@ export class UhkHidDevice {
|
|||||||
* Return with true is an UHK Device is connected to the computer.
|
* Return with true is an UHK Device is connected to the computer.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
public deviceConnected(): boolean {
|
public getDeviceConnectionState(): DeviceConnectionState {
|
||||||
const connected = devices().some((dev: Device) => dev.vendorId === Constants.VENDOR_ID &&
|
const devs = devices();
|
||||||
dev.productId === Constants.PRODUCT_ID);
|
const result: DeviceConnectionState = {
|
||||||
|
bootloaderActive: false,
|
||||||
|
connected: false,
|
||||||
|
hasPermission: this.hasPermission()
|
||||||
|
};
|
||||||
|
|
||||||
if (!connected) {
|
for (const dev of devs) {
|
||||||
this._hasPermission = false;
|
if (isUhkDevice(dev)) {
|
||||||
|
result.connected = true;
|
||||||
|
} else if (dev.vendorId === Constants.VENDOR_ID &&
|
||||||
|
dev.productId === Constants.BOOTLOADER_ID) {
|
||||||
|
result.bootloaderActive = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return connected;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -142,6 +157,10 @@ export class UhkHidDevice {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public resetDeviceCache(): void {
|
||||||
|
this._prevDevices = {};
|
||||||
|
}
|
||||||
|
|
||||||
async reenumerate(enumerationMode: EnumerationModes): Promise<void> {
|
async reenumerate(enumerationMode: EnumerationModes): Promise<void> {
|
||||||
const reenumMode = EnumerationModes[enumerationMode].toString();
|
const reenumMode = EnumerationModes[enumerationMode].toString();
|
||||||
this.logService.debug(`[UhkHidDevice] Start reenumeration, mode: ${reenumMode}`);
|
this.logService.debug(`[UhkHidDevice] Start reenumeration, mode: ${reenumMode}`);
|
||||||
@@ -197,7 +216,7 @@ export class UhkHidDevice {
|
|||||||
|
|
||||||
async sendKbootCommandToModule(module: ModuleSlotToI2cAddress, command: KbootCommands, maxTry = 1): Promise<any> {
|
async sendKbootCommandToModule(module: ModuleSlotToI2cAddress, command: KbootCommands, maxTry = 1): Promise<any> {
|
||||||
let transfer;
|
let transfer;
|
||||||
const moduleName = kbootKommandName(module);
|
const moduleName = kbootCommandName(module);
|
||||||
this.logService.debug(`[UhkHidDevice] USB[T]: Send KbootCommand ${moduleName} ${KbootCommands[command].toString()}`);
|
this.logService.debug(`[UhkHidDevice] USB[T]: Send KbootCommand ${moduleName} ${KbootCommands[command].toString()}`);
|
||||||
if (command === KbootCommands.idle) {
|
if (command === KbootCommands.idle) {
|
||||||
transfer = new Buffer([UsbCommand.SendKbootCommandToModule, command]);
|
transfer = new Buffer([UsbCommand.SendKbootCommandToModule, command]);
|
||||||
@@ -233,12 +252,14 @@ export class UhkHidDevice {
|
|||||||
private connectToDevice(): HID {
|
private connectToDevice(): HID {
|
||||||
try {
|
try {
|
||||||
const devs = devices();
|
const devs = devices();
|
||||||
|
if (!isEqual(this._prevDevices, devs)) {
|
||||||
this.logService.debug('[UhkHidDevice] Available devices:', devs);
|
this.logService.debug('[UhkHidDevice] Available devices:', devs);
|
||||||
|
this._prevDevices = devs;
|
||||||
|
} else {
|
||||||
|
this.logService.debug('[UhkHidDevice] Available devices unchanged');
|
||||||
|
}
|
||||||
|
|
||||||
const dev = devs.find((x: Device) =>
|
const dev = devs.find(isUhkDevice);
|
||||||
x.vendorId === Constants.VENDOR_ID &&
|
|
||||||
x.productId === Constants.PRODUCT_ID &&
|
|
||||||
((x.usagePage === 128 && x.usage === 129) || x.interface === 0));
|
|
||||||
|
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
this.logService.debug('[UhkHidDevice] UHK Device not found:');
|
this.logService.debug('[UhkHidDevice] UHK Device not found:');
|
||||||
@@ -256,7 +277,7 @@ export class UhkHidDevice {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function kbootKommandName(module: ModuleSlotToI2cAddress): string {
|
function kbootCommandName(module: ModuleSlotToI2cAddress): string {
|
||||||
switch (module) {
|
switch (module) {
|
||||||
case ModuleSlotToI2cAddress.leftHalf:
|
case ModuleSlotToI2cAddress.leftHalf:
|
||||||
return 'leftHalf';
|
return 'leftHalf';
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
} from './constants';
|
} from './constants';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
import * as os from 'os';
|
||||||
import { UhkBlhost } from './uhk-blhost';
|
import { UhkBlhost } from './uhk-blhost';
|
||||||
import { UhkHidDevice } from './uhk-hid-device';
|
import { UhkHidDevice } from './uhk-hid-device';
|
||||||
import { snooze } from './util';
|
import { snooze } from './util';
|
||||||
@@ -29,6 +30,7 @@ export class UhkOperations {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async updateRightFirmware(firmwarePath = this.getFirmwarePath()) {
|
public async updateRightFirmware(firmwarePath = this.getFirmwarePath()) {
|
||||||
|
this.logService.debug(`[UhkOperations] Operating system: ${os.type()} ${os.release()} ${os.arch()}`);
|
||||||
this.logService.debug('[UhkOperations] Start flashing right firmware');
|
this.logService.debug('[UhkOperations] Start flashing right firmware');
|
||||||
const prefix = [`--usb 0x1d50,0x${EnumerationNameToProductId.bootloader.toString(16)}`];
|
const prefix = [`--usb 0x1d50,0x${EnumerationNameToProductId.bootloader.toString(16)}`];
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
import { Device } from 'node-hid';
|
||||||
|
import { DeviceConnectionState, LogService } from 'uhk-common';
|
||||||
|
|
||||||
import { Constants, UsbCommand } from './constants';
|
import { Constants, UsbCommand } from './constants';
|
||||||
import { LogService } from 'uhk-common';
|
|
||||||
|
|
||||||
export const snooze = ms => new Promise(resolve => setTimeout(resolve, ms));
|
export const snooze = ms => new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
|
||||||
@@ -95,3 +97,18 @@ export async function retry(command: Function, maxTry = 3, logService?: LogServi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const deviceConnectionStateComparer = (a: DeviceConnectionState, b: DeviceConnectionState): boolean => {
|
||||||
|
return a.hasPermission === b.hasPermission
|
||||||
|
&& a.connected === b.connected
|
||||||
|
&& a.bootloaderActive === b.bootloaderActive;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isUhkDevice = (dev: Device): boolean => {
|
||||||
|
return dev.vendorId === Constants.VENDOR_ID &&
|
||||||
|
dev.productId === Constants.PRODUCT_ID &&
|
||||||
|
// hidapi can not read the interface number on Mac, so check the usage page and usage
|
||||||
|
((dev.usagePage === 128 && dev.usage === 129) || // Old firmware
|
||||||
|
(dev.usagePage === (0xFF00 | 0x00) && dev.usage === 0x01) || // New firmware
|
||||||
|
dev.interface === 0);
|
||||||
|
};
|
||||||
|
|||||||
6010
packages/uhk-web/package-lock.json
generated
6010
packages/uhk-web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -10,22 +10,24 @@
|
|||||||
"lint": "ng lint",
|
"lint": "ng lint",
|
||||||
"e2e": "ng e2e",
|
"e2e": "ng e2e",
|
||||||
"build:renderer": "webpack --config webpack.config.js",
|
"build:renderer": "webpack --config webpack.config.js",
|
||||||
"server:renderer": "webpack --config webpack.config.js --watch"
|
"server:renderer": "webpack --config webpack.config.js --watch",
|
||||||
|
"pree2e": "webdriver-manager update --standalone false --gecko false --quiet"
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular/animations": "4.4.5",
|
"@angular/animations": "5.2.9",
|
||||||
"@angular/cli": "1.4.7",
|
"@angular/cli": "1.7.4",
|
||||||
"@angular/common": "4.4.5",
|
"@angular/common": "5.2.9",
|
||||||
"@angular/compiler": "4.4.5",
|
"@angular/compiler": "5.2.9",
|
||||||
"@angular/compiler-cli": "4.4.5",
|
"@angular/compiler-cli": "5.2.9",
|
||||||
"@angular/core": "4.4.5",
|
"@angular/core": "5.2.9",
|
||||||
"@angular/forms": "4.4.5",
|
"@angular-devkit/build-optimizer": "0.3.2",
|
||||||
"@angular/http": "4.4.5",
|
"@angular/forms": "5.2.9",
|
||||||
"@angular/language-service": "4.4.5",
|
"@angular/http": "5.2.9",
|
||||||
"@angular/platform-browser": "4.4.5",
|
"@angular/language-service": "5.2.9",
|
||||||
"@angular/platform-browser-dynamic": "4.4.5",
|
"@angular/platform-browser": "5.2.9",
|
||||||
"@angular/router": "4.4.5",
|
"@angular/platform-browser-dynamic": "5.2.9",
|
||||||
|
"@angular/router": "5.2.9",
|
||||||
"@ngrx/effects": "4.0.5",
|
"@ngrx/effects": "4.0.5",
|
||||||
"@ngrx/router-store": "4.0.4",
|
"@ngrx/router-store": "4.0.4",
|
||||||
"@ngrx/store": "4.0.3",
|
"@ngrx/store": "4.0.3",
|
||||||
@@ -41,60 +43,41 @@
|
|||||||
"@types/usb": "1.1.3",
|
"@types/usb": "1.1.3",
|
||||||
"angular-confirmation-popover": "3.2.0",
|
"angular-confirmation-popover": "3.2.0",
|
||||||
"angular-notifier": "2.0.0",
|
"angular-notifier": "2.0.0",
|
||||||
"autoprefixer": "6.5.3",
|
"autoprefixer": "^7.2.3",
|
||||||
"bootstrap": "3.3.7",
|
"bootstrap": "3.3.7",
|
||||||
"buffer": "5.0.6",
|
"buffer": "5.0.6",
|
||||||
"circular-dependency-plugin": "3.0.0",
|
"circular-dependency-plugin": "^4.2.1",
|
||||||
"codelyzer": "3.0.1",
|
"codelyzer": "3.0.1",
|
||||||
"copy-webpack-plugin": "4.0.1",
|
|
||||||
"css-loader": "0.28.1",
|
|
||||||
"cssnano": "3.10.0",
|
|
||||||
"dragula": "3.7.2",
|
"dragula": "3.7.2",
|
||||||
"exports-loader": "0.6.3",
|
|
||||||
"file-loader": "0.10.0",
|
|
||||||
"file-saver": "1.3.3",
|
|
||||||
"font-awesome": "4.7.0",
|
"font-awesome": "4.7.0",
|
||||||
"html-webpack-plugin": "2.29.0",
|
"html-webpack-plugin": "^2.29.0",
|
||||||
"istanbul-instrumenter-loader": "2.0.0",
|
|
||||||
"jasmine-core": "2.6.2",
|
"jasmine-core": "2.6.2",
|
||||||
"jasmine-spec-reporter": "4.1.0",
|
"jasmine-spec-reporter": "4.1.0",
|
||||||
"jquery": "3.2.1",
|
"jquery": "3.2.1",
|
||||||
"jsonfile": "3.0.1",
|
"jsonfile": "3.0.1",
|
||||||
"karma": "1.7.0",
|
"karma": "1.7.0",
|
||||||
"karma-chrome-launcher": "2.1.1",
|
"karma-chrome-launcher": "2.1.1",
|
||||||
"karma-cli": "1.0.1",
|
|
||||||
"karma-coverage-istanbul-reporter": "1.2.1",
|
"karma-coverage-istanbul-reporter": "1.2.1",
|
||||||
"karma-jasmine": "1.1.0",
|
"karma-jasmine": "1.1.0",
|
||||||
"karma-jasmine-html-reporter": "0.2.2",
|
"karma-jasmine-html-reporter": "0.2.2",
|
||||||
"less-loader": "4.0.5",
|
|
||||||
"lodash-es": "4.17.4",
|
"lodash-es": "4.17.4",
|
||||||
"ng2-dragula": "1.5.0",
|
"ng2-dragula": "1.5.0",
|
||||||
"ng2-nouislider": "^1.7.6",
|
"ng2-nouislider": "^1.7.7",
|
||||||
"ng2-select2": "1.0.0-beta.10",
|
"ng2-select2": "1.0.0-beta.10",
|
||||||
"ngx-clipboard": "8.0.0",
|
"ngx-clipboard": "10.0.0",
|
||||||
"ngrx-store-freeze": "0.1.9",
|
"ngrx-store-freeze": "0.1.9",
|
||||||
"nouislider": "^10.1.0",
|
"nouislider": "^11.1.0",
|
||||||
"postcss-loader": "1.3.3",
|
"postcss-url": "^7.1.2",
|
||||||
"postcss-url": "5.1.2",
|
|
||||||
"protractor": "5.1.2",
|
"protractor": "5.1.2",
|
||||||
"raw-loader": "0.5.1",
|
|
||||||
"reselect": "3.0.1",
|
"reselect": "3.0.1",
|
||||||
"sass-loader": "6.0.3",
|
"rxjs": "5.5.8",
|
||||||
"script-loader": "0.7.0",
|
|
||||||
"select2": "4.0.3",
|
"select2": "4.0.3",
|
||||||
"source-map-loader": "0.2.0",
|
"typescript": "2.6.2",
|
||||||
"style-loader": "0.13.1",
|
|
||||||
"stylus-loader": "3.0.1",
|
|
||||||
"sudo-prompt": "7.1.1",
|
|
||||||
"ts-loader": "2.3.1",
|
|
||||||
"ts-node": "3.0.4",
|
|
||||||
"uhk-common": "1.0.0",
|
"uhk-common": "1.0.0",
|
||||||
"url-loader": "0.5.7",
|
|
||||||
"webpack": "3.4.1",
|
|
||||||
"webpack-dev-server": "2.5.1",
|
|
||||||
"webpack-svgstore-plugin": "4.0.1",
|
|
||||||
"xml-loader": "1.2.1",
|
"xml-loader": "1.2.1",
|
||||||
"zone.js": "0.8.14"
|
"zone.js": "0.8.26",
|
||||||
|
"@angular-devkit/core": "0.3.2",
|
||||||
|
"@ngtools/webpack": "1.10.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"classlist.js": "1.1.20150312",
|
"classlist.js": "1.1.20150312",
|
||||||
|
|||||||
@@ -5,17 +5,19 @@ import { deviceRoutes } from './components/device';
|
|||||||
import { addOnRoutes } from './components/add-on';
|
import { addOnRoutes } from './components/add-on';
|
||||||
import { keymapRoutes } from './components/keymap';
|
import { keymapRoutes } from './components/keymap';
|
||||||
import { macroRoutes } from './components/macro';
|
import { macroRoutes } from './components/macro';
|
||||||
import { PrivilegeCheckerComponent } from './components/privilege-checker/privilege-checker.component';
|
import { PrivilegeCheckerComponent } from './components/privilege-checker';
|
||||||
import { MissingDeviceComponent } from './components/missing-device/missing-device.component';
|
import { MissingDeviceComponent } from './components/missing-device';
|
||||||
import { UhkDeviceDisconnectedGuard } from './services/uhk-device-disconnected.guard';
|
import { UhkDeviceDisconnectedGuard } from './services/uhk-device-disconnected.guard';
|
||||||
import { UhkDeviceConnectedGuard } from './services/uhk-device-connected.guard';
|
import { UhkDeviceConnectedGuard } from './services/uhk-device-connected.guard';
|
||||||
import { UhkDeviceUninitializedGuard } from './services/uhk-device-uninitialized.guard';
|
import { UhkDeviceUninitializedGuard } from './services/uhk-device-uninitialized.guard';
|
||||||
import { UhkDeviceInitializedGuard } from './services/uhk-device-initialized.guard';
|
import { UhkDeviceInitializedGuard } from './services/uhk-device-initialized.guard';
|
||||||
import { MainPage } from './pages/main-page/main.page';
|
import { MainPage } from './pages/main-page/main.page';
|
||||||
import { agentRoutes } from './components/agent/agent.routes';
|
import { agentRoutes } from './components/agent';
|
||||||
import { LoadingDevicePageComponent } from './pages/loading-page/loading-device.page';
|
import { LoadingDevicePageComponent } from './pages/loading-page/loading-device.page';
|
||||||
import { UhkDeviceLoadingGuard } from './services/uhk-device-loading.guard';
|
import { UhkDeviceLoadingGuard } from './services/uhk-device-loading.guard';
|
||||||
import { UhkDeviceLoadedGuard } from './services/uhk-device-loaded.guard';
|
import { UhkDeviceLoadedGuard } from './services/uhk-device-loaded.guard';
|
||||||
|
import { RecoveryModeComponent } from './components/device';
|
||||||
|
import { UhkDeviceBootloaderNotActiveGuard } from './services/uhk-device-bootloader-not-active.guard';
|
||||||
|
|
||||||
const appRoutes: Routes = [
|
const appRoutes: Routes = [
|
||||||
{
|
{
|
||||||
@@ -33,6 +35,11 @@ const appRoutes: Routes = [
|
|||||||
component: LoadingDevicePageComponent,
|
component: LoadingDevicePageComponent,
|
||||||
canActivate: [UhkDeviceLoadedGuard]
|
canActivate: [UhkDeviceLoadedGuard]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'recovery-device',
|
||||||
|
component: RecoveryModeComponent,
|
||||||
|
canActivate: [UhkDeviceBootloaderNotActiveGuard]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
component: MainPage,
|
component: MainPage,
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<input #inputControl
|
||||||
|
cancelable
|
||||||
|
[class]="css"
|
||||||
|
type="text"
|
||||||
|
[disabled]="disabled"
|
||||||
|
[(ngModel)]="model"
|
||||||
|
(blur)="blur()"
|
||||||
|
(focus)="focus()"
|
||||||
|
(keyup.enter)="keyEnter($event)"
|
||||||
|
(keyup)="calculateTextWidth($event.target.value)">
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
import {
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
ChangeDetectorRef,
|
||||||
|
Component,
|
||||||
|
ElementRef,
|
||||||
|
forwardRef, HostListener,
|
||||||
|
Input,
|
||||||
|
Renderer2,
|
||||||
|
ViewChild
|
||||||
|
} from '@angular/core';
|
||||||
|
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||||
|
import * as util from '../../util';
|
||||||
|
|
||||||
|
const noop = (_: any) => {
|
||||||
|
};
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'auto-grow-input',
|
||||||
|
templateUrl: './auto-grow-input.component.html',
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: NG_VALUE_ACCESSOR,
|
||||||
|
useExisting: forwardRef(() => AutoGrowInputComponent),
|
||||||
|
multi: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AutoGrowInputComponent implements ControlValueAccessor {
|
||||||
|
@Input() maxParentWidthPercent = 1;
|
||||||
|
@Input() css: string;
|
||||||
|
|
||||||
|
@ViewChild('inputControl') inputControl: ElementRef;
|
||||||
|
|
||||||
|
disabled: boolean;
|
||||||
|
|
||||||
|
get model(): string {
|
||||||
|
return this._model;
|
||||||
|
}
|
||||||
|
|
||||||
|
set model(value: string) {
|
||||||
|
if (this._model === value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._model = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _model: string;
|
||||||
|
private _originalModel: string;
|
||||||
|
private _onChanged = noop;
|
||||||
|
private _onTouched = noop;
|
||||||
|
|
||||||
|
constructor(private _cdRef: ChangeDetectorRef,
|
||||||
|
private _renderer: Renderer2) {
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnChange(fn: any): void {
|
||||||
|
this._onChanged = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnTouched(fn: any): void {
|
||||||
|
this._onTouched = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
setDisabledState(isDisabled: boolean): void {
|
||||||
|
if (this.disabled === isDisabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.disabled = isDisabled;
|
||||||
|
this._cdRef.markForCheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
@HostListener('window:resize')
|
||||||
|
windowResize(): void {
|
||||||
|
this.calculateTextWidth(this._model);
|
||||||
|
}
|
||||||
|
|
||||||
|
writeValue(obj: any): void {
|
||||||
|
console.log('write', new Date());
|
||||||
|
if (this.model === obj) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._model = obj;
|
||||||
|
this._originalModel = obj;
|
||||||
|
this.calculateTextWidth(this._model);
|
||||||
|
this._cdRef.markForCheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
focus(): void {
|
||||||
|
this._onTouched(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
blur(): void {
|
||||||
|
if (!util.isValidName(this._model) || this._model.trim() === this._originalModel) {
|
||||||
|
this._model = this._originalModel;
|
||||||
|
this.calculateTextWidth(this._model);
|
||||||
|
this._cdRef.markForCheck();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._originalModel = this._model;
|
||||||
|
this._onChanged(this._model);
|
||||||
|
}
|
||||||
|
|
||||||
|
keyEnter(event): void {
|
||||||
|
event.target.blur();
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateTextWidth(text: string): void {
|
||||||
|
const htmlInput = this.inputControl.nativeElement as HTMLInputElement;
|
||||||
|
const maxWidth = htmlInput.parentElement.parentElement.offsetWidth * this.maxParentWidthPercent;
|
||||||
|
const textWidth = util.getContentWidth(window.getComputedStyle(htmlInput), text);
|
||||||
|
this._renderer.setStyle(htmlInput, 'width', Math.min(maxWidth, textWidth) + 'px');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from './auto-grow-input.component';
|
||||||
@@ -14,11 +14,9 @@
|
|||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label class="btn btn-default btn-file">
|
<file-upload (fileChanged)="changeFile($event)"
|
||||||
Import device configuration
|
label="Import device configuration">
|
||||||
<input type="file"
|
</file-upload>
|
||||||
(change)="changeFile($event)">
|
|
||||||
</label>
|
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<button class="btn btn-danger"
|
<button class="btn btn-danger"
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
SaveUserConfigInBinaryFileAction,
|
SaveUserConfigInBinaryFileAction,
|
||||||
SaveUserConfigInJsonFileAction
|
SaveUserConfigInJsonFileAction
|
||||||
} from '../../../store/actions/user-config';
|
} from '../../../store/actions/user-config';
|
||||||
|
import { UploadFileData } from '../../../models/upload-file-data';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'device-settings',
|
selector: 'device-settings',
|
||||||
@@ -42,16 +43,7 @@ export class DeviceConfigurationComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
changeFile(event): void {
|
changeFile(data: UploadFileData): void {
|
||||||
const files = event.srcElement.files;
|
this.store.dispatch(new LoadUserConfigurationFromFileAction(data));
|
||||||
const fileReader = new FileReader();
|
|
||||||
fileReader.onloadend = function () {
|
|
||||||
const arrayBuffer = new Uint8Array(fileReader.result);
|
|
||||||
this.store.dispatch(new LoadUserConfigurationFromFileAction({
|
|
||||||
filename: event.srcElement.value,
|
|
||||||
data: Array.from(arrayBuffer)
|
|
||||||
}));
|
|
||||||
}.bind(this);
|
|
||||||
fileReader.readAsArrayBuffer(files[0]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { DeviceFirmwareComponent } from './firmware/device-firmware.component';
|
|||||||
import { MouseSpeedComponent } from './mouse-speed/mouse-speed.component';
|
import { MouseSpeedComponent } from './mouse-speed/mouse-speed.component';
|
||||||
import { LEDBrightnessComponent } from './led-brightness/led-brightness.component';
|
import { LEDBrightnessComponent } from './led-brightness/led-brightness.component';
|
||||||
import { RestoreConfigurationComponent } from './restore-configuration/restore-configuration.component';
|
import { RestoreConfigurationComponent } from './restore-configuration/restore-configuration.component';
|
||||||
|
import { RecoveryModeComponent } from './recovery-mode/recovery-mode.component';
|
||||||
|
|
||||||
export const deviceRoutes: Routes = [
|
export const deviceRoutes: Routes = [
|
||||||
{
|
{
|
||||||
@@ -34,6 +35,10 @@ export const deviceRoutes: Routes = [
|
|||||||
{
|
{
|
||||||
path: 'restore-user-configuration',
|
path: 'restore-user-configuration',
|
||||||
component: RestoreConfigurationComponent
|
component: RestoreConfigurationComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'recovery-mode',
|
||||||
|
component: RecoveryModeComponent
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,14 +12,17 @@
|
|||||||
Firmware {{ hardwareModules.rightModuleInfo.firmwareVersion }} is running on the right keyboard half.
|
Firmware {{ hardwareModules.rightModuleInfo.firmwareVersion }} is running on the right keyboard half.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
If the update process fails, consider the following points:
|
||||||
<i>
|
<ol>
|
||||||
Please note that the firmware update process may sometimes fail. If if fails then
|
<li>Windows 7, Windows Vista, and Windows XP are not supported. Use Linux, OSX, Windows 10, or Windows 8.</li>
|
||||||
simply retry until it succeeds. If the left half becomes unresponsive after a failed
|
<li>Connect your UHK directly to the host computer. Don't use USB hubs or KVM switches.</li>
|
||||||
update then retry and follow the instructions displayed during the update to fix it.
|
<li>Run Agent directly on the host operating system. Don't use VirtualBox or VMware Workstation.</li>
|
||||||
We'll make the firmware update process more robust.
|
<li>Give a try to every USB port of your computer.</li>
|
||||||
</i>
|
<li>Remove every other USB device from your computer.</li>
|
||||||
</p>
|
<li>If the left half becomes unresponsive after a failed update then retry and follow the instructions displayed during the update to fix it.</li>
|
||||||
|
<li>If the above fails, retry a couple of times.</li>
|
||||||
|
<li>If everything else fails, please add a new comment to <a class="link-github" (click)="openFirmwareGitHubIssuePage($event)">the GitHub issue</a>, and attach the update log.</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<button class="btn btn-primary"
|
<button class="btn btn-primary"
|
||||||
@@ -27,27 +30,17 @@
|
|||||||
(click)="onUpdateFirmware()">
|
(click)="onUpdateFirmware()">
|
||||||
Flash firmware {{ (getAgentVersionInfo$ | async).firmwareVersion }} (bundled with Agent)
|
Flash firmware {{ (getAgentVersionInfo$ | async).firmwareVersion }} (bundled with Agent)
|
||||||
</button>
|
</button>
|
||||||
<label class="btn btn-primary btn-file"
|
<file-upload [disabled]="flashFirmwareButtonDisbabled$ | async"
|
||||||
[class.disabled]="flashFirmwareButtonDisbabled$ | async">
|
(fileChanged)="changeFile($event)"
|
||||||
Choose firmware file and flash it
|
|
||||||
<input id="firmware-file-select"
|
|
||||||
type="file"
|
|
||||||
accept=".tar.bz2"
|
accept=".tar.bz2"
|
||||||
[disabled]="flashFirmwareButtonDisbabled$ | async"
|
label="Choose firmware file and flash it"></file-upload>
|
||||||
(change)="changeFile($event)">
|
|
||||||
</label>
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex-grow" #scrollMe>
|
<div class="flex-grow">
|
||||||
<xterm [logs]="xtermLog$ | async"></xterm>
|
<xterm [logs]="xtermLog$ | async"></xterm>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<div class="flex-footer">
|
||||||
<button type="button"
|
|
||||||
class="btn btn-primary ok-button"
|
|
||||||
[disabled]="firmwareOkButtonDisabled$ | async"
|
|
||||||
(click)="onOkButtonClick()">OK
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,24 +6,6 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-container {
|
.link-github {
|
||||||
height: 100%;
|
cursor: pointer;
|
||||||
max-height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-grow {
|
|
||||||
background-color: black;
|
|
||||||
overflow: auto;
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer {
|
|
||||||
margin-top: 0.5em;
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ok-button {
|
|
||||||
min-width: 100px;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,21 @@
|
|||||||
import { Component, ElementRef, OnDestroy, ViewChild } from '@angular/core';
|
import { Component, OnDestroy } from '@angular/core';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { Subscription } from 'rxjs/Subscription';
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
import { HardwareModules, VersionInformation } from 'uhk-common';
|
import { HardwareModules, VersionInformation } from 'uhk-common';
|
||||||
|
import { Constants } from 'uhk-common';
|
||||||
|
import { OpenUrlInNewWindowAction } from '../../../store/actions/app';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AppState,
|
AppState,
|
||||||
firmwareOkButtonDisabled,
|
|
||||||
flashFirmwareButtonDisbabled,
|
flashFirmwareButtonDisbabled,
|
||||||
getAgentVersionInfo,
|
getAgentVersionInfo,
|
||||||
getHardwareModules,
|
getHardwareModules,
|
||||||
xtermLog
|
xtermLog
|
||||||
} from '../../../store';
|
} from '../../../store';
|
||||||
import { UpdateFirmwareAction, UpdateFirmwareOkButtonAction, UpdateFirmwareWithAction } from '../../../store/actions/device';
|
import { UpdateFirmwareAction, UpdateFirmwareWithAction } from '../../../store/actions/device';
|
||||||
import { XtermLog } from '../../../models/xterm-log';
|
import { XtermLog } from '../../../models/xterm-log';
|
||||||
|
import { UploadFileData } from '../../../models/upload-file-data';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'device-firmware',
|
selector: 'device-firmware',
|
||||||
@@ -26,33 +28,20 @@ import { XtermLog } from '../../../models/xterm-log';
|
|||||||
export class DeviceFirmwareComponent implements OnDestroy {
|
export class DeviceFirmwareComponent implements OnDestroy {
|
||||||
flashFirmwareButtonDisbabled$: Observable<boolean>;
|
flashFirmwareButtonDisbabled$: Observable<boolean>;
|
||||||
xtermLog$: Observable<Array<XtermLog>>;
|
xtermLog$: Observable<Array<XtermLog>>;
|
||||||
xtermLogSubscription: Subscription;
|
|
||||||
getAgentVersionInfo$: Observable<VersionInformation>;
|
getAgentVersionInfo$: Observable<VersionInformation>;
|
||||||
firmwareOkButtonDisabled$: Observable<boolean>;
|
|
||||||
hardwareModulesSubscription: Subscription;
|
hardwareModulesSubscription: Subscription;
|
||||||
hardwareModules: HardwareModules;
|
hardwareModules: HardwareModules;
|
||||||
|
|
||||||
@ViewChild('scrollMe') divElement: ElementRef;
|
|
||||||
|
|
||||||
constructor(private store: Store<AppState>) {
|
constructor(private store: Store<AppState>) {
|
||||||
this.flashFirmwareButtonDisbabled$ = store.select(flashFirmwareButtonDisbabled);
|
this.flashFirmwareButtonDisbabled$ = store.select(flashFirmwareButtonDisbabled);
|
||||||
this.xtermLog$ = store.select(xtermLog);
|
this.xtermLog$ = store.select(xtermLog);
|
||||||
this.xtermLogSubscription = this.xtermLog$.subscribe(() => {
|
|
||||||
if (this.divElement && this.divElement.nativeElement) {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.divElement.nativeElement.scrollTop = this.divElement.nativeElement.scrollHeight;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.getAgentVersionInfo$ = store.select(getAgentVersionInfo);
|
this.getAgentVersionInfo$ = store.select(getAgentVersionInfo);
|
||||||
this.firmwareOkButtonDisabled$ = store.select(firmwareOkButtonDisabled);
|
|
||||||
this.hardwareModulesSubscription = store.select(getHardwareModules).subscribe(data => {
|
this.hardwareModulesSubscription = store.select(getHardwareModules).subscribe(data => {
|
||||||
this.hardwareModules = data;
|
this.hardwareModules = data;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.xtermLogSubscription.unsubscribe();
|
|
||||||
this.hardwareModulesSubscription.unsubscribe();
|
this.hardwareModulesSubscription.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,22 +49,12 @@ export class DeviceFirmwareComponent implements OnDestroy {
|
|||||||
this.store.dispatch(new UpdateFirmwareAction());
|
this.store.dispatch(new UpdateFirmwareAction());
|
||||||
}
|
}
|
||||||
|
|
||||||
onOkButtonClick(): void {
|
changeFile(data: UploadFileData): void {
|
||||||
this.store.dispatch(new UpdateFirmwareOkButtonAction());
|
this.store.dispatch(new UpdateFirmwareWithAction(data.data));
|
||||||
}
|
}
|
||||||
|
|
||||||
changeFile(event): void {
|
openFirmwareGitHubIssuePage(event): void {
|
||||||
const files = event.srcElement.files;
|
event.preventDefault();
|
||||||
|
this.store.dispatch(new OpenUrlInNewWindowAction(Constants.FIRMWARE_GITHUB_ISSUE_URL));
|
||||||
if (files.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const fileReader = new FileReader();
|
|
||||||
fileReader.onloadend = function () {
|
|
||||||
const arrayBuffer = new Uint8Array(fileReader.result);
|
|
||||||
this.store.dispatch(new UpdateFirmwareWithAction(Array.prototype.slice.call(arrayBuffer)));
|
|
||||||
}.bind(this);
|
|
||||||
fileReader.readAsArrayBuffer(files[0]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,4 +3,5 @@ export * from './firmware/device-firmware.component';
|
|||||||
export * from './mouse-speed/mouse-speed.component';
|
export * from './mouse-speed/mouse-speed.component';
|
||||||
export * from './led-brightness/led-brightness.component';
|
export * from './led-brightness/led-brightness.component';
|
||||||
export * from './restore-configuration/restore-configuration.component';
|
export * from './restore-configuration/restore-configuration.component';
|
||||||
|
export * from './recovery-mode/recovery-mode.component';
|
||||||
export * from './device.routes';
|
export * from './device.routes';
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<div class="full-height">
|
||||||
|
<div class="flex-container">
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<h1>
|
||||||
|
<i class="fa fa-wrench"></i>
|
||||||
|
<span>Fix device</span>
|
||||||
|
</h1>
|
||||||
|
<p>
|
||||||
|
Your device seems to be broken. No worries, Agent can fix it.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<button class="btn btn-primary"
|
||||||
|
type="button"
|
||||||
|
[disabled]="flashFirmwareButtonDisbabled$ | async"
|
||||||
|
(click)="onRecoveryDevice()">Fix device
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex-grow">
|
||||||
|
<xterm [logs]="xtermLog$ | async"></xterm>
|
||||||
|
</div>
|
||||||
|
<div class="flex-footer">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
:host {
|
||||||
|
overflow-y: auto;
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 1.5rem 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
|
||||||
|
import { XtermLog } from '../../../models/xterm-log';
|
||||||
|
import { AppState, flashFirmwareButtonDisbabled, xtermLog } from '../../../store';
|
||||||
|
import { RecoveryDeviceAction } from '../../../store/actions/device';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'device-recovery-mode',
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
templateUrl: './recovery-mode.component.html',
|
||||||
|
styleUrls: ['./recovery-mode.component.scss'],
|
||||||
|
host: {
|
||||||
|
'class': 'container-fluid'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
export class RecoveryModeComponent implements OnInit {
|
||||||
|
flashFirmwareButtonDisbabled$: Observable<boolean>;
|
||||||
|
|
||||||
|
xtermLog$: Observable<Array<XtermLog>>;
|
||||||
|
|
||||||
|
constructor(private store: Store<AppState>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.flashFirmwareButtonDisbabled$ = this.store.select(flashFirmwareButtonDisbabled);
|
||||||
|
this.xtermLog$ = this.store.select(xtermLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
onRecoveryDevice(): void {
|
||||||
|
this.store.dispatch(new RecoveryDeviceAction());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<label class="btn btn-primary btn-file"
|
||||||
|
[class.disabled]="disabled">
|
||||||
|
{{ label }}
|
||||||
|
<input #inputControl
|
||||||
|
type="file"
|
||||||
|
[accept]="accept"
|
||||||
|
[disabled]="disabled"
|
||||||
|
(change)="changeFile($event)">
|
||||||
|
</label>
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
||||||
|
|
||||||
|
import { UploadFileData } from '../../models/upload-file-data';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'file-upload',
|
||||||
|
templateUrl: './file-upload.component.html',
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
|
})
|
||||||
|
export class FileUploadComponent {
|
||||||
|
@Input() label = 'Select file';
|
||||||
|
@Input() disabled: boolean;
|
||||||
|
@Input() accept: string;
|
||||||
|
|
||||||
|
@Output() fileChanged = new EventEmitter<UploadFileData>();
|
||||||
|
|
||||||
|
changeFile(event): void {
|
||||||
|
const files = event.srcElement.files;
|
||||||
|
|
||||||
|
if (files.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileReader = new FileReader();
|
||||||
|
fileReader.onloadend = function () {
|
||||||
|
const arrayBuffer = new Uint8Array(fileReader.result);
|
||||||
|
const target = event.target || event.srcElement || event.currentTarget;
|
||||||
|
target.value = null;
|
||||||
|
this.fileChanged.emit({
|
||||||
|
filename: event.srcElement.value,
|
||||||
|
data: Array.from(arrayBuffer)
|
||||||
|
});
|
||||||
|
}.bind(this);
|
||||||
|
fileReader.readAsArrayBuffer(files[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
1
packages/uhk-web/src/app/components/file-upload/index.ts
Normal file
1
packages/uhk-web/src/app/components/file-upload/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './file-upload.component';
|
||||||
@@ -67,7 +67,7 @@ export class MacroKeyTabComponent extends MacroBaseComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getKeyMacroAction(): KeyMacroAction {
|
getKeyMacroAction(): KeyMacroAction {
|
||||||
const keyMacroAction = Object.assign(new KeyMacroAction(), this.keypressTab.toKeyAction());
|
const keyMacroAction = new KeyMacroAction(this.keypressTab.toKeyAction() as any);
|
||||||
keyMacroAction.action = this.getActionType(this.activeTab);
|
keyMacroAction.action = this.getActionType(this.activeTab);
|
||||||
return keyMacroAction;
|
return keyMacroAction;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
<div>
|
<div>
|
||||||
<h4>Type text</h4>
|
<h4>Type text</h4>
|
||||||
<textarea #macroTextInput name="macro-text" (change)="onTextChange()"
|
<textarea #macroTextInput
|
||||||
(keyup)="validate()" class="macro__text-input">{{ macroAction?.text }}</textarea>
|
name="macro-text"
|
||||||
|
(keydown)="onKeydown($event)"
|
||||||
|
(change)="onTextChange()"
|
||||||
|
(keyup)="validate()"
|
||||||
|
(paste)="onPaste($event)"
|
||||||
|
class="macro__text-input">{{ macroAction?.text }}</textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import { TextMacroAction } from 'uhk-common';
|
|||||||
|
|
||||||
import { MacroBaseComponent } from '../macro-base.component';
|
import { MacroBaseComponent } from '../macro-base.component';
|
||||||
|
|
||||||
|
const NON_ASCII_REGEXP = /[^\x00-\x7F]/g;
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'macro-text-tab',
|
selector: 'macro-text-tab',
|
||||||
templateUrl: './macro-text.component.html',
|
templateUrl: './macro-text.component.html',
|
||||||
@@ -36,6 +38,41 @@ export class MacroTextTabComponent extends MacroBaseComponent implements OnInit,
|
|||||||
this.macroAction.text = this.input.nativeElement.value;
|
this.macroAction.text = this.input.nativeElement.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not allow non ascii character
|
||||||
|
* @param $event
|
||||||
|
*/
|
||||||
|
onKeydown($event: KeyboardEvent): void {
|
||||||
|
if (new RegExp(NON_ASCII_REGEXP).test($event.key)) {
|
||||||
|
$event.preventDefault();
|
||||||
|
$event.stopPropagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove non ascii character from clipboard data
|
||||||
|
* @param $event
|
||||||
|
*/
|
||||||
|
onPaste($event: ClipboardEvent): void {
|
||||||
|
$event.preventDefault();
|
||||||
|
|
||||||
|
const textarea: HTMLTextAreaElement = this.input.nativeElement;
|
||||||
|
const data = $event.clipboardData.getData('text/plain');
|
||||||
|
const text = data && data.replace(NON_ASCII_REGEXP, '') || '';
|
||||||
|
if (text.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = textarea.value || '';
|
||||||
|
const prefix = value.substr(0, textarea.selectionStart);
|
||||||
|
const end = textarea.selectionEnd;
|
||||||
|
const suffix = value.substr(textarea.selectionEnd);
|
||||||
|
textarea.value = prefix + text + suffix;
|
||||||
|
const correction = end === 0 ? 0 : 1;
|
||||||
|
textarea.selectionStart = textarea.selectionEnd = end + text.length - correction;
|
||||||
|
this.macroAction.text = textarea.value;
|
||||||
|
}
|
||||||
|
|
||||||
isMacroValid = () => !!this.input.nativeElement.value;
|
isMacroValid = () => !!this.input.nativeElement.value;
|
||||||
|
|
||||||
private init = () => {
|
private init = () => {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<div class="row list-container">
|
<div class="row list-container">
|
||||||
<div class="col-xs-10 col-xs-offset-1 list-group">
|
<div class="col-xs-10 col-xs-offset-1 list-group">
|
||||||
|
<p><i>Please note that macro playback is not implemented yet. You can create macros, but they won't have any effect until firmware support is implemented. We're working on this.</i></p>
|
||||||
<div class="macro-actions-container" [dragula]="'macroActions'" [dragulaModel]="macro.macroActions">
|
<div class="macro-actions-container" [dragula]="'macroActions'" [dragulaModel]="macro.macroActions">
|
||||||
<macro-item *ngFor="let macroAction of macro.macroActions; let macroActionIndex = index"
|
<macro-item *ngFor="let macroAction of macro.macroActions; let macroActionIndex = index"
|
||||||
[macroAction]="macroAction"
|
[macroAction]="macroAction"
|
||||||
|
|||||||
@@ -79,8 +79,8 @@ export class PopoverComponent implements OnChanges {
|
|||||||
@Input() defaultKeyAction: KeyAction;
|
@Input() defaultKeyAction: KeyAction;
|
||||||
@Input() currentKeymap: Keymap;
|
@Input() currentKeymap: Keymap;
|
||||||
@Input() currentLayer: number;
|
@Input() currentLayer: number;
|
||||||
@Input() keyPosition: ClientRect;
|
@Input() keyPosition: any;
|
||||||
@Input() wrapPosition: ClientRect;
|
@Input() wrapPosition: any;
|
||||||
@Input() visible: boolean;
|
@Input() visible: boolean;
|
||||||
|
|
||||||
@Output() cancel = new EventEmitter<any>();
|
@Output() cancel = new EventEmitter<any>();
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
></select2>
|
></select2>
|
||||||
<icon name="question-circle"
|
<icon name="question-circle"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip"
|
||||||
title="Looking for a non-US character? Just pick the character of the desired key according to the US layout."
|
title="Looking for a non-US character? Just pick the character of the desired key according to the US layout. For example, on US keyboards next to Tab there is the Q key, but it's й on Russian keyboards, so in this case choose Q instead of й in Agent."
|
||||||
data-placement="bottom"></icon>
|
data-placement="bottom"></icon>
|
||||||
<capture-keystroke-button (capture)="onKeysCapture($event)" tabindex="0"></capture-keystroke-button>
|
<capture-keystroke-button (capture)="onKeysCapture($event)" tabindex="0"></capture-keystroke-button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ export class KeypressTabComponent extends Tab implements OnChanges {
|
|||||||
const scTypePair = this.toScancodeTypePair(this.selectedScancodeOption);
|
const scTypePair = this.toScancodeTypePair(this.selectedScancodeOption);
|
||||||
keystrokeAction.scancode = scTypePair[0];
|
keystrokeAction.scancode = scTypePair[0];
|
||||||
if (scTypePair[1] === 'media') {
|
if (scTypePair[1] === 'media') {
|
||||||
keystrokeAction.type = KeystrokeType.shortMedia;
|
keystrokeAction.type = keystrokeAction.scancode > 255 ? KeystrokeType.longMedia : KeystrokeType.shortMedia;
|
||||||
} else {
|
} else {
|
||||||
keystrokeAction.type = KeystrokeType[scTypePair[1]];
|
keystrokeAction.type = KeystrokeType[scTypePair[1]];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
<span [ngSwitch]="toggle">
|
<span [ngSwitch]="toggle">
|
||||||
<ng-template [ngSwitchCase]="true">layer by pressing this key.</ng-template>
|
<ng-template [ngSwitchCase]="true">layer by tapping this key.</ng-template>
|
||||||
<ng-template ngSwitchDefault>layer by holding this key.</ng-template>
|
<ng-template ngSwitchDefault>layer by holding this key.</ng-template>
|
||||||
</span>
|
</span>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<span> No macros are available to choose from. Create a macro first! </span>
|
<span> No macros are available to choose from. Create a macro first! </span>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template [ngIf]="macroOptions.length > 0">
|
<ng-template [ngIf]="macroOptions.length > 0">
|
||||||
<p><i>Please note that macro playback is not implemented yet. You can bind macros, but they don't have any effect.</i></p>
|
<p><i>Please note that macro playback is not implemented yet. You can bind macros, but they won't have any effect until firmware support is implemented. We're working on this.</i></p>
|
||||||
<div class="macro-selector">
|
<div class="macro-selector">
|
||||||
<b> Play macro: </b>
|
<b> Play macro: </b>
|
||||||
<select2 [data]="macroOptions" [value]="macroOptions[selectedMacroIndex].id" (valueChanged)="onChange($event)" [width]="'100%'"></select2>
|
<select2 [data]="macroOptions" [value]="macroOptions[selectedMacroIndex].id" (valueChanged)="onChange($event)" [width]="'100%'"></select2>
|
||||||
|
|||||||
@@ -2,13 +2,11 @@
|
|||||||
<li class="sidebar__level-0--item">
|
<li class="sidebar__level-0--item">
|
||||||
<div class="sidebar__level-0">
|
<div class="sidebar__level-0">
|
||||||
<i class="uhk-icon uhk-icon-0401-usb-stick rotate-right"></i>
|
<i class="uhk-icon uhk-icon-0401-usb-stick rotate-right"></i>
|
||||||
<input #deviceName cancelable
|
<auto-grow-input [ngModel]="state.deviceName"
|
||||||
class="pane-title__name"
|
[maxParentWidthPercent]="0.65"
|
||||||
type="text"
|
[css]="'side-menu-pane-title__name'"
|
||||||
[readonly]="state.restoreUserConfiguration"
|
[disabled]="state.restoreUserConfiguration || state.updatingFirmware"
|
||||||
(change)="editDeviceName($event.target.value)"
|
(ngModelChange)="editDeviceName($event)"></auto-grow-input>
|
||||||
(keyup.enter)="deviceName.blur()"
|
|
||||||
(keyup)="calculateHeaderTextWidth($event.target.value)">
|
|
||||||
<i class="fa fa-chevron-up pull-right" (click)="toggleHide($event, 'device')"></i>
|
<i class="fa fa-chevron-up pull-right" (click)="toggleHide($event, 'device')"></i>
|
||||||
</div>
|
</div>
|
||||||
<ul [@toggler]="animation['device']">
|
<ul [@toggler]="animation['device']">
|
||||||
|
|||||||
@@ -162,22 +162,3 @@ ul {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.pane-title {
|
|
||||||
margin-bottom: 1em;
|
|
||||||
|
|
||||||
&__name {
|
|
||||||
border: none;
|
|
||||||
border-bottom: 2px dotted #999;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0 0.25rem;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
background-color: transparent;
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
box-shadow: 0 0 0 1px #ccc, 0 0 5px 0 #ccc;
|
|
||||||
border-color: transparent;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import {
|
import {
|
||||||
AfterContentInit,
|
|
||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
ChangeDetectorRef,
|
ChangeDetectorRef,
|
||||||
Component,
|
Component,
|
||||||
@@ -19,7 +18,6 @@ import 'rxjs/add/operator/let';
|
|||||||
|
|
||||||
import { AppState, getSideMenuPageState } from '../../store';
|
import { AppState, getSideMenuPageState } from '../../store';
|
||||||
import { MacroActions } from '../../store/actions';
|
import { MacroActions } from '../../store/actions';
|
||||||
import * as util from '../../util';
|
|
||||||
import { RenameUserConfigurationAction } from '../../store/actions/user-config';
|
import { RenameUserConfigurationAction } from '../../store/actions/user-config';
|
||||||
import { SideMenuPageState } from '../../models/side-menu-page-state';
|
import { SideMenuPageState } from '../../models/side-menu-page-state';
|
||||||
|
|
||||||
@@ -40,7 +38,7 @@ import { SideMenuPageState } from '../../models/side-menu-page-state';
|
|||||||
styleUrls: ['./side-menu.component.scss'],
|
styleUrls: ['./side-menu.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class SideMenuComponent implements AfterContentInit, OnInit, OnDestroy {
|
export class SideMenuComponent implements OnInit, OnDestroy {
|
||||||
state: SideMenuPageState;
|
state: SideMenuPageState;
|
||||||
animation: { [key: string]: 'active' | 'inactive' };
|
animation: { [key: string]: 'active' | 'inactive' };
|
||||||
@ViewChild('deviceName') deviceName: ElementRef;
|
@ViewChild('deviceName') deviceName: ElementRef;
|
||||||
@@ -62,15 +60,10 @@ export class SideMenuComponent implements AfterContentInit, OnInit, OnDestroy {
|
|||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.stateSubscription = this.store.select(getSideMenuPageState).subscribe(data => {
|
this.stateSubscription = this.store.select(getSideMenuPageState).subscribe(data => {
|
||||||
this.state = data;
|
this.state = data;
|
||||||
this.setDeviceName();
|
|
||||||
this.cdRef.markForCheck();
|
this.cdRef.markForCheck();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterContentInit(): void {
|
|
||||||
this.setDeviceName();
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (this.stateSubscription) {
|
if (this.stateSubscription) {
|
||||||
this.stateSubscription.unsubscribe();
|
this.stateSubscription.unsubscribe();
|
||||||
@@ -106,24 +99,6 @@ export class SideMenuComponent implements AfterContentInit, OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
editDeviceName(name: string): void {
|
editDeviceName(name: string): void {
|
||||||
if (!util.isValidName(name) || name.trim() === this.state.deviceName) {
|
|
||||||
this.setDeviceName();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.store.dispatch(new RenameUserConfigurationAction(name));
|
this.store.dispatch(new RenameUserConfigurationAction(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
calculateHeaderTextWidth(text): void {
|
|
||||||
const htmlInput = this.deviceName.nativeElement as HTMLInputElement;
|
|
||||||
const maxWidth = htmlInput.parentElement.offsetWidth * 0.66;
|
|
||||||
const textWidth = util.getContentWidth(window.getComputedStyle(htmlInput), text);
|
|
||||||
this.renderer.setStyle(htmlInput, 'width', Math.min(maxWidth, textWidth) + 'px');
|
|
||||||
}
|
|
||||||
|
|
||||||
private setDeviceName(): void {
|
|
||||||
if (this.deviceName) {
|
|
||||||
this.renderer.setProperty(this.deviceName.nativeElement, 'value', this.state.deviceName);
|
|
||||||
this.calculateHeaderTextWidth(this.deviceName.nativeElement.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { AfterViewInit, Component, EventEmitter, forwardRef, Input, Output, OnDestroy, ViewChild } from '@angular/core';
|
import { AfterViewInit, Component, EventEmitter, forwardRef, Input, Output, OnDestroy, ViewChild } from '@angular/core';
|
||||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||||
import { NouisliderComponent } from 'ng2-nouislider/src/nouislider';
|
import { NouisliderComponent } from 'ng2-nouislider';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { Observer } from 'rxjs/Observer';
|
import { Observer } from 'rxjs/Observer';
|
||||||
import 'rxjs/add/operator/debounceTime';
|
import 'rxjs/add/operator/debounceTime';
|
||||||
|
|||||||
@@ -1,5 +1,17 @@
|
|||||||
<div class="wrapper">
|
<div class="x-term-container">
|
||||||
|
<div class="x-term-wrapper" #scrollMe>
|
||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled">
|
||||||
<li *ngFor="let log of logs" [ngClass]="log.cssClass"><span>{{ log.message }}</span></li>
|
<li *ngFor="let log of logs" [ngClass]="log.cssClass"><span>{{ log.message }}</span></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="copy-container-wrapper">
|
||||||
|
<div class="copy-container">
|
||||||
|
<span class="fa fa-2x fa-copy"
|
||||||
|
ngxClipboard
|
||||||
|
[cbContent]="getClipboardContent()"
|
||||||
|
title="Copy to clipboard"
|
||||||
|
data-toggle="tooltip"
|
||||||
|
data-placement="top"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,9 +1,36 @@
|
|||||||
|
$scrollbar-color: #ffffff;
|
||||||
|
$scrollbar-radius: 6px;
|
||||||
|
|
||||||
:host {
|
:host {
|
||||||
background-color: yellow;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wrapper {
|
.x-term-container {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.x-term-wrapper {
|
||||||
background-color: black;
|
background-color: black;
|
||||||
|
overflow: auto;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-container-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
right: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.xterm-standard {
|
.xterm-standard {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, ElementRef, Input, OnChanges, SimpleChanges, ViewChild } from '@angular/core';
|
||||||
import { XtermLog } from '../../models/xterm-log';
|
import { XtermLog } from '../../models/xterm-log';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -7,6 +7,21 @@ import { XtermLog } from '../../models/xterm-log';
|
|||||||
styleUrls: ['./xterm.component.scss'],
|
styleUrls: ['./xterm.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class XtermComponent {
|
export class XtermComponent implements OnChanges {
|
||||||
@Input() logs: Array<XtermLog> = [];
|
@Input() logs: Array<XtermLog> = [];
|
||||||
|
|
||||||
|
@ViewChild('scrollMe') divElement: ElementRef;
|
||||||
|
|
||||||
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
|
if (changes.logs && this.divElement && this.divElement.nativeElement) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.divElement.nativeElement.scrollTop = this.divElement.nativeElement.scrollHeight;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getClipboardContent(): string {
|
||||||
|
return this.logs.reduce((value, line) => value + line.message + '\n', '');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { HardwareModules } from 'uhk-common';
|
||||||
|
|
||||||
|
export interface FirmwareUpgradeError {
|
||||||
|
error: any;
|
||||||
|
modules?: HardwareModules;
|
||||||
|
}
|
||||||
@@ -46,6 +46,10 @@ export class DeviceRendererService {
|
|||||||
this.ipcRenderer.send(IpcEvents.device.startConnectionPoller);
|
this.ipcRenderer.send(IpcEvents.device.startConnectionPoller);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
recoveryDevice(): void {
|
||||||
|
this.ipcRenderer.send(IpcEvents.device.recoveryDevice);
|
||||||
|
}
|
||||||
|
|
||||||
private registerEvents(): void {
|
private registerEvents(): void {
|
||||||
this.ipcRenderer.on(IpcEvents.device.deviceConnectionStateChanged, (event: string, arg: DeviceConnectionState) => {
|
this.ipcRenderer.on(IpcEvents.device.deviceConnectionStateChanged, (event: string, arg: DeviceConnectionState) => {
|
||||||
this.dispachStoreAction(new ConnectionStateChangedAction(arg));
|
this.dispachStoreAction(new ConnectionStateChangedAction(arg));
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { CanActivate, Router } from '@angular/router';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
import 'rxjs/add/operator/do';
|
||||||
|
import 'rxjs/add/operator/map';
|
||||||
|
|
||||||
|
import { AppState, bootloaderActive } from '../store';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class UhkDeviceBootloaderNotActiveGuard implements CanActivate {
|
||||||
|
|
||||||
|
constructor(private store: Store<AppState>, private router: Router) { }
|
||||||
|
|
||||||
|
canActivate(): Observable<boolean> {
|
||||||
|
return this.store.select(bootloaderActive)
|
||||||
|
.do(active => {
|
||||||
|
if (!active) {
|
||||||
|
this.router.navigate(['/']);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,11 +7,11 @@
|
|||||||
"iconsAndLayerTextsBrightness": 255,
|
"iconsAndLayerTextsBrightness": 255,
|
||||||
"alphanumericSegmentsBrightness": 255,
|
"alphanumericSegmentsBrightness": 255,
|
||||||
"keyBacklightBrightness": 255,
|
"keyBacklightBrightness": 255,
|
||||||
"mouseMoveInitialSpeed": 5,
|
"mouseMoveInitialSpeed": 4,
|
||||||
"mouseMoveAcceleration": 35,
|
"mouseMoveAcceleration": 68,
|
||||||
"mouseMoveDeceleratedSpeed": 10,
|
"mouseMoveDeceleratedSpeed": 8,
|
||||||
"mouseMoveBaseSpeed": 40,
|
"mouseMoveBaseSpeed": 32,
|
||||||
"mouseMoveAcceleratedSpeed": 80,
|
"mouseMoveAcceleratedSpeed": 64,
|
||||||
"mouseScrollInitialSpeed": 20,
|
"mouseScrollInitialSpeed": 20,
|
||||||
"mouseScrollAcceleration": 20,
|
"mouseScrollAcceleration": 20,
|
||||||
"mouseScrollDeceleratedSpeed": 20,
|
"mouseScrollDeceleratedSpeed": 20,
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ import {
|
|||||||
DeviceFirmwareComponent,
|
DeviceFirmwareComponent,
|
||||||
MouseSpeedComponent,
|
MouseSpeedComponent,
|
||||||
LEDBrightnessComponent,
|
LEDBrightnessComponent,
|
||||||
RestoreConfigurationComponent
|
RestoreConfigurationComponent,
|
||||||
|
RecoveryModeComponent
|
||||||
} from './components/device';
|
} from './components/device';
|
||||||
import { KeymapAddComponent, KeymapEditComponent, KeymapHeaderComponent } from './components/keymap';
|
import { KeymapAddComponent, KeymapEditComponent, KeymapHeaderComponent } from './components/keymap';
|
||||||
import { LayersComponent } from './components/layers';
|
import { LayersComponent } from './components/layers';
|
||||||
@@ -105,6 +106,9 @@ import { XtermComponent } from './components/xterm/xterm.component';
|
|||||||
import { SliderWrapperComponent } from './components/slider-wrapper/slider-wrapper.component';
|
import { SliderWrapperComponent } from './components/slider-wrapper/slider-wrapper.component';
|
||||||
import { EditableTextComponent } from './components/editable-text/editable-text.component';
|
import { EditableTextComponent } from './components/editable-text/editable-text.component';
|
||||||
import { Autofocus } from './directives/autofocus/autofocus.directive';
|
import { Autofocus } from './directives/autofocus/autofocus.directive';
|
||||||
|
import { UhkDeviceBootloaderNotActiveGuard } from './services/uhk-device-bootloader-not-active.guard';
|
||||||
|
import { FileUploadComponent } from './components/file-upload';
|
||||||
|
import { AutoGrowInputComponent } from './components/auto-grow-input';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@@ -176,7 +180,10 @@ import { Autofocus } from './directives/autofocus/autofocus.directive';
|
|||||||
SliderWrapperComponent,
|
SliderWrapperComponent,
|
||||||
EditableTextComponent,
|
EditableTextComponent,
|
||||||
Autofocus,
|
Autofocus,
|
||||||
RestoreConfigurationComponent
|
RestoreConfigurationComponent,
|
||||||
|
RecoveryModeComponent,
|
||||||
|
FileUploadComponent,
|
||||||
|
AutoGrowInputComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
@@ -211,7 +218,8 @@ import { Autofocus } from './directives/autofocus/autofocus.directive';
|
|||||||
UhkDeviceInitializedGuard,
|
UhkDeviceInitializedGuard,
|
||||||
UhkDeviceUninitializedGuard,
|
UhkDeviceUninitializedGuard,
|
||||||
UhkDeviceLoadingGuard,
|
UhkDeviceLoadingGuard,
|
||||||
UhkDeviceLoadedGuard
|
UhkDeviceLoadedGuard,
|
||||||
|
UhkDeviceBootloaderNotActiveGuard
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
UhkMessageComponent,
|
UhkMessageComponent,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Action } from '@ngrx/store';
|
import { Action } from '@ngrx/store';
|
||||||
import { DeviceConnectionState, HardwareModules, IpcResponse, type } from 'uhk-common';
|
import { DeviceConnectionState, FirmwareUpgradeIpcResponse, HardwareModules, IpcResponse, type } from 'uhk-common';
|
||||||
|
import { FirmwareUpgradeError } from '../../models/firmware-upgrade-error';
|
||||||
|
|
||||||
const PREFIX = '[device] ';
|
const PREFIX = '[device] ';
|
||||||
|
|
||||||
@@ -26,7 +27,8 @@ export const ActionTypes = {
|
|||||||
MODULES_INFO_LOADED: type(PREFIX + 'module info loaded'),
|
MODULES_INFO_LOADED: type(PREFIX + 'module info loaded'),
|
||||||
HAS_BACKUP_USER_CONFIGURATION: type(PREFIX + 'Store backup user configuration'),
|
HAS_BACKUP_USER_CONFIGURATION: type(PREFIX + 'Store backup user configuration'),
|
||||||
RESTORE_CONFIGURATION_FROM_BACKUP: type(PREFIX + 'Restore configuration from backup'),
|
RESTORE_CONFIGURATION_FROM_BACKUP: type(PREFIX + 'Restore configuration from backup'),
|
||||||
RESTORE_CONFIGURATION_FROM_BACKUP_SUCCESS: type(PREFIX + 'Restore configuration from backup success')
|
RESTORE_CONFIGURATION_FROM_BACKUP_SUCCESS: type(PREFIX + 'Restore configuration from backup success'),
|
||||||
|
RECOVERY_DEVICE: type(PREFIX + 'Recovery device')
|
||||||
};
|
};
|
||||||
|
|
||||||
export class SetPrivilegeOnLinuxAction implements Action {
|
export class SetPrivilegeOnLinuxAction implements Action {
|
||||||
@@ -95,25 +97,23 @@ export class UpdateFirmwareWithAction implements Action {
|
|||||||
export class UpdateFirmwareReplyAction implements Action {
|
export class UpdateFirmwareReplyAction implements Action {
|
||||||
type = ActionTypes.UPDATE_FIRMWARE_REPLY;
|
type = ActionTypes.UPDATE_FIRMWARE_REPLY;
|
||||||
|
|
||||||
constructor(public payload: IpcResponse) {
|
constructor(public payload: FirmwareUpgradeIpcResponse) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UpdateFirmwareSuccessAction implements Action {
|
export class UpdateFirmwareSuccessAction implements Action {
|
||||||
type = ActionTypes.UPDATE_FIRMWARE_SUCCESS;
|
type = ActionTypes.UPDATE_FIRMWARE_SUCCESS;
|
||||||
|
constructor(public payload: HardwareModules) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UpdateFirmwareFailedAction implements Action {
|
export class UpdateFirmwareFailedAction implements Action {
|
||||||
type = ActionTypes.UPDATE_FIRMWARE_FAILED;
|
type = ActionTypes.UPDATE_FIRMWARE_FAILED;
|
||||||
|
|
||||||
constructor(public payload: any) {
|
constructor(public payload: FirmwareUpgradeError) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UpdateFirmwareOkButtonAction implements Action {
|
|
||||||
type = ActionTypes.UPDATE_FIRMWARE_OK_BUTTON;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ResetMouseSpeedSettingsAction implements Action {
|
export class ResetMouseSpeedSettingsAction implements Action {
|
||||||
type = ActionTypes.RESET_MOUSE_SPEED_SETTINGS;
|
type = ActionTypes.RESET_MOUSE_SPEED_SETTINGS;
|
||||||
}
|
}
|
||||||
@@ -140,6 +140,10 @@ export class RestoreUserConfigurationFromBackupSuccessAction implements Action {
|
|||||||
type = ActionTypes.RESTORE_CONFIGURATION_FROM_BACKUP_SUCCESS;
|
type = ActionTypes.RESTORE_CONFIGURATION_FROM_BACKUP_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class RecoveryDeviceAction implements Action {
|
||||||
|
type = ActionTypes.RECOVERY_DEVICE;
|
||||||
|
}
|
||||||
|
|
||||||
export type Actions
|
export type Actions
|
||||||
= SetPrivilegeOnLinuxAction
|
= SetPrivilegeOnLinuxAction
|
||||||
| SetPrivilegeOnLinuxReplyAction
|
| SetPrivilegeOnLinuxReplyAction
|
||||||
@@ -157,9 +161,9 @@ export type Actions
|
|||||||
| UpdateFirmwareReplyAction
|
| UpdateFirmwareReplyAction
|
||||||
| UpdateFirmwareSuccessAction
|
| UpdateFirmwareSuccessAction
|
||||||
| UpdateFirmwareFailedAction
|
| UpdateFirmwareFailedAction
|
||||||
| UpdateFirmwareOkButtonAction
|
|
||||||
| HardwareModulesLoadedAction
|
| HardwareModulesLoadedAction
|
||||||
| RestoreUserConfigurationFromBackupAction
|
| RestoreUserConfigurationFromBackupAction
|
||||||
| HasBackupUserConfigurationAction
|
| HasBackupUserConfigurationAction
|
||||||
| RestoreUserConfigurationFromBackupSuccessAction
|
| RestoreUserConfigurationFromBackupSuccessAction
|
||||||
|
| RecoveryDeviceAction
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ export class ApplicationEffects {
|
|||||||
new ApplyCommandLineArgsAction(appInfo.commandLineArgs),
|
new ApplyCommandLineArgsAction(appInfo.commandLineArgs),
|
||||||
new ConnectionStateChangedAction({
|
new ConnectionStateChangedAction({
|
||||||
connected: appInfo.deviceConnected,
|
connected: appInfo.deviceConnected,
|
||||||
hasPermission: appInfo.hasPermission
|
hasPermission: appInfo.hasPermission,
|
||||||
|
bootloaderActive: appInfo.bootloaderActive
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import 'rxjs/add/operator/withLatestFrom';
|
|||||||
import 'rxjs/add/operator/switchMap';
|
import 'rxjs/add/operator/switchMap';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
DeviceConnectionState,
|
FirmwareUpgradeIpcResponse,
|
||||||
HardwareConfiguration,
|
HardwareConfiguration,
|
||||||
IpcResponse,
|
IpcResponse,
|
||||||
NotificationType,
|
NotificationType,
|
||||||
@@ -24,6 +24,7 @@ import {
|
|||||||
ActionTypes,
|
ActionTypes,
|
||||||
ConnectionStateChangedAction,
|
ConnectionStateChangedAction,
|
||||||
HideSaveToKeyboardButton,
|
HideSaveToKeyboardButton,
|
||||||
|
RecoveryDeviceAction,
|
||||||
ResetUserConfigurationAction,
|
ResetUserConfigurationAction,
|
||||||
RestoreUserConfigurationFromBackupSuccessAction,
|
RestoreUserConfigurationFromBackupSuccessAction,
|
||||||
SaveConfigurationAction,
|
SaveConfigurationAction,
|
||||||
@@ -33,14 +34,13 @@ import {
|
|||||||
SetPrivilegeOnLinuxReplyAction,
|
SetPrivilegeOnLinuxReplyAction,
|
||||||
UpdateFirmwareAction,
|
UpdateFirmwareAction,
|
||||||
UpdateFirmwareFailedAction,
|
UpdateFirmwareFailedAction,
|
||||||
UpdateFirmwareOkButtonAction,
|
|
||||||
UpdateFirmwareReplyAction,
|
UpdateFirmwareReplyAction,
|
||||||
UpdateFirmwareSuccessAction,
|
UpdateFirmwareSuccessAction,
|
||||||
UpdateFirmwareWithAction
|
UpdateFirmwareWithAction
|
||||||
} from '../actions/device';
|
} from '../actions/device';
|
||||||
import { DeviceRendererService } from '../../services/device-renderer.service';
|
import { DeviceRendererService } from '../../services/device-renderer.service';
|
||||||
import { SetupPermissionErrorAction, ShowNotificationAction } from '../actions/app';
|
import { SetupPermissionErrorAction, ShowNotificationAction } from '../actions/app';
|
||||||
import { AppState } from '../index';
|
import { AppState, getRouterState } from '../index';
|
||||||
import {
|
import {
|
||||||
ActionTypes as UserConfigActions,
|
ActionTypes as UserConfigActions,
|
||||||
ApplyUserConfigurationFromFileAction,
|
ApplyUserConfigurationFromFileAction,
|
||||||
@@ -55,11 +55,20 @@ export class DeviceEffects {
|
|||||||
@Effect()
|
@Effect()
|
||||||
deviceConnectionStateChange$: Observable<Action> = this.actions$
|
deviceConnectionStateChange$: Observable<Action> = this.actions$
|
||||||
.ofType<ConnectionStateChangedAction>(ActionTypes.CONNECTION_STATE_CHANGED)
|
.ofType<ConnectionStateChangedAction>(ActionTypes.CONNECTION_STATE_CHANGED)
|
||||||
.map(action => action.payload)
|
.withLatestFrom(this.store.select(getRouterState))
|
||||||
.do((state: DeviceConnectionState) => {
|
.do(([action, route]) => {
|
||||||
|
const state = action.payload;
|
||||||
|
|
||||||
|
if (route.state && route.state.url.startsWith('/device/firmware')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!state.hasPermission) {
|
if (!state.hasPermission) {
|
||||||
this.router.navigate(['/privilege']);
|
this.router.navigate(['/privilege']);
|
||||||
}
|
}
|
||||||
|
else if (state.bootloaderActive) {
|
||||||
|
this.router.navigate(['/recovery-device']);
|
||||||
|
}
|
||||||
else if (state.connected) {
|
else if (state.connected) {
|
||||||
this.router.navigate(['/']);
|
this.router.navigate(['/']);
|
||||||
}
|
}
|
||||||
@@ -67,7 +76,9 @@ export class DeviceEffects {
|
|||||||
this.router.navigate(['/detection']);
|
this.router.navigate(['/detection']);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.switchMap((state: DeviceConnectionState) => {
|
.switchMap(([action, route]) => {
|
||||||
|
const state = action.payload;
|
||||||
|
|
||||||
if (state.connected && state.hasPermission) {
|
if (state.connected && state.hasPermission) {
|
||||||
return Observable.of(new LoadConfigFromDeviceAction());
|
return Observable.of(new LoadConfigFromDeviceAction());
|
||||||
}
|
}
|
||||||
@@ -90,7 +101,8 @@ export class DeviceEffects {
|
|||||||
if (response.success) {
|
if (response.success) {
|
||||||
return new ConnectionStateChangedAction({
|
return new ConnectionStateChangedAction({
|
||||||
connected: true,
|
connected: true,
|
||||||
hasPermission: true
|
hasPermission: true,
|
||||||
|
bootloaderActive: false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,22 +210,26 @@ export class DeviceEffects {
|
|||||||
@Effect() updateFirmwareReply$ = this.actions$
|
@Effect() updateFirmwareReply$ = this.actions$
|
||||||
.ofType<UpdateFirmwareReplyAction>(ActionTypes.UPDATE_FIRMWARE_REPLY)
|
.ofType<UpdateFirmwareReplyAction>(ActionTypes.UPDATE_FIRMWARE_REPLY)
|
||||||
.map(action => action.payload)
|
.map(action => action.payload)
|
||||||
.switchMap((response: IpcResponse) => {
|
.switchMap((response: FirmwareUpgradeIpcResponse)
|
||||||
|
: Observable<UpdateFirmwareSuccessAction | UpdateFirmwareFailedAction> => {
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
return Observable.of(new UpdateFirmwareSuccessAction());
|
return Observable.of(new UpdateFirmwareSuccessAction(response.modules));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Observable.of(new UpdateFirmwareFailedAction(response.error));
|
return Observable.of(new UpdateFirmwareFailedAction({
|
||||||
|
error: response.error,
|
||||||
|
modules: response.modules
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
@Effect({dispatch: false}) updateFirmwareOkButton$ = this.actions$
|
|
||||||
.ofType<UpdateFirmwareOkButtonAction>(ActionTypes.UPDATE_FIRMWARE_OK_BUTTON)
|
|
||||||
.do(() => this.deviceRendererService.startConnectionPoller());
|
|
||||||
|
|
||||||
@Effect() restoreUserConfiguration$ = this.actions$
|
@Effect() restoreUserConfiguration$ = this.actions$
|
||||||
.ofType<ResetUserConfigurationAction>(ActionTypes.RESTORE_CONFIGURATION_FROM_BACKUP)
|
.ofType<ResetUserConfigurationAction>(ActionTypes.RESTORE_CONFIGURATION_FROM_BACKUP)
|
||||||
.map(() => new SaveConfigurationAction());
|
.map(() => new SaveConfigurationAction());
|
||||||
|
|
||||||
|
@Effect({dispatch: false}) recoveryDevice$ = this.actions$
|
||||||
|
.ofType<RecoveryDeviceAction>(ActionTypes.RECOVERY_DEVICE)
|
||||||
|
.do(() => this.deviceRendererService.recoveryDevice());
|
||||||
|
|
||||||
constructor(private actions$: Actions,
|
constructor(private actions$: Actions,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private deviceRendererService: DeviceRendererService,
|
private deviceRendererService: DeviceRendererService,
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ import {
|
|||||||
|
|
||||||
import { DataStorageRepositoryService } from '../../services/datastorage-repository.service';
|
import { DataStorageRepositoryService } from '../../services/datastorage-repository.service';
|
||||||
import { DefaultUserConfigurationService } from '../../services/default-user-configuration.service';
|
import { DefaultUserConfigurationService } from '../../services/default-user-configuration.service';
|
||||||
import { AppState, getPrevUserConfiguration, getUserConfiguration } from '../index';
|
import { AppState, getPrevUserConfiguration, getRouterState, getUserConfiguration } from '../index';
|
||||||
import { KeymapAction, KeymapActions, MacroAction, MacroActions } from '../actions';
|
import { KeymapAction, KeymapActions, MacroAction, MacroActions } from '../actions';
|
||||||
import {
|
import {
|
||||||
DismissUndoNotificationAction,
|
DismissUndoNotificationAction,
|
||||||
@@ -118,8 +118,10 @@ export class UserConfigEffects {
|
|||||||
|
|
||||||
@Effect() loadConfigFromDeviceReply$ = this.actions$
|
@Effect() loadConfigFromDeviceReply$ = this.actions$
|
||||||
.ofType<LoadConfigFromDeviceReplyAction>(ActionTypes.LOAD_CONFIG_FROM_DEVICE_REPLY)
|
.ofType<LoadConfigFromDeviceReplyAction>(ActionTypes.LOAD_CONFIG_FROM_DEVICE_REPLY)
|
||||||
.map(action => action.payload)
|
.withLatestFrom(this.store.select(getRouterState))
|
||||||
.mergeMap((data: ConfigurationReply): any => {
|
.mergeMap(([action, route]): any => {
|
||||||
|
const data: ConfigurationReply = action.payload;
|
||||||
|
|
||||||
if (!data.success) {
|
if (!data.success) {
|
||||||
return [new ShowNotificationAction({
|
return [new ShowNotificationAction({
|
||||||
type: NotificationType.Error,
|
type: NotificationType.Error,
|
||||||
@@ -128,12 +130,16 @@ export class UserConfigEffects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const result = [];
|
const result = [];
|
||||||
let newPageDestination = ['/'];
|
let newPageDestination: Array<string>;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const userConfig = getUserConfigFromDeviceResponse(data.userConfiguration);
|
const userConfig = getUserConfigFromDeviceResponse(data.userConfiguration);
|
||||||
result.push(new LoadUserConfigSuccessAction(userConfig));
|
result.push(new LoadUserConfigSuccessAction(userConfig));
|
||||||
|
|
||||||
|
if (route.state && !route.state.url.startsWith('/device/firmware')) {
|
||||||
|
newPageDestination = ['/'];
|
||||||
|
}
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.logService.error('Eeprom user-config parse error:', err);
|
this.logService.error('Eeprom user-config parse error:', err);
|
||||||
const userConfig = new UserConfiguration().fromJsonObject(data.backupConfiguration);
|
const userConfig = new UserConfiguration().fromJsonObject(data.backupConfiguration);
|
||||||
@@ -158,7 +164,9 @@ export class UserConfigEffects {
|
|||||||
|
|
||||||
result.push(new HardwareModulesLoadedAction(data.modules));
|
result.push(new HardwareModulesLoadedAction(data.modules));
|
||||||
|
|
||||||
|
if (newPageDestination) {
|
||||||
this.router.navigate(newPageDestination);
|
this.router.navigate(newPageDestination);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { MetaReducer } from '@ngrx/store';
|
import { ActionReducerMap, MetaReducer } from '@ngrx/store';
|
||||||
import { RouterReducerState } from '@ngrx/router-store';
|
import { RouterReducerState, routerReducer } from '@ngrx/router-store';
|
||||||
import { storeFreeze } from 'ngrx-store-freeze';
|
import { storeFreeze } from 'ngrx-store-freeze';
|
||||||
import { Keymap, UserConfiguration } from 'uhk-common';
|
import { Keymap, UserConfiguration } from 'uhk-common';
|
||||||
|
|
||||||
@@ -14,15 +14,6 @@ import { initProgressButtonState } from './reducers/progress-button-state';
|
|||||||
import { environment } from '../../environments/environment';
|
import { environment } from '../../environments/environment';
|
||||||
import { RouterStateUrl } from './router-util';
|
import { RouterStateUrl } from './router-util';
|
||||||
|
|
||||||
export const reducers = {
|
|
||||||
userConfiguration: fromUserConfig.reducer,
|
|
||||||
presetKeymaps: fromPreset.reducer,
|
|
||||||
autoUpdateSettings: autoUpdateSettings.reducer,
|
|
||||||
app: fromApp.reducer,
|
|
||||||
appUpdate: fromAppUpdate.reducer,
|
|
||||||
device: fromDevice.reducer
|
|
||||||
};
|
|
||||||
|
|
||||||
// State interface for the application
|
// State interface for the application
|
||||||
export interface AppState {
|
export interface AppState {
|
||||||
userConfiguration: UserConfiguration;
|
userConfiguration: UserConfiguration;
|
||||||
@@ -34,6 +25,16 @@ export interface AppState {
|
|||||||
device: fromDevice.State;
|
device: fromDevice.State;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const reducers: ActionReducerMap<AppState> = {
|
||||||
|
userConfiguration: fromUserConfig.reducer,
|
||||||
|
presetKeymaps: fromPreset.reducer,
|
||||||
|
autoUpdateSettings: autoUpdateSettings.reducer,
|
||||||
|
app: fromApp.reducer,
|
||||||
|
router: routerReducer,
|
||||||
|
appUpdate: fromAppUpdate.reducer,
|
||||||
|
device: fromDevice.reducer
|
||||||
|
};
|
||||||
|
|
||||||
export const metaReducers: MetaReducer<AppState>[] = environment.production
|
export const metaReducers: MetaReducer<AppState>[] = environment.production
|
||||||
? []
|
? []
|
||||||
: [storeFreeze];
|
: [storeFreeze];
|
||||||
@@ -73,12 +74,12 @@ export const saveToKeyboardState = createSelector(runningInElectron, saveToKeybo
|
|||||||
});
|
});
|
||||||
export const updatingFirmware = createSelector(deviceState, fromDevice.updatingFirmware);
|
export const updatingFirmware = createSelector(deviceState, fromDevice.updatingFirmware);
|
||||||
export const xtermLog = createSelector(deviceState, fromDevice.xtermLog);
|
export const xtermLog = createSelector(deviceState, fromDevice.xtermLog);
|
||||||
export const firmwareOkButtonDisabled = createSelector(deviceState, fromDevice.firmwareOkButtonDisabled);
|
|
||||||
// tslint:disable-next-line: max-line-length
|
// tslint:disable-next-line: max-line-length
|
||||||
export const flashFirmwareButtonDisbabled = createSelector(runningInElectron, deviceState, (electron, state: fromDevice.State) => !electron || state.updatingFirmware);
|
export const flashFirmwareButtonDisbabled = createSelector(runningInElectron, deviceState, (electron, state: fromDevice.State) => !electron || state.updatingFirmware);
|
||||||
export const getHardwareModules = createSelector(deviceState, fromDevice.getHardwareModules);
|
export const getHardwareModules = createSelector(deviceState, fromDevice.getHardwareModules);
|
||||||
export const getBackupUserConfigurationState = createSelector(deviceState, fromDevice.getBackupUserConfigurationState);
|
export const getBackupUserConfigurationState = createSelector(deviceState, fromDevice.getBackupUserConfigurationState);
|
||||||
export const getRestoreUserConfiguration = createSelector(deviceState, fromDevice.getHasBackupUserConfiguration);
|
export const getRestoreUserConfiguration = createSelector(deviceState, fromDevice.getHasBackupUserConfiguration);
|
||||||
|
export const bootloaderActive = createSelector(deviceState, fromDevice.bootloaderActive);
|
||||||
|
|
||||||
export const getSideMenuPageState = createSelector(
|
export const getSideMenuPageState = createSelector(
|
||||||
showAddonMenu,
|
showAddonMenu,
|
||||||
@@ -102,3 +103,5 @@ export const getSideMenuPageState = createSelector(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const getRouterState = (state: AppState) => state.router;
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ import {
|
|||||||
HardwareModulesLoadedAction,
|
HardwareModulesLoadedAction,
|
||||||
SaveConfigurationAction,
|
SaveConfigurationAction,
|
||||||
HasBackupUserConfigurationAction,
|
HasBackupUserConfigurationAction,
|
||||||
UpdateFirmwareFailedAction
|
UpdateFirmwareFailedAction,
|
||||||
|
UpdateFirmwareSuccessAction
|
||||||
} from '../actions/device';
|
} from '../actions/device';
|
||||||
import { ActionTypes as AppActions, ElectronMainLogReceivedAction } from '../actions/app';
|
import { ActionTypes as AppActions, ElectronMainLogReceivedAction } from '../actions/app';
|
||||||
import { initProgressButtonState, ProgressButtonState } from './progress-button-state';
|
import { initProgressButtonState, ProgressButtonState } from './progress-button-state';
|
||||||
@@ -17,7 +18,9 @@ import { RestoreConfigurationState } from '../../models/restore-configuration-st
|
|||||||
export interface State {
|
export interface State {
|
||||||
connected: boolean;
|
connected: boolean;
|
||||||
hasPermission: boolean;
|
hasPermission: boolean;
|
||||||
|
bootloaderActive: boolean;
|
||||||
saveToKeyboard: ProgressButtonState;
|
saveToKeyboard: ProgressButtonState;
|
||||||
|
savingToKeyboard: boolean;
|
||||||
updatingFirmware: boolean;
|
updatingFirmware: boolean;
|
||||||
firmwareUpdateFinished: boolean;
|
firmwareUpdateFinished: boolean;
|
||||||
modules: HardwareModules;
|
modules: HardwareModules;
|
||||||
@@ -29,7 +32,9 @@ export interface State {
|
|||||||
export const initialState: State = {
|
export const initialState: State = {
|
||||||
connected: true,
|
connected: true,
|
||||||
hasPermission: true,
|
hasPermission: true,
|
||||||
|
bootloaderActive: false,
|
||||||
saveToKeyboard: initProgressButtonState,
|
saveToKeyboard: initProgressButtonState,
|
||||||
|
savingToKeyboard: false,
|
||||||
updatingFirmware: false,
|
updatingFirmware: false,
|
||||||
firmwareUpdateFinished: false,
|
firmwareUpdateFinished: false,
|
||||||
modules: {
|
modules: {
|
||||||
@@ -46,14 +51,15 @@ export const initialState: State = {
|
|||||||
hasBackupUserConfiguration: false
|
hasBackupUserConfiguration: false
|
||||||
};
|
};
|
||||||
|
|
||||||
export function reducer(state = initialState, action: Action) {
|
export function reducer(state = initialState, action: Action): State {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ActionTypes.CONNECTION_STATE_CHANGED: {
|
case ActionTypes.CONNECTION_STATE_CHANGED: {
|
||||||
const data = (<ConnectionStateChangedAction>action).payload;
|
const data = (<ConnectionStateChangedAction>action).payload;
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
connected: data.connected,
|
connected: data.connected,
|
||||||
hasPermission: data.hasPermission
|
hasPermission: data.hasPermission,
|
||||||
|
bootloaderActive: data.bootloaderActive
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,12 +135,14 @@ export function reducer(state = initialState, action: Action) {
|
|||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
updatingFirmware: false,
|
updatingFirmware: false,
|
||||||
firmwareUpdateFinished: true
|
firmwareUpdateFinished: true,
|
||||||
|
modules: (action as UpdateFirmwareSuccessAction).payload
|
||||||
};
|
};
|
||||||
|
|
||||||
case ActionTypes.UPDATE_FIRMWARE_FAILED: {
|
case ActionTypes.UPDATE_FIRMWARE_FAILED: {
|
||||||
|
const data = (action as UpdateFirmwareFailedAction).payload;
|
||||||
const logEntry = {
|
const logEntry = {
|
||||||
message: (action as UpdateFirmwareFailedAction).payload.message,
|
message: data.error.message,
|
||||||
cssClass: XtermCssClass.error
|
cssClass: XtermCssClass.error
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -142,6 +150,7 @@ export function reducer(state = initialState, action: Action) {
|
|||||||
...state,
|
...state,
|
||||||
updatingFirmware: false,
|
updatingFirmware: false,
|
||||||
firmwareUpdateFinished: true,
|
firmwareUpdateFinished: true,
|
||||||
|
modules: data.modules,
|
||||||
log: [...state.log, logEntry]
|
log: [...state.log, logEntry]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -193,6 +202,13 @@ export function reducer(state = initialState, action: Action) {
|
|||||||
hasBackupUserConfiguration: false
|
hasBackupUserConfiguration: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
case ActionTypes.RECOVERY_DEVICE: {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
updatingFirmware: true,
|
||||||
|
log: [{message: '', cssClass: XtermCssClass.standard}]
|
||||||
|
};
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
@@ -203,7 +219,6 @@ export const isDeviceConnected = (state: State) => state.connected || state.upda
|
|||||||
export const hasDevicePermission = (state: State) => state.hasPermission;
|
export const hasDevicePermission = (state: State) => state.hasPermission;
|
||||||
export const getSaveToKeyboardState = (state: State) => state.saveToKeyboard;
|
export const getSaveToKeyboardState = (state: State) => state.saveToKeyboard;
|
||||||
export const xtermLog = (state: State) => state.log;
|
export const xtermLog = (state: State) => state.log;
|
||||||
export const firmwareOkButtonDisabled = (state: State) => !state.firmwareUpdateFinished;
|
|
||||||
export const getHardwareModules = (state: State) => state.modules;
|
export const getHardwareModules = (state: State) => state.modules;
|
||||||
export const getHasBackupUserConfiguration = (state: State) => state.hasBackupUserConfiguration;
|
export const getHasBackupUserConfiguration = (state: State) => state.hasBackupUserConfiguration;
|
||||||
export const getBackupUserConfigurationState = (state: State): RestoreConfigurationState => {
|
export const getBackupUserConfigurationState = (state: State): RestoreConfigurationState => {
|
||||||
@@ -212,3 +227,4 @@ export const getBackupUserConfigurationState = (state: State): RestoreConfigurat
|
|||||||
hasBackupUserConfiguration: state.hasBackupUserConfiguration
|
hasBackupUserConfiguration: state.hasBackupUserConfiguration
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
export const bootloaderActive = (state: State) => state.bootloaderActive;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Action } from '@ngrx/store';
|
|||||||
export interface ProgressButtonState {
|
export interface ProgressButtonState {
|
||||||
showButton: boolean;
|
showButton: boolean;
|
||||||
text: string;
|
text: string;
|
||||||
showProgress: boolean;
|
showProgress?: boolean;
|
||||||
action?: Action;
|
action?: Action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
@import '~font-awesome/scss/font-awesome';
|
@import '~font-awesome/scss/font-awesome';
|
||||||
@import './styles/tooltip';
|
@import './styles/tooltip';
|
||||||
@import './styles/uhk-icons/uhk-icon';
|
@import './styles/uhk-icons/uhk-icon';
|
||||||
|
@import './styles/side-menu';
|
||||||
|
|
||||||
html, body {
|
html, body {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -155,3 +156,25 @@ pre {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.flex-container {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-grow {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-footer {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ok-button {
|
||||||
|
min-width: 100px;
|
||||||
|
}
|
||||||
|
|||||||
22
packages/uhk-web/src/styles/_side-menu.scss
Normal file
22
packages/uhk-web/src/styles/_side-menu.scss
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
.side-menu-pane-title {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
|
||||||
|
&__name {
|
||||||
|
border: none;
|
||||||
|
border-bottom: 2px dotted #999;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0 0.25rem;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
background-color: transparent;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
box-shadow: 0 0 0 1px #ccc, 0 0 5px 0 #ccc;
|
||||||
|
border-color: transparent;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
8
packages/usb/erase-hardware-config.js
Executable file
8
packages/usb/erase-hardware-config.js
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
const uhk = require('./uhk');
|
||||||
|
|
||||||
|
const device = uhk.getUhkDevice();
|
||||||
|
uhk.eraseHca(device)
|
||||||
|
.catch((err)=>{
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
10
packages/usb/erase-user-config.js
Executable file
10
packages/usb/erase-user-config.js
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
const fs = require('fs');
|
||||||
|
const uhk = require('./uhk');
|
||||||
|
|
||||||
|
(async function() {
|
||||||
|
const device = uhk.getUhkDevice();
|
||||||
|
const buffer = new Buffer(Array(2**15-64).fill(0xff));
|
||||||
|
await uhk.writeConfig(device, buffer, false);
|
||||||
|
await uhk.launchEepromTransfer(device, uhk.eepromOperations.write, uhk.configBufferIds.stagingUserConfig);
|
||||||
|
})();
|
||||||
@@ -11,4 +11,24 @@ const firmwareMajorVersion = uhk.getUint16(response, 1);
|
|||||||
const firmwareMinorVersion = uhk.getUint16(response, 3);
|
const firmwareMinorVersion = uhk.getUint16(response, 3);
|
||||||
const firmwarePatchVersion = uhk.getUint16(response, 5);
|
const firmwarePatchVersion = uhk.getUint16(response, 5);
|
||||||
|
|
||||||
|
const deviceProtocolMajorVersion = uhk.getUint16(response, 7);
|
||||||
|
const deviceProtocolMinorVersion = uhk.getUint16(response, 9);
|
||||||
|
const deviceProtocolPatchVersion = uhk.getUint16(response, 11);
|
||||||
|
|
||||||
|
const moduleProtocolMajorVersion = uhk.getUint16(response, 13);
|
||||||
|
const moduleProtocolMinorVersion = uhk.getUint16(response, 15);
|
||||||
|
const moduleProtocolPatchVersion = uhk.getUint16(response, 17);
|
||||||
|
|
||||||
|
const userConfigMajorVersion = uhk.getUint16(response, 19);
|
||||||
|
const userConfigMinorVersion = uhk.getUint16(response, 21);
|
||||||
|
const userConfigPatchVersion = uhk.getUint16(response, 23);
|
||||||
|
|
||||||
|
const hardwareConfigMajorVersion = uhk.getUint16(response, 25);
|
||||||
|
const hardwareConfigMinorVersion = uhk.getUint16(response, 27);
|
||||||
|
const hardwareConfigPatchVersion = uhk.getUint16(response, 29);
|
||||||
|
|
||||||
console.log(`firmwareVersion: ${firmwareMajorVersion}.${firmwareMinorVersion}.${firmwarePatchVersion}`);
|
console.log(`firmwareVersion: ${firmwareMajorVersion}.${firmwareMinorVersion}.${firmwarePatchVersion}`);
|
||||||
|
console.log(`deviceProtocolVersion: ${deviceProtocolMajorVersion}.${deviceProtocolMinorVersion}.${deviceProtocolPatchVersion}`);
|
||||||
|
console.log(`moduleProtocolVersion: ${moduleProtocolMajorVersion}.${moduleProtocolMinorVersion}.${moduleProtocolPatchVersion}`);
|
||||||
|
console.log(`userConfigVersion: ${userConfigMajorVersion}.${userConfigMinorVersion}.${userConfigPatchVersion}`);
|
||||||
|
console.log(`hardwareConfigVersion: ${hardwareConfigMajorVersion}.${hardwareConfigMinorVersion}.${hardwareConfigPatchVersion}`);
|
||||||
|
|||||||
135
packages/usb/package-lock.json
generated
135
packages/usb/package-lock.json
generated
@@ -13,11 +13,11 @@
|
|||||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
|
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
|
||||||
},
|
},
|
||||||
"ansi-styles": {
|
"ansi-styles": {
|
||||||
"version": "3.2.0",
|
"version": "3.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||||
"integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
|
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"color-convert": "1.9.0"
|
"color-convert": "1.9.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"aproba": {
|
"aproba": {
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
"integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=",
|
"integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"delegates": "1.0.0",
|
"delegates": "1.0.0",
|
||||||
"readable-stream": "2.3.3"
|
"readable-stream": "2.3.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
@@ -50,17 +50,18 @@
|
|||||||
"integrity": "sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw=="
|
"integrity": "sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw=="
|
||||||
},
|
},
|
||||||
"bl": {
|
"bl": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/bl/-/bl-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
|
||||||
"integrity": "sha1-ysMo977kVzDUBLaSID/LWQ4XLV4=",
|
"integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"readable-stream": "2.3.3"
|
"readable-stream": "2.3.6",
|
||||||
|
"safe-buffer": "5.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.8",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
"integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
|
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"balanced-match": "1.0.0",
|
"balanced-match": "1.0.0",
|
||||||
"concat-map": "0.0.1"
|
"concat-map": "0.0.1"
|
||||||
@@ -72,7 +73,7 @@
|
|||||||
"integrity": "sha1-pyyTb3e5a/UvX357RnGAYoVR3vs=",
|
"integrity": "sha1-pyyTb3e5a/UvX357RnGAYoVR3vs=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"base64-js": "0.0.8",
|
"base64-js": "0.0.8",
|
||||||
"ieee754": "1.1.8",
|
"ieee754": "1.1.11",
|
||||||
"isarray": "1.0.0"
|
"isarray": "1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -86,9 +87,9 @@
|
|||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz",
|
||||||
"integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==",
|
"integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"ansi-styles": "3.2.0",
|
"ansi-styles": "3.2.1",
|
||||||
"escape-string-regexp": "1.0.5",
|
"escape-string-regexp": "1.0.5",
|
||||||
"supports-color": "4.4.0"
|
"supports-color": "4.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"chownr": {
|
"chownr": {
|
||||||
@@ -102,9 +103,9 @@
|
|||||||
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
|
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
|
||||||
},
|
},
|
||||||
"color-convert": {
|
"color-convert": {
|
||||||
"version": "1.9.0",
|
"version": "1.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz",
|
||||||
"integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=",
|
"integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"color-name": "1.1.3"
|
"color-name": "1.1.3"
|
||||||
}
|
}
|
||||||
@@ -115,9 +116,9 @@
|
|||||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
|
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
|
||||||
},
|
},
|
||||||
"commander": {
|
"commander": {
|
||||||
"version": "2.11.0",
|
"version": "2.15.1",
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
|
||||||
"integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ=="
|
"integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag=="
|
||||||
},
|
},
|
||||||
"concat-map": {
|
"concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
@@ -144,7 +145,7 @@
|
|||||||
"decompress-targz": "4.1.1",
|
"decompress-targz": "4.1.1",
|
||||||
"decompress-unzip": "4.0.1",
|
"decompress-unzip": "4.0.1",
|
||||||
"graceful-fs": "4.1.11",
|
"graceful-fs": "4.1.11",
|
||||||
"make-dir": "1.1.0",
|
"make-dir": "1.2.0",
|
||||||
"pify": "2.3.0",
|
"pify": "2.3.0",
|
||||||
"strip-dirs": "2.1.0"
|
"strip-dirs": "2.1.0"
|
||||||
}
|
}
|
||||||
@@ -164,7 +165,7 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"file-type": "5.2.0",
|
"file-type": "5.2.0",
|
||||||
"is-stream": "1.1.0",
|
"is-stream": "1.1.0",
|
||||||
"tar-stream": "1.5.4"
|
"tar-stream": "1.5.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"decompress-tarbz2": {
|
"decompress-tarbz2": {
|
||||||
@@ -230,9 +231,9 @@
|
|||||||
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
|
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
|
||||||
},
|
},
|
||||||
"end-of-stream": {
|
"end-of-stream": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
|
||||||
"integrity": "sha1-epDYM+/abPpurA9JSduw+tOmMgY=",
|
"integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"once": "1.4.0"
|
"once": "1.4.0"
|
||||||
}
|
}
|
||||||
@@ -333,9 +334,9 @@
|
|||||||
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
|
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
|
||||||
},
|
},
|
||||||
"ieee754": {
|
"ieee754": {
|
||||||
"version": "1.1.8",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz",
|
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.11.tgz",
|
||||||
"integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q="
|
"integrity": "sha512-VhDzCKN7K8ufStx/CLj5/PDTMgph+qwN5Pkd5i0sGnVwk56zJ0lkT8Qzi1xqWLS0Wp29DgDtNeS7v8/wMoZeHg=="
|
||||||
},
|
},
|
||||||
"inflight": {
|
"inflight": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
@@ -357,9 +358,9 @@
|
|||||||
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
|
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
|
||||||
},
|
},
|
||||||
"interpret": {
|
"interpret": {
|
||||||
"version": "1.0.4",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz",
|
||||||
"integrity": "sha1-ggzdWIuGj/sZGoCVBtbJyPISsbA="
|
"integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ="
|
||||||
},
|
},
|
||||||
"is-fullwidth-code-point": {
|
"is-fullwidth-code-point": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -385,9 +386,9 @@
|
|||||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||||
},
|
},
|
||||||
"make-dir": {
|
"make-dir": {
|
||||||
"version": "1.1.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.2.0.tgz",
|
||||||
"integrity": "sha512-0Pkui4wLJ7rxvmfUvs87skoEaxmu0hCUApF8nonzpl7q//FWp9zu8W61Scz4sd/kUiqDxvUhtoam2efDyiBzcA==",
|
"integrity": "sha512-aNUAa4UMg/UougV25bbrU4ZaaKNjJ/3/xnvg/twpmKROPdKZPZ9wGgI0opdZzO8q/zUFawoUuixuOv33eZ61Iw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"pify": "3.0.0"
|
"pify": "3.0.0"
|
||||||
},
|
},
|
||||||
@@ -409,7 +410,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"brace-expansion": "1.1.8"
|
"brace-expansion": "1.1.11"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minimist": {
|
"minimist": {
|
||||||
@@ -555,16 +556,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"process-nextick-args": {
|
"process-nextick-args": {
|
||||||
"version": "1.0.7",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
|
||||||
"integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
|
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
|
||||||
},
|
},
|
||||||
"pump": {
|
"pump": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
|
||||||
"integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
|
"integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"end-of-stream": "1.4.0",
|
"end-of-stream": "1.4.1",
|
||||||
"once": "1.4.0"
|
"once": "1.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -580,16 +581,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"readable-stream": {
|
"readable-stream": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||||
"integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
|
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"core-util-is": "1.0.2",
|
"core-util-is": "1.0.2",
|
||||||
"inherits": "2.0.3",
|
"inherits": "2.0.3",
|
||||||
"isarray": "1.0.0",
|
"isarray": "1.0.0",
|
||||||
"process-nextick-args": "1.0.7",
|
"process-nextick-args": "2.0.0",
|
||||||
"safe-buffer": "5.1.1",
|
"safe-buffer": "5.1.1",
|
||||||
"string_decoder": "1.0.3",
|
"string_decoder": "1.1.1",
|
||||||
"util-deprecate": "1.0.2"
|
"util-deprecate": "1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -598,13 +599,13 @@
|
|||||||
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
|
||||||
"integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
|
"integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"resolve": "1.5.0"
|
"resolve": "1.7.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"resolve": {
|
"resolve": {
|
||||||
"version": "1.5.0",
|
"version": "1.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.0.tgz",
|
||||||
"integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==",
|
"integrity": "sha512-QdgZ5bjR1WAlpLaO5yHepFvC+o3rCr6wpfE2tpJNMkXdulf2jKomQBdNRQITF3ZKHNlT71syG98yQP03gasgnA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"path-parse": "1.0.5"
|
"path-parse": "1.0.5"
|
||||||
}
|
}
|
||||||
@@ -648,7 +649,7 @@
|
|||||||
"integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=",
|
"integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"glob": "7.1.2",
|
"glob": "7.1.2",
|
||||||
"interpret": "1.0.4",
|
"interpret": "1.1.0",
|
||||||
"rechoir": "0.6.2"
|
"rechoir": "0.6.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -693,9 +694,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"string_decoder": {
|
"string_decoder": {
|
||||||
"version": "1.0.3",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||||
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
|
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"safe-buffer": "5.1.1"
|
"safe-buffer": "5.1.1"
|
||||||
}
|
}
|
||||||
@@ -722,9 +723,9 @@
|
|||||||
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
|
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
|
||||||
},
|
},
|
||||||
"supports-color": {
|
"supports-color": {
|
||||||
"version": "4.4.0",
|
"version": "4.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
|
||||||
"integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==",
|
"integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"has-flag": "2.0.0"
|
"has-flag": "2.0.0"
|
||||||
}
|
}
|
||||||
@@ -737,7 +738,7 @@
|
|||||||
"chownr": "1.0.1",
|
"chownr": "1.0.1",
|
||||||
"mkdirp": "0.5.1",
|
"mkdirp": "0.5.1",
|
||||||
"pump": "1.0.3",
|
"pump": "1.0.3",
|
||||||
"tar-stream": "1.5.4"
|
"tar-stream": "1.5.5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"pump": {
|
"pump": {
|
||||||
@@ -745,20 +746,20 @@
|
|||||||
"resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz",
|
||||||
"integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==",
|
"integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"end-of-stream": "1.4.0",
|
"end-of-stream": "1.4.1",
|
||||||
"once": "1.4.0"
|
"once": "1.4.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tar-stream": {
|
"tar-stream": {
|
||||||
"version": "1.5.4",
|
"version": "1.5.5",
|
||||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.5.tgz",
|
||||||
"integrity": "sha1-NlSc8E7RrumyowwBQyUiONr5QBY=",
|
"integrity": "sha512-mQdgLPc/Vjfr3VWqWbfxW8yQNiJCbAZ+Gf6GDu1Cy0bdb33ofyiNGBtAY96jHFhDuivCwgW1H9DgTON+INiXgg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"bl": "1.2.1",
|
"bl": "1.2.2",
|
||||||
"end-of-stream": "1.4.0",
|
"end-of-stream": "1.4.1",
|
||||||
"readable-stream": "2.3.3",
|
"readable-stream": "2.3.6",
|
||||||
"xtend": "4.0.1"
|
"xtend": "4.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -784,9 +785,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "2.5.3",
|
"version": "2.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.2.tgz",
|
||||||
"integrity": "sha512-ptLSQs2S4QuS6/OD1eAKG+S5G8QQtrU5RT32JULdZQtM1L3WTi34Wsu48Yndzi8xsObRAB9RPt/KhA9wlpEF6w=="
|
"integrity": "sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q="
|
||||||
},
|
},
|
||||||
"unbzip2-stream": {
|
"unbzip2-stream": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.5",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "8.0.28",
|
"@types/node": "8.0.28",
|
||||||
"shx": "0.2.2",
|
"shx": "0.2.2",
|
||||||
"typescript": "2.5.3"
|
"typescript": "2.6.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chalk": "2.1.0",
|
"chalk": "2.1.0",
|
||||||
|
|||||||
@@ -2,9 +2,12 @@
|
|||||||
const uhk = require('./uhk');
|
const uhk = require('./uhk');
|
||||||
const program = require('commander');
|
const program = require('commander');
|
||||||
|
|
||||||
program.parse(process.argv);
|
program
|
||||||
|
.option('-t, --timeout <ms>', 'Bootloader timeout in ms', 5000)
|
||||||
|
.parse(process.argv);
|
||||||
|
|
||||||
const enumerationMode = program.args[0];
|
const enumerationMode = program.args[0];
|
||||||
|
|
||||||
(async function() {
|
(async function() {
|
||||||
await uhk.reenumerate(enumerationMode);
|
await uhk.reenumerate(enumerationMode, program.timeout);
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
const util = require('util');
|
|
||||||
const HID = require('node-hid');
|
const HID = require('node-hid');
|
||||||
const {HardwareConfiguration, UhkBuffer} = require('uhk-common');
|
const {HardwareConfiguration, UhkBuffer} = require('uhk-common');
|
||||||
const {getTransferBuffers, ConfigBufferId, UhkHidDevice, UsbCommand} = require('uhk-usb');
|
|
||||||
const Logger = require('./logger');
|
const Logger = require('./logger');
|
||||||
const debug = process.env.DEBUG;
|
const debug = process.env.DEBUG;
|
||||||
|
|
||||||
@@ -18,7 +16,7 @@ const kbootCommandIdToName = {
|
|||||||
const eepromOperationIdToName = {
|
const eepromOperationIdToName = {
|
||||||
0: 'read',
|
0: 'read',
|
||||||
1: 'write',
|
1: 'write',
|
||||||
}
|
};
|
||||||
|
|
||||||
function bufferToString(buffer) {
|
function bufferToString(buffer) {
|
||||||
let str = '';
|
let str = '';
|
||||||
@@ -71,7 +69,10 @@ function writeDevice(device, data, options={}) {
|
|||||||
function getUhkDevice() {
|
function getUhkDevice() {
|
||||||
const foundDevice = HID.devices().find(device =>
|
const foundDevice = HID.devices().find(device =>
|
||||||
device.vendorId === 0x1d50 && device.productId === 0x6122 &&
|
device.vendorId === 0x1d50 && device.productId === 0x6122 &&
|
||||||
((device.usagePage === 128 && device.usage === 129) || device.interface === 0));
|
// hidapi can not read the interface number on Mac, so check the usage page and usage
|
||||||
|
((device.usagePage === 128 && device.usage === 129) || // Old firmware
|
||||||
|
(device.usagePage === (0xFF00 | 0x00) && device.usage === 0x01) || // New firmware
|
||||||
|
device.interface === 0));
|
||||||
|
|
||||||
if (!foundDevice) {
|
if (!foundDevice) {
|
||||||
return null;
|
return null;
|
||||||
@@ -188,8 +189,7 @@ async function updateDeviceFirmware(firmwareImage, extension) {
|
|||||||
|
|
||||||
// USB commands
|
// USB commands
|
||||||
|
|
||||||
function reenumerate(enumerationMode) {
|
function reenumerate(enumerationMode, bootloaderTimeoutMs=5000) {
|
||||||
const bootloaderTimeoutMs = 5000;
|
|
||||||
const pollingIntervalMs = 100;
|
const pollingIntervalMs = 100;
|
||||||
let pollingTimeoutMs = 10000;
|
let pollingTimeoutMs = 10000;
|
||||||
|
|
||||||
@@ -393,6 +393,12 @@ async function writeHca(device, isIso) {
|
|||||||
await uhk.launchEepromTransfer(device, uhk.eepromOperations.write, configBufferIds.hardwareConfig);
|
await uhk.launchEepromTransfer(device, uhk.eepromOperations.write, configBufferIds.hardwareConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function eraseHca(device) {
|
||||||
|
const buffer = new Buffer(Array(64).fill(0xff));
|
||||||
|
await uhk.writeConfig(device, buffer, true);
|
||||||
|
await uhk.launchEepromTransfer(device, uhk.eepromOperations.write, configBufferIds.hardwareConfig);
|
||||||
|
}
|
||||||
|
|
||||||
async function getModuleProperty(device, slotId, moduleProperty) {
|
async function getModuleProperty(device, slotId, moduleProperty) {
|
||||||
await writeDevice(device, [uhk.usbCommands.getModuleProperty, slotId, moduleProperty]);
|
await writeDevice(device, [uhk.usbCommands.getModuleProperty, slotId, moduleProperty]);
|
||||||
}
|
}
|
||||||
@@ -423,6 +429,7 @@ uhk = exports = module.exports = moduleExports = {
|
|||||||
launchEepromTransfer,
|
launchEepromTransfer,
|
||||||
writeUca,
|
writeUca,
|
||||||
writeHca,
|
writeHca,
|
||||||
|
eraseHca,
|
||||||
getModuleProperty,
|
getModuleProperty,
|
||||||
usbCommands: {
|
usbCommands: {
|
||||||
getDeviceProperty : 0x00,
|
getDeviceProperty : 0x00,
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
const program = require('commander');
|
|
||||||
const fs = require('fs');
|
|
||||||
const uhk = require('./uhk');
|
|
||||||
|
|
||||||
(async function() {
|
|
||||||
const device = uhk.getUhkDevice();
|
|
||||||
require('shelljs/global');
|
|
||||||
|
|
||||||
program
|
|
||||||
.usage(`config.bin`)
|
|
||||||
.option('-h, --hardware-config', 'Write the hardware config instead of the user config')
|
|
||||||
.parse(process.argv);
|
|
||||||
|
|
||||||
if (program.args.length == 0) {
|
|
||||||
console.error('No binary config file specified.');
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const configBin = program.args[0];
|
|
||||||
const isHardwareConfig = program.hardwareConfig;
|
|
||||||
const configTypeString = isHardwareConfig ? 'hardware' : 'user';
|
|
||||||
const configBuffer = fs.readFileSync(configBin);
|
|
||||||
|
|
||||||
await uhk.writeUserConfig(device, configBuffer, isHardwareConfig);
|
|
||||||
})();
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
const uhk = require('./uhk');
|
const uhk = require('./uhk');
|
||||||
|
|
||||||
if (process.argv.length < 2) {
|
if (process.argv.length < 2) {
|
||||||
console.log(`use: write-hca {iso|ansi}`);
|
console.log(`use: write-hardware-config {iso|ansi}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -12,7 +12,8 @@ if (layout !== 'iso' && layout !== 'ansi') {
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
uhk.writeHca(layout === 'iso')
|
const device = uhk.getUhkDevice();
|
||||||
|
uhk.writeHca(device, layout === 'iso')
|
||||||
.catch((err)=>{
|
.catch((err)=>{
|
||||||
console.error(err);
|
console.error(err);
|
||||||
});
|
});
|
||||||
@@ -17,5 +17,6 @@ const uhk = require('./uhk');
|
|||||||
const device = uhk.getUhkDevice();
|
const device = uhk.getUhkDevice();
|
||||||
const configBuffer = fs.readFileSync(configPath);
|
const configBuffer = fs.readFileSync(configPath);
|
||||||
await uhk.writeConfig(device, configBuffer, false);
|
await uhk.writeConfig(device, configBuffer, false);
|
||||||
await uhk.launchEepromTransfer(device, uhk.eepromOperations.write, uhk.configBufferIds.stagingUserConfig);
|
await uhk.applyConfig(device);
|
||||||
|
await uhk.launchEepromTransfer(device, uhk.eepromOperations.write, uhk.configBufferIds.validatedUserConfig);
|
||||||
})();
|
})();
|
||||||
Reference in New Issue
Block a user