I have a new keyboard and mouse and I want to have an indicator for both devices in the windows 1 taskbar.
Something like this : Battery indicator in taskbar
My devices are :
- Razer Basilisk Ultimate
- Nuphy Halo96 Keyboard (A fairly unknown custom keyboard company)
And so, I was looking for a solution and got to this reddit post where someone used NodeJS (ElecronJS with node-usb library) to get the razer mouse battery percentage : https://www.reddit.com/r/razer/comments/zwz4rw/razer_battery_taskbar_monitor/
I'm fairly new to NodeJS and tried to reproduce this but with no success whatsoever. Any help and advice on retrieving this kind of information from usb devices would be welcome.
Here's my main.js content :
// Modules to control application life and create native browser window
const { app, BrowserWindow } = require('electron');
const path = require('path');
const usb = require('usb');
let windows = [];
const webusb = new usb.WebUSB({
allowAllDevices: true
});
const showDevices = async () => {
const devices = await webusb.getDevices();
const text = devices.map(d => `${d.vendorId}\t${d.productId}\t${d.serialNumber || '<no serial>'}`);
text.unshift('VID\tPID\tSerial\n-------------------------------------');
windows.forEach(win => {
if (win) {
win.webContents.send('devices', text.join('\n'));
}
});
// const device = await usb.findByIds(1452, 598); // Keyboard
// const device = await usb.findByIds(5426, 136); // Mouse
let device;
try {
device = await webusb.requestDevice({
filters: [{
vendorId: 5426,
productId: 136
}]
})
} catch (err) {
// No device was selected.
console.log(err);
}
console.log(device);
if (device !== undefined) {
await device.open();
if (device.configuration === null)
await device.selectConfiguration(1);
await device.claimInterface(1);
const request = await device.controlTransferOut({
requestType: 'class',
recipient: 'interface',
request: 0x09,
value: 0x300,
index: 0x00
})
console.log(request);
}
};
const createWindow = () => {
// Create the browser window.
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
});
// and load the index.html of the app.
win.loadFile('index.html');
// Open the DevTools.
// win.webContents.openDevTools()
windows.push(win);
showDevices();
};
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
webusb.addEventListener('connect', showDevices);
webusb.addEventListener('disconnect', showDevices);
createWindow();
app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
webusb.removeEventListener('connect', showDevices);
webusb.removeEventListener('disconnect', showDevices);
app.quit();
});
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
And my console output (Trying with the razer mouse first) :
WebUSBDevice {
device: {
busNumber: 1,
deviceAddress: 18,
deviceDescriptor: {
bLength: 18,
bDescriptorType: 1,
bcdUSB: 512,
bDeviceClass: 0,
bDeviceSubClass: 0,
bDeviceProtocol: 0,
bMaxPacketSize0: 64,
idVendor: 5426,
idProduct: 136,
bcdDevice: 512,
iManufacturer: 1,
iProduct: 2,
iSerialNumber: 0,
bNumConfigurations: 1
},
portNumbers: [ 11 ],
interfaces: undefined
},
configurations: [
{
configurationValue: 1,
configurationName: '',
interfaces: [Array]
}
],
usbVersionMajor: 2,
usbVersionMinor: 0,
usbVersionSubminor: 0,
deviceClass: 0,
deviceSubclass: 0,
deviceProtocol: 0,
vendorId: 5426,
productId: 136,
deviceVersionMajor: 2,
deviceVersionMinor: 0,
deviceVersionSubminor: 0,
manufacturerName: 'Razer',
productName: 'Razer Basilisk Ultimate Dongle',
serialNumber: ''
}
(node:65280) UnhandledPromiseRejectionWarning: Error: controlTransferOut error: Error: LIBUSB_ERROR_INVALID_PARAM
at WebUSBDevice.<anonymous> (C:\Users\Fskng\node_modules\usb\dist\webusb\webusb-device.js:376:31)
at step (C:\Users\Fskng\node_modules\usb\dist\webusb\webusb-device.js:33:23)
at Object.throw (C:\Users\Fskng\node_modules\usb\dist\webusb\webusb-device.js:14:53)
at rejected (C:\Users\Fskng\node_modules\usb\dist\webusb\webusb-device.js:6:65)
at process.processTicksAndRejections (node:internal/process/task_queues:96:5)
(Use `electron --trace-warnings ...` to show where the warning was created)
(node:65280) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 6)
[63068:0124/213351.034:ERROR:gpu_init.cc(523)] Passthrough is not supported, GL is disabled, ANGLE is