deskhop/webconfig/templates/script.js

218 lines
5.8 KiB
JavaScript
Raw Normal View History

const mgmtReportId = 6;
var device;
const packetType = {
keyboardReportMsg: 1, mouseReportMsg: 2, outputSelectMsg: 3, firmwareUpgradeMsg: 4, switchLockMsg: 7,
syncBordersMsg: 8, flashLedMsg: 9, wipeConfigMsg: 10, readConfigMsg: 16, writeConfigMsg: 17, saveConfigMsg: 18,
rebootMsg: 19, getValMsg: 20, setValMsg: 21, proxyPacketMsg: 23
};
function calcChecksum(report) {
let checksum = 0;
for (let i = 3; i < 11; i++)
checksum ^= report[i];
return checksum;
}
async function sendReport(type, payload = [], sendBoth = false) {
if (!device || !device.opened)
return;
/* First send this one, if the first one gets e.g. rebooted */
if (sendBoth) {
var reportProxy = makeReport(type, payload, true);
await device.sendReport(mgmtReportId, reportProxy);
}
var report = makeReport(type, payload, false);
await device.sendReport(mgmtReportId, report);
}
function makeReport(type, payload, proxy=false) {
var dataOffset = proxy ? 4 : 3;
report = new Uint8Array([0xaa, 0x55, type, ...new Array(9).fill(0)]);
if (proxy)
report = new Uint8Array([0xaa, 0x55, packetType.proxyPacketMsg, type, ...new Array(7).fill(0), type]);
if (payload) {
report.set([...payload], dataOffset);
report[report.length - 1] = calcChecksum(report);
}
return report;
}
function packValue(element, key, dataType, buffer) {
const dataOffset = 1;
var buffer = new ArrayBuffer(8);
var view = new DataView(buffer);
const methods = {
"uint32": view.setUint32,
"uint64": view.setUint32, /* Yes, I know. :-| */
"int32": view.setInt32,
"uint16": view.setUint16,
"uint8": view.setUint8,
"int16": view.setInt16,
"int8": view.setInt8
};
if (dataType in methods) {
const method = methods[dataType];
if (element.type === 'checkbox')
view.setUint8(dataOffset, element.checked ? 1 : 0, true);
else
method.call(view, dataOffset, element.value, true);
}
view.setUint8(0, key);
return new Uint8Array(buffer);
}
window.addEventListener('load', function () {
if (!("hid" in navigator)) {
document.getElementById('warning').style.display = 'block';
}
this.document.getElementById('menu-buttons').addEventListener('click', function (event) {
window[event.target.dataset.handler]();
})
});
document.getElementById('submitButton').addEventListener('click', async () => { await saveHandler(); });
async function connectHandler() {
if (device && device.opened)
return;
var devices = await navigator.hid.requestDevice({
filters: [{ vendorId: 0x1209, productId: 0xc000, usagePage: 0xff00, usage: 0x10 }]
});
device = devices[0];
device.open().then(async () => {
document.querySelectorAll('.online').forEach(element => { element.style.opacity = 1.0; });
await readHandler();
});
}
async function blinkHandler() {
await sendReport(packetType.flashLedMsg, []);
}
async function blinkBothHandler() {
await sendReport(packetType.flashLedMsg, [], true);
}
function getValue(element) {
if (element.type === 'checkbox')
return element.checked ? 1 : 0;
else
return element.value;
}
function setValue(element, value) {
element.setAttribute('fetched-value', value);
if (element.type === 'checkbox')
element.checked = value;
else
element.value = value;
element.dispatchEvent(new Event('input', { bubbles: true }));
}
function updateElement(element, event, dataType) {
var dataOffset = 3;
const methods = {
"uint32": event.data.getUint32,
"uint64": event.data.getUint32, /* Yes, I know. :-| */
"int32": event.data.getInt32,
"uint16": event.data.getUint16,
"uint8": event.data.getUint8,
"int16": event.data.getInt16,
"int8": event.data.getInt8
};
if (dataType in methods) {
var value = methods[dataType].call(event.data, dataOffset, true);
setValue(element, value);
if (element.hasAttribute('data-hex'))
setValue(element, parseInt(value).toString(16));
}
}
async function readHandler() {
if (!device || !device.opened)
await connectHandler();
const elements = document.querySelectorAll('.api');
for (const element of elements) {
var key = element.getAttribute('data-key');
var dataType = element.getAttribute('data-type');
await sendReport(packetType.getValMsg, [key]);
let incomingReport = await new Promise((resolve, reject) => {
const handleInputReport = (event) => {
updateElement(element, event, dataType);
device.removeEventListener('inputreport', handleInputReport);
resolve();
}
device.addEventListener('inputreport', handleInputReport);
});
}
}
async function rebootHandler() {
await sendReport(packetType.rebootMsg);
}
async function enterBootloaderHandler() {
await sendReport(packetType.firmwareUpgradeMsg, true, true);
}
async function valueChangedHandler(element) {
var key = element.getAttribute('data-key');
var dataType = element.getAttribute('data-type');
var origValue = element.getAttribute('fetched-value');
var newValue = getValue(element);
if (origValue != newValue) {
uintBuffer = packValue(element, key, dataType);
/* Send to both devices */
await sendReport(packetType.setValMsg, uintBuffer, true);
/* Set this as the current value */
element.setAttribute('fetched-value', newValue);
}
}
async function saveHandler() {
const elements = document.querySelectorAll('.api');
if (!device || !device.opened)
return;
for (const element of elements) {
var origValue = element.getAttribute('fetched-value')
if (element.hasAttribute('readonly'))
continue;
if (origValue != getValue(element))
await valueChangedHandler(element);
}
await sendReport(packetType.saveConfigMsg, [], true);
}
async function wipeConfigHandler() {
await sendReport(packetType.wipeConfigMsg, [], true);
}