deskhop/webconfig/config-unpacked.htm

1915 lines
35 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
/*!
* Milligram v1.4.1
* https://milligram.io
*
* Copyright (c) 2020 CJ Patoilo
* Licensed under the MIT license
*/
*,
*:after,
*:before {
box-sizing: inherit;
}
:root {
--highlight-color: #384955;
--font-color: #384955;
--highlight-color2: #5e9f41;
}
html {
box-sizing: border-box;
font-size: 62.5%;
}
body {
color: var(--font-color);
font-family: 'Roboto', 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;
font-size: 1.6em;
font-weight: 300;
letter-spacing: .01em;
line-height: 1.6;
}
blockquote {
border-left: 0.3rem solid #384955;
margin-left: 0;
margin-right: 0;
padding: 1rem 1.5rem;
}
blockquote *:last-child {
margin-bottom: 0;
}
.button,
button,
input[type='button'],
input[type='reset'],
input[type='submit'] {
background-color: var(--highlight-color);
border: 0.1rem solid var(--highlight-color);
border-radius: .4rem;
color: #fff;
cursor: pointer;
display: inline-block;
font-size: 1.1rem;
font-weight: 700;
height: 3.8rem;
letter-spacing: .1rem;
line-height: 3.8rem;
padding: 0.0rem 2.0rem;
text-align: center;
text-decoration: none;
text-transform: uppercase;
white-space: nowrap;
}
.button:focus, .button:hover,
button:focus,
button:hover,
input[type='button']:focus,
input[type='button']:hover,
input[type='reset']:focus,
input[type='reset']:hover,
input[type='submit']:focus,
input[type='submit']:hover {
background-color: var(--highlight-color2);
border-color: var(--highlight-color2);
color: #fff;
outline: 0;
}
.button[disabled],
button[disabled],
input[type='button'][disabled],
input[type='reset'][disabled],
input[type='submit'][disabled] {
cursor: default;
opacity: .5;
}
.button[disabled]:focus, .button[disabled]:hover,
button[disabled]:focus,
button[disabled]:hover,
input[type='button'][disabled]:focus,
input[type='button'][disabled]:hover,
input[type='reset'][disabled]:focus,
input[type='reset'][disabled]:hover,
input[type='submit'][disabled]:focus,
input[type='submit'][disabled]:hover {
background-color: var(--highlight-color);
border-color: var(--highlight-color);
}
.button.button-outline,
button.button-outline,
input[type='button'].button-outline,
input[type='reset'].button-outline,
input[type='submit'].button-outline {
background-color: transparent;
color: var(--highlight-color);
}
.button.button-outline:focus, .button.button-outline:hover,
button.button-outline:focus,
button.button-outline:hover,
input[type='button'].button-outline:focus,
input[type='button'].button-outline:hover,
input[type='reset'].button-outline:focus,
input[type='reset'].button-outline:hover,
input[type='submit'].button-outline:focus,
input[type='submit'].button-outline:hover {
background-color: transparent;
border-color: var(--highlight-color2);
color: var(--highlight-color2);
}
.button.button-outline[disabled]:focus, .button.button-outline[disabled]:hover,
button.button-outline[disabled]:focus,
button.button-outline[disabled]:hover,
input[type='button'].button-outline[disabled]:focus,
input[type='button'].button-outline[disabled]:hover,
input[type='reset'].button-outline[disabled]:focus,
input[type='reset'].button-outline[disabled]:hover,
input[type='submit'].button-outline[disabled]:focus,
input[type='submit'].button-outline[disabled]:hover {
border-color: inherit;
color: var(--highlight-color);
}
.button.button-clear,
button.button-clear,
input[type='button'].button-clear,
input[type='reset'].button-clear,
input[type='submit'].button-clear {
background-color: transparent;
border-color: transparent;
color: var(--highlight-color);
}
.button.button-clear:focus, .button.button-clear:hover,
button.button-clear:focus,
button.button-clear:hover,
input[type='button'].button-clear:focus,
input[type='button'].button-clear:hover,
input[type='reset'].button-clear:focus,
input[type='reset'].button-clear:hover,
input[type='submit'].button-clear:focus,
input[type='submit'].button-clear:hover {
background-color: transparent;
border-color: transparent;
color: var(--highlight-color2);
}
.button.button-clear[disabled]:focus, .button.button-clear[disabled]:hover,
button.button-clear[disabled]:focus,
button.button-clear[disabled]:hover,
input[type='button'].button-clear[disabled]:focus,
input[type='button'].button-clear[disabled]:hover,
input[type='reset'].button-clear[disabled]:focus,
input[type='reset'].button-clear[disabled]:hover,
input[type='submit'].button-clear[disabled]:focus,
input[type='submit'].button-clear[disabled]:hover {
color: var(--highlight-color);
}
.button.button-shifted {
margin-left: 10%;
}
code {
background: #f4f5f6;
border-radius: .4rem;
font-size: 86%;
margin: 0 .2rem;
padding: .2rem .5rem;
white-space: nowrap;
}
pre {
background: #f4f5f6;
border-left: 0.3rem solid var(--highlight-color);
overflow-y: hidden;
}
pre > code {
border-radius: 0;
display: block;
padding: 1rem 1.5rem;
white-space: pre;
}
hr {
border: 0;
border-top: 0.1rem dotted lightblue;
margin: 1.0rem 3.0rem;
}
input[type='color'],
input[type='date'],
input[type='datetime'],
input[type='datetime-local'],
input[type='email'],
input[type='month'],
input[type='password'],
input[type='search'],
input[type='number'],
input[type='tel'],
input[type='text'],
input[type='url'],
input[type='week'],
input:not([type]),
textarea,
select {
-webkit-appearance: none;
background-color: transparent;
border: 0.1rem solid #d1d1d1;
border-radius: .4rem;
box-shadow: none;
box-sizing: inherit;
height: 3.8rem;
padding: .6rem 1.0rem .7rem;
width: 100%;
}
input[type='color']:focus,
input[type='date']:focus,
input[type='datetime']:focus,
input[type='datetime-local']:focus,
input[type='email']:focus,
input[type='month']:focus,
input[type='number']:focus,
input[type='password']:focus,
input[type='search']:focus,
input[type='tel']:focus,
input[type='text']:focus,
input[type='url']:focus,
input[type='week']:focus,
input:not([type]):focus,
textarea:focus,
select:focus {
border-color: var(--highlight-color);
outline: 0;
}
select {
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 8" width="30"><path fill="%23d1d1d1" d="M0,0l6,8l6-8"/></svg>') center right no-repeat;
padding-right: 3.0rem;
}
select:focus {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 8" width="30"><path fill="%239b4dca" d="M0,0l6,8l6-8"/></svg>');
}
select[multiple] {
background: none;
height: auto;
}
textarea {
min-height: 6.5rem;
}
label,
legend {
display: block;
font-size: 1.6rem;
font-weight: 700;
margin-bottom: .5rem;
}
fieldset {
border-width: 0;
padding: 0;
}
input[type='checkbox'],
input[type='radio'] {
display: inline;
}
.label-inline {
display: inline-block;
font-weight: normal;
margin-left: .5rem;
}
.label-inline-bold {
display: inline-block;
font-size: 1.6rem;
font-weight: 700;
}
input[type='range'].input-inline,
input[type='number'].input-inline {
display: inline-block;
font-weight: normal;
border: none;
width: 20%;
}
.range {
width: 100%;
}
.container {
margin: 0 auto;
max-width: 112.0rem;
padding: 0 2.0rem;
position: relative;
width: 100%;
}
.row {
display: flex;
flex-direction: column;
padding: 0;
width: 100%;
}
.row.row-no-padding {
padding: 0;
}
.row.row-no-padding > .column {
padding: 0;
}
.row.row-wrap {
flex-wrap: wrap;
}
.row.row-top {
align-items: flex-start;
}
.row.row-bottom {
align-items: flex-end;
}
.row.row-center {
align-items: center;
}
.row.row-stretch {
align-items: stretch;
}
.row.row-baseline {
align-items: baseline;
}
.row .column {
display: block;
flex: 1 1 auto;
margin-left: 0;
max-width: 100%;
width: 100%;
}
.row .column.column-offset-10 {
margin-left: 10%;
}
.row .column.column-offset-20 {
margin-left: 20%;
}
.row .column.column-offset-25 {
margin-left: 25%;
}
.row .column.column-offset-33, .row .column.column-offset-34 {
margin-left: 33.3333%;
}
.row .column.column-offset-40 {
margin-left: 40%;
}
.row .column.column-offset-50 {
margin-left: 50%;
}
.row .column.column-offset-60 {
margin-left: 60%;
}
.row .column.column-offset-66, .row .column.column-offset-67 {
margin-left: 66.6666%;
}
.row .column.column-offset-75 {
margin-left: 75%;
}
.row .column.column-offset-80 {
margin-left: 80%;
}
.row .column.column-offset-90 {
margin-left: 90%;
}
.row .column.column-10 {
flex: 0 0 10%;
max-width: 10%;
}
.row .column.column-20 {
flex: 0 0 20%;
max-width: 20%;
}
.row .column.column-25 {
flex: 0 0 25%;
max-width: 25%;
}
.row .column.column-33, .row .column.column-34 {
flex: 0 0 33.3333%;
max-width: 33.3333%;
}
.row .column.column-40 {
flex: 0 0 40%;
max-width: 40%;
}
.row .column.column-50 {
flex: 0 0 50%;
max-width: 50%;
}
.row .column.column-60 {
flex: 0 0 60%;
max-width: 60%;
}
.row .column.column-66, .row .column.column-67 {
flex: 0 0 66.6666%;
max-width: 66.6666%;
}
.row .column.column-75 {
flex: 0 0 75%;
max-width: 75%;
}
.row .column.column-80 {
flex: 0 0 80%;
max-width: 80%;
}
.row .column.column-90 {
flex: 0 0 90%;
max-width: 90%;
}
.row .column .column-top {
align-self: flex-start;
}
.row .column .column-bottom {
align-self: flex-end;
}
.row .column .column-center {
align-self: center;
}
@media (min-width: 40rem) {
.row {
flex-direction: row;
width: calc(100% + 2.0rem);
}
.row .column {
margin-bottom: inherit;
padding: 0 1.0rem;
}
}
a {
color: var(--highlight-color);
text-decoration: none;
}
a:focus, a:hover {
color: var(--highlight-color2);
}
dl,
ol,
ul {
list-style: none;
margin-top: 0;
padding-left: 0;
}
dl dl,
dl ol,
dl ul,
ol dl,
ol ol,
ol ul,
ul dl,
ul ol,
ul ul {
font-size: 90%;
margin: 1.5rem 0 1.5rem 3.0rem;
}
ol {
list-style: decimal inside;
}
ul {
list-style: circle inside;
}
.button,
button,
dd,
dt,
li {
margin-bottom: 1.0rem;
}
fieldset,
input,
select,
textarea {
margin-bottom: 1.5rem;
}
blockquote,
dl,
figure,
form,
ol,
p,
pre,
table,
ul {
margin-bottom: 2.5rem;
}
table {
border-spacing: 0;
display: block;
overflow-x: auto;
text-align: left;
width: 100%;
}
td,
th {
border-bottom: 0.1rem solid #e1e1e1;
padding: 1.2rem 1.5rem;
}
td:first-child,
th:first-child {
padding-left: 0;
}
td:last-child,
th:last-child {
padding-right: 0;
}
@media (min-width: 40rem) {
table {
display: table;
overflow-x: initial;
}
}
b,
strong {
font-weight: bold;
}
p {
margin-top: 0;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-weight: 300;
letter-spacing: -.1rem;
margin-bottom: 2.0rem;
margin-top: 0;
}
h1 {
font-size: 4.6rem;
line-height: 1.2;
}
h2 {
font-size: 3.6rem;
line-height: 1.25;
}
h3 {
font-size: 2.8rem;
line-height: 1.3;
}
h4 {
font-size: 2.2rem;
letter-spacing: -.08rem;
line-height: 1.35;
}
h5 {
font-size: 1.8rem;
letter-spacing: -.05rem;
line-height: 1.5;
}
h6 {
font-size: 1.6rem;
letter-spacing: 0;
line-height: 1.4;
}
img {
max-width: 100%;
}
.clearfix:after {
clear: both;
content: ' ';
display: table;
}
.float-left {
float: left;
}
.float-right {
float: right;
}
.online {
opacity: 0.5;
}
</style>
<title>DeskHop Config</title>
</head>
<body>
<main class="wrapper">
<section class="container">
<div class="row" id="warning" style="display: none;">
<blockquote>
<h3> Oh, no! </h3>
Unfortunately, your browser does not support WebHID or the Permissions Policy is blocking its usage. Please try Chromium <br />
(or Chrome if you have to). Apologies for the inconvenience, hopefully a cross-browser solution happens soon.
</blockquote>
</div>
<div class="row">
<div class="column column-80" style="padding-top: 1%;">
<h3>Desk<span style="color: #5e9f41;">Hop</span> Config</h3>
</div>
</div>
<div class="column" style="border: 2px solid #d7e5f0; padding-right: 3em;">
<div class="row">
<div class="column column-20" style="margin-right: 2em; padding-top: 2em; background-color: #d7e5f0">
<svg style="width:180px; height:110px; stroke:#384955; stroke-width:1px; fill:white">
<g transform="translate(-135, -190) scale (2)">
<path d="m 88.742006,98.633938 c -0.12648,0.0838 -0.252994,0.223292 -0.309214,0.320992 -0.0984,0.223308 0.337328,26.23798 0.44977,26.53106 0.0984,0.2512 0.42166,0.41868 0.74493,0.41868 0.309218,0 0.224886,0.0838 3.837102,-3.37742 l 1.672582,-1.56312 0.210828,0.43264 c 0.11244,0.23728 1.236868,2.5261 2.473736,5.09408 1.9818,4.11712 2.27696,4.68934 2.47373,4.81496 0.16868,0.1116 0.28111,0.1396 0.44977,0.1256 0.16868,-0.014 5.34102,-2.42842 6.21245,-2.88898 0.253,-0.1396 0.42166,-0.4187 0.42166,-0.68386 0,-0.1814 -0.59032,-1.4654 -2.44562,-5.28946 -1.33526,-2.77734 -2.43157,-5.06616 -2.40346,-5.09408 0.0281,-0.0278 1.57419,-0.23728 3.4295,-0.47452 1.8553,-0.23724 3.47166,-0.47452 3.5841,-0.5164 0.23894,-0.1116 0.46383,-0.43262 0.46383,-0.6699 0,-0.0838 -0.0562,-0.25122 -0.11244,-0.36286 -0.0703,-0.1256 -1.02604,-0.963 -2.41752,-2.09346 -1.26498,-1.03276 -5.80484,-4.75912 -10.077656,-8.29008 -4.272816,-3.53096 -7.842866,-6.447844 -7.941254,-6.489712 -0.23894,-0.12554 -0.47788,-0.11164 -0.71682,0.0558 z" />
<path d="m 112.69484,105.14605 a 1.8639801,1.8639801 0 0 0 -1.86328,1.86328 1.8639801,1.8639801 0 0 0 1.86328,1.86328 h 17.58204 a 1.8639801,1.8639801 0 0 0 1.86328,-1.86328 1.8639801,1.8639801 0 0 0 -1.86328,-1.86328 z" />
<path d="m 136.31594,110.95075 a 1.8639801,1.8639801 0 0 0 -1.86328,1.86328 1.8639801,1.8639801 0 0 0 1.86328,1.86328 h 2.71874 a 1.8639801,1.8639801 0 0 0 1.8672,-1.86328 1.8639801,1.8639801 0 0 0 -1.8672,-1.86328 z" />
<path d="m 121.55422,128.36481 a 1.8639801,1.8639801 0 0 0 -1.86328,1.86328 1.8639801,1.8639801 0 0 0 1.86328,1.86328 h 2.72266 a 1.8639801,1.8639801 0 0 0 1.86328,-1.86328 1.8639801,1.8639801 0 0 0 -1.86328,-1.86328 z" />
<path d="m 121.55812,110.83355 a 1.8639801,1.8639801 0 0 0 -1.86328,1.8672 1.8639801,1.8639801 0 0 0 1.86328,1.86328 h 4.15626 a 1.8639801,1.8639801 0 0 0 1.86328,-1.86328 1.8639801,1.8639801 0 0 0 -1.86328,-1.8672 z" />
<path d="m 118.64406,116.75543 a 1.8639801,1.8639801 0 0 0 -1.86328,1.86328 1.8639801,1.8639801 0 0 0 1.86328,1.86328 h 24.70704 a 1.8639801,1.8639801 0 0 0 1.86718,-1.86328 1.8639801,1.8639801 0 0 0 -1.86718,-1.86328 z" />
<path d="m 129.55812,122.56011 a 1.8639801,1.8639801 0 0 0 -1.86328,1.86328 1.8639801,1.8639801 0 0 0 1.86328,1.8633 h 10.6836 a 1.8639801,1.8639801 0 0 0 1.86328,-1.8633 1.8639801,1.8639801 0 0 0 -1.86328,-1.86328 z" />
<path d="m 104.01516,99.341366 a 1.8639801,1.8639801 0 0 0 -1.86329,1.863284 1.8639801,1.8639801 0 0 0 1.86329,1.86328 h 27.4375 a 1.8639801,1.8639801 0 0 0 1.86718,-1.86328 1.8639801,1.8639801 0 0 0 -1.86718,-1.863284 z" />
</g>
</svg>
<div id="menu-buttons">
<button data-handler="connectHandler" class="button button-clear button-shifted">Connect</button><br />
<button data-handler="readHandler" class="button button-clear button-shifted online">Read</button><br />
<button data-handler="saveHandler" class="button button-clear button-shifted online">Save</button><br />
<button data-handler="rebootHandler" class="button button-clear button-shifted online">Exit</button><br />
<hr />
<button data-handler="blinkHandler" class="button button-clear button-shifted online">Blink</button><br />
<button data-handler="blinkBothHandler" class="button button-clear button-shifted online">Blink both</button><br />
<button data-handler="enterBootloaderHandler" class="button button-clear button-shifted online">Bootloader</button><br />
<button data-handler="wipeConfigHandler" class="button button-clear button-shifted online">Wipe Config</button><br />
</div>
</div>
<div class="column" style="padding-top: 2em;">
<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<rect x="5" y="5" width="90" height="70" stroke="black" stroke-width="2" fill="#beffa1" rx="10" ry="10" />
<line x1="50" y1="90" x2="50" y2="75" stroke="black" stroke-width="2" />
<rect x="30" y="90" width="40" height="3" stroke="black" stroke-width="2" fill="#d7e5f0" rx="5" ry="5" />
</svg>
<h3>Output A</h3>
<label class=""> Screen Count</label>
<select class="api" data-type="uint32" data-key="11" required>
<option disabled selected value></option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select><br />
<div class="clearfix">
<form>
<label class="label-inline"> Speed X=</label>
<input class="input-inline" type="number" name="aInput12" data-type="int32" data-key="12"
onchange="valueChangedHandler(this)"
readonly oninput="this.form.aRange12.value=this.value" />
<input class="range api" type="range" name="aRange12" data-type="int32" data-key="12"
onchange="valueChangedHandler(this)"
min="" max="" oninput="this.form.aInput12.value=this.value" />
</form>
</div>
<div class="clearfix">
<form>
<label class="label-inline"> Speed Y=</label>
<input class="input-inline" type="number" name="aInput13" data-type="int32" data-key="13"
onchange="valueChangedHandler(this)"
readonly oninput="this.form.aRange13.value=this.value" />
<input class="range api" type="range" name="aRange13" data-type="int32" data-key="13"
onchange="valueChangedHandler(this)"
min="" max="" oninput="this.form.aInput13.value=this.value" />
</form>
</div>
<label class=""> Border Top</label>
<input class="api" type="text" name="name14" data-type="int32" data-key="14"
onchange="valueChangedHandler(this)"
/>
<label class=""> Border Bottom</label>
<input class="api" type="text" name="name15" data-type="int32" data-key="15"
onchange="valueChangedHandler(this)"
/>
<label class=""> Operating System</label>
<select class="api" data-type="uint8" data-key="16" required>
<option disabled selected value></option>
<option value="1">Linux</option>
<option value="2">MacOS</option>
<option value="3">Windows</option>
<option value="4">Android</option>
<option value="255">Other</option>
</select><br />
<label class=""> Screen Position</label>
<select class="api" data-type="uint8" data-key="17" required>
<option disabled selected value></option>
<option value="1">Left</option>
<option value="2">Right</option>
</select><br />
<label class=""> Cursor Park Position</label>
<select class="api" data-type="uint8" data-key="18" required>
<option disabled selected value></option>
<option value="0">Top</option>
<option value="1">Bottom</option>
<option value="3">Previous</option>
</select><br />
<label class=""> Screensaver</label>
<label class=""> Mode</label>
<select class="api" data-type="uint8" data-key="19" required>
<option disabled selected value></option>
<option value="0">Disabled</option>
<option value="1">Pong</option>
<option value="2">Jitter</option>
</select><br />
<div class="clearfix">
<label class="label-inline"> Only If Inactive</label>
<input class="api" type="checkbox" name="name20" data-type="uint8" data-key="20"
onchange="valueChangedHandler(this)"
/>
</div>
<label class=""> Idle Time (μs)</label>
<input class="api" type="text" name="name21" data-type="uint64" data-key="21"
onchange="valueChangedHandler(this)"
/>
<label class=""> Max Time (μs)</label>
<input class="api" type="text" name="name22" data-type="uint64" data-key="22"
onchange="valueChangedHandler(this)"
/>
</div>
<div class="column" style="padding-top: 2em;">
<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<rect x="5" y="5" width="90" height="70" stroke="black" stroke-width="2" fill="#beffa1" rx="10" ry="10" />
<line x1="50" y1="90" x2="50" y2="75" stroke="black" stroke-width="2" />
<rect x="30" y="90" width="40" height="3" stroke="black" stroke-width="2" fill="#d7e5f0" rx="5" ry="5" />
</svg>
<h3>Output B</h3>
<label class=""> Screen Count</label>
<select class="api" data-type="uint32" data-key="41" required>
<option disabled selected value></option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select><br />
<div class="clearfix">
<form>
<label class="label-inline"> Speed X=</label>
<input class="input-inline" type="number" name="aInput42" data-type="int32" data-key="42"
onchange="valueChangedHandler(this)"
readonly oninput="this.form.aRange42.value=this.value" />
<input class="range api" type="range" name="aRange42" data-type="int32" data-key="42"
onchange="valueChangedHandler(this)"
min="" max="" oninput="this.form.aInput42.value=this.value" />
</form>
</div>
<div class="clearfix">
<form>
<label class="label-inline"> Speed Y=</label>
<input class="input-inline" type="number" name="aInput43" data-type="int32" data-key="43"
onchange="valueChangedHandler(this)"
readonly oninput="this.form.aRange43.value=this.value" />
<input class="range api" type="range" name="aRange43" data-type="int32" data-key="43"
onchange="valueChangedHandler(this)"
min="" max="" oninput="this.form.aInput43.value=this.value" />
</form>
</div>
<label class=""> Border Top</label>
<input class="api" type="text" name="name44" data-type="int32" data-key="44"
onchange="valueChangedHandler(this)"
/>
<label class=""> Border Bottom</label>
<input class="api" type="text" name="name45" data-type="int32" data-key="45"
onchange="valueChangedHandler(this)"
/>
<label class=""> Operating System</label>
<select class="api" data-type="uint8" data-key="46" required>
<option disabled selected value></option>
<option value="1">Linux</option>
<option value="2">MacOS</option>
<option value="3">Windows</option>
<option value="4">Android</option>
<option value="255">Other</option>
</select><br />
<label class=""> Screen Position</label>
<select class="api" data-type="uint8" data-key="47" required>
<option disabled selected value></option>
<option value="1">Left</option>
<option value="2">Right</option>
</select><br />
<label class=""> Cursor Park Position</label>
<select class="api" data-type="uint8" data-key="48" required>
<option disabled selected value></option>
<option value="0">Top</option>
<option value="1">Bottom</option>
<option value="3">Previous</option>
</select><br />
<label class=""> Screensaver</label>
<label class=""> Mode</label>
<select class="api" data-type="uint8" data-key="49" required>
<option disabled selected value></option>
<option value="0">Disabled</option>
<option value="1">Pong</option>
<option value="2">Jitter</option>
</select><br />
<div class="clearfix">
<label class="label-inline"> Only If Inactive</label>
<input class="api" type="checkbox" name="name50" data-type="uint8" data-key="50"
onchange="valueChangedHandler(this)"
/>
</div>
<label class=""> Idle Time (μs)</label>
<input class="api" type="text" name="name51" data-type="uint64" data-key="51"
onchange="valueChangedHandler(this)"
/>
<label class=""> Max Time (μs)</label>
<input class="api" type="text" name="name52" data-type="uint64" data-key="52"
onchange="valueChangedHandler(this)"
/>
</div>
</div>
<div class="row">
<div class="column column-20" style="background-color: #d7e5f0; margin-right: 2em;">
</div>
<div class="column-20" style="background-color: #d7e5f0;">
</div>
<div class="column">
<h3>Common Config</h3>
<label class=""> Mouse</label>
<div class="clearfix">
<label class="label-inline"> Force Mouse Boot Mode</label>
<input class="api" type="checkbox" name="name71" data-type="uint8" data-key="71"
onchange="valueChangedHandler(this)"
/>
</div>
<div class="clearfix">
<label class="label-inline"> Enable Acceleration</label>
<input class="api" type="checkbox" name="name75" data-type="uint8" data-key="75"
onchange="valueChangedHandler(this)"
/>
</div>
<div class="clearfix">
<form>
<label class="label-inline"> Jump Treshold=</label>
<input class="input-inline" type="number" name="aInput77" data-type="uint16" data-key="77"
onchange="valueChangedHandler(this)"
readonly oninput="this.form.aRange77.value=this.value" />
<input class="range api" type="range" name="aRange77" data-type="uint16" data-key="77"
onchange="valueChangedHandler(this)"
min="" max="" oninput="this.form.aInput77.value=this.value" />
</form>
</div>
<label class=""> Keyboard</label>
<div class="clearfix">
<label class="label-inline"> Force KBD Boot Protocol</label>
<input class="api" type="checkbox" name="name72" data-type="uint8" data-key="72"
onchange="valueChangedHandler(this)"
/>
</div>
<div class="clearfix">
<label class="label-inline"> KBD LED as Indicator</label>
<input class="api" type="checkbox" name="name73" data-type="uint8" data-key="73"
onchange="valueChangedHandler(this)"
/>
</div>
<div class="clearfix">
<label class="label-inline"> Enforce Ports</label>
<input class="api" type="checkbox" name="name76" data-type="uint8" data-key="76"
onchange="valueChangedHandler(this)"
/>
</div>
<input type="submit" value="Save" id="submitButton">
</div>
<div class="column">
<h3>Device Status</h3>
<label class="label-inline"> Running FW version:</label>
<input class="content api" type="text" name="name78" data-type="uint16" data-key="78"
onchange="valueChangedHandler(this)"
data-hex readonly />
<label class="label-inline"> Running FW checksum:</label>
<input class="content api" type="text" name="name79" data-type="uint32" data-key="79"
onchange="valueChangedHandler(this)"
data-hex readonly />
</div>
</div>
</div>
</section>
</main>
<script>
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);
}
</script>
</body>
</html>