virtual keyboard prototype

This commit is contained in:
Devaev Maxim 2018-07-25 10:34:44 +03:00
parent 22c060956e
commit 922e303c70
9 changed files with 585 additions and 163 deletions

92
kvmd/web/css/keyboard.css Normal file
View File

@ -0,0 +1,92 @@
div#keyboard {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
zoom: 0.8;
}
div#keyboard div.keyboard-block {
padding-right: 15px;
display: table-cell;
}
div#keyboard div.keyboard-block:last-child {
padding-right: 0;
}
div#keyboard div.keyboard-row {
white-space: nowrap;
height: 40px;
margin-bottom: 5px;
}
div#keyboard div.keyboard-row:last-child {
margin-bottom: 0;
}
div#keyboard div.key, div.empty-key {
box-sizing: border-box;
display: inline-block;
margin-right: 5px;
padding: 0;
width: 40px;
height: 40px;
}
div#keyboard div.key {
font-size: 0.9em;
text-align: center;
vertical-align: top;
box-shadow: var(--micro-shadow);
border: var(--grey-border);
-webkit-border-radius: 6px;
-moz-border-radius: 6px;
border-radius: 6px;
color: var(--fg-color-normal);
background-color: var(--bg-color-gray);
cursor: pointer;
}
div#keyboard div.key:hover {
color: var(--fg-color-intensive);
background-color: var(--bg-color-ctl);
}
div#keyboard div.key:active {
box-shadow: none;
color: var(--fg-color-selected);
background-color: var(--bg-color-dark);
}
div#keyboard div.key:last-child, div.empty-key:last-child {
margin-right: 0;
}
div#keyboard div.wide-1 {
width: 61px;
}
div#keyboard div.wide-2 {
width: 64px;
}
div#keyboard div.wide-3 {
width: 77px;
}
div#keyboard div.wide-4 {
width: 102px;
}
div#keyboard div.wide-5 {
width: 288px;
}
div#keyboard div.left {
text-align: left !important;
padding-left: 6px !important;
}
div#keyboard div.right {
text-align: right !important;
padding-right: 6px !important;
}
div#keyboard div.small {
font-size: 0.7em;
}
div#keyboard div.key p {
margin: 0;
position: relative;
top: 50%;
-webkit-transform: translateY(-50%);
-moz-transform: translateY(-50%);
transform: translateY(-50%);
}

44
kvmd/web/css/leds.css Normal file
View File

@ -0,0 +1,44 @@
@-webkit-keyframes spin {
100% {
-webkit-transform: rotate(360deg);
}
}
@-moz-keyframes spin {
100% {
-moz-transform: rotate(360deg);
}
}
@keyframes spin {
100% {
-webkit-transform: rotate(360deg);
-moz-transform: rotate(360deg);
transform: rotate(360deg);
}
}
img.led-on {
-webkit-filter: invert(0.5) sepia(1) saturate(5) hue-rotate(100deg);
-moz-filter: invert(0.5) sepia(1) saturate(5) hue-rotate(100deg);
filter: invert(0.5) sepia(1) saturate(5) hue-rotate(100deg);
}
img.led-off {
-webkit-filter: invert(0.5);
-moz-filter: invert(0.5);
filter: invert(0.5);
}
img.led-hdd-busy {
-webkit-filter: invert(0.5) sepia(1) saturate(15) hue-rotate(320deg);
-moz-filter: invert(0.5) sepia(1) saturate(15) hue-rotate(320deg);
filter: invert(0.5) sepia(1) saturate(15) hue-rotate(320deg);
}
img.led-msd-writing {
-webkit-filter: invert(0.5) sepia(1) saturate(5) hue-rotate(0deg);
-moz-filter: invert(0.5) sepia(1) saturate(5) hue-rotate(0deg);
filter: invert(0.5) sepia(1) saturate(5) hue-rotate(0deg);
-webkit-animation: spin 2s linear infinite;
-moz-animation: spin 2s linear infinite;
animation: spin 2s linear infinite;
}

View File

@ -1,28 +1,3 @@
:root {
--dark-border: 1px solid #17191d;
--black-border: 1px solid black;
--small-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
--big-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.4);
--bg-color-normal: #36393f;
--bg-color-light: #484b51;
--bg-color-dark: #17191d;
--bg-color-ctl: #202225;
--bg-color-hovered: #1a1c1f;
--bg-color-selected: #171717;
--bg-color-progress: #171717;
--fg-color-normal: #c3c3c3;
--fg-color-dark: #aaaaaa;
--fg-color-intensive: white;
--fg-color-inactive: #6c7481;
--fg-color-selected: #6c7481;
--fg-color-progress: #436a8a;
--bg-color-stream-screen: black;
}
body {
margin: 0;
overflow: hidden;
@ -32,34 +7,15 @@ body {
}
img#logo {
-webkit-filter: invert(0.7);
-moz-filter: invert(0.7);
filter: invert(0.7);
vertical-align: middle;
padding: 13px 15px;
}
div.window {
user-select: none;
position: absolute;
border: var(--dark-border);
border-radius: 8px;
box-sizing: border-box;
box-shadow: var(--big-shadow);
display: inline-block;
background-color: var(--bg-color-light);
padding: 3px 10px 10px 10px;
top: 70px;
left: 50%;
-webkit-transform: translate(-50%);
-moz-transform: translate(-50%);
transform: translate(-50%);
}
div.window-header {
color: var(--fg-color-dark);
cursor: move;
padding-bottom: 3px;
}
ul#ctl {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
box-shadow: var(--small-shadow);
list-style-type: none;
@ -95,10 +51,14 @@ ul#ctl li a.ctl-item:hover:not(.active) {
background-color: var(--bg-color-hovered);
}
div.ctl-dropdown-content {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
overflow: hidden;
user-select: text;
white-space: nowrap;
border: var(--dark-border);
-webkit-border-radius: 0 0 8px 8px;
-moz-border-radius: 0 0 8px 8px;
border-radius: 0 0 8px 8px;
position: absolute;
background-color: var(--bg-color-ctl);
@ -160,106 +120,7 @@ div.ctl-dropdown-content-text {
font-size: 14px;
}
img#stream-image {
width: 640px;
height: 480px;
display: inline-block;
border: var(--dark-border);
background-color: var(--bg-color-stream-screen);
}
img.stream-image-active {
cursor: crosshair;
-webkit-filter: none;
filter: none;
}
img.stream-image-inactive {
cursor: wait;
-webkit-filter: grayscale(100%) brightness(75%);
filter: grayscale(100%) brightness(75%);
}
img.led-on {
-webkit-filter: invert(0.5) sepia(1) saturate(5) hue-rotate(100deg);
filter: invert(0.5) sepia(1) saturate(5) hue-rotate(100deg);
}
img.led-off {
-webkit-filter: invert(0.5);
filter: invert(0.5);
}
img.led-hdd-busy {
-webkit-filter: invert(0.5) sepia(1) saturate(15) hue-rotate(320deg);
filter: invert(0.5) sepia(1) saturate(15) hue-rotate(320deg);
}
img.led-msd-writing {
-webkit-filter: invert(0.5) sepia(1) saturate(5) hue-rotate(0deg);
filter: invert(0.5) sepia(1) saturate(5) hue-rotate(0deg);
-webkit-animation:spin 2s linear infinite;
-moz-animation:spin 2s linear infinite;
animation:spin 2s linear infinite;
}
@-webkit-keyframes spin {
100% {
-webkit-transform: rotate(360deg);
}
}
@-moz-keyframes spin {
100% {
-moz-transform: rotate(360deg);
}
}
@keyframes spin {
100% {
-webkit-transform: rotate(360deg);
-moz-transform: rotate(360deg);
transform:rotate(360deg);
}
}
div#msd-menu {
width: 450px;
}
table#msd-info {
user-select: text;
border-spacing: 5px;
margin: 0 10px 0 10px;
font-size: 12px;
}
table#msd-info
td#msd-status,
td#msd-current-image-name,
td#msd-current-image-size,
td#msd-storage-size,
td#msd-new-image-name,
td#msd-new-image-size {
font-weight: bold;
max-width: 310px;
overflow: hidden;
}
div#msd-progress {
background-color: var(--bg-color-progress);
height: 1.5em;
width: 100%;
position: relative;
}
div#msd-progress:before {
color: var(--fg-color-intensive);
content: attr(data-label);
font-size: 0.8em;
position: absolute;
text-align: center;
top: 4px;
left: 0;
right: 0;
}
div#msd-progress span#msd-progress-value {
background-color: var(--fg-color-progress);
display: inline-block;
height: 100%;
}
ul#bottom {
ul#footer {
list-style-type: none;
bottom: 0;
position: fixed;
@ -269,16 +130,20 @@ ul#bottom {
color: var(--fg-color-inactive);
z-index: -10;
}
ul#bottom li {
ul#footer li {
padding: 0 10px;
}
ul#bottom li.bottom-left {
ul#footer li.footer-left {
float: left;
}
ul#bottom li.bottom-right {
ul#footer li.footer-right {
float: right;
}
ul#bottom li a {
ul#footer li a {
text-decoration: underline dotted;
color: var(--fg-color-inactive);
}
ul#footer li a:hover {
text-decoration: underline;
color: var(--fg-color-inactive);
}

45
kvmd/web/css/msd.css Normal file
View File

@ -0,0 +1,45 @@
div#msd-menu {
width: 450px;
}
table#msd-info {
-webkit-user-select: text;
-moz-user-select: text;
user-select: text;
border-spacing: 5px;
margin: 0 10px 0 10px;
font-size: 12px;
}
table#msd-info
td#msd-status,
td#msd-current-image-name,
td#msd-current-image-size,
td#msd-storage-size,
td#msd-new-image-name,
td#msd-new-image-size {
font-weight: bold;
max-width: 310px;
overflow: hidden;
}
div#msd-progress {
background-color: var(--bg-color-progress);
height: 1.5em;
width: 100%;
position: relative;
}
div#msd-progress:before {
color: var(--fg-color-intensive);
content: attr(data-label);
font-size: 0.8em;
position: absolute;
text-align: center;
top: 4px;
left: 0;
right: 0;
}
div#msd-progress span#msd-progress-value {
background-color: var(--fg-color-progress);
display: inline-block;
height: 100%;
}

21
kvmd/web/css/stream.css Normal file
View File

@ -0,0 +1,21 @@
img#stream-image {
width: 640px;
height: 480px;
display: inline-block;
border: var(--dark-border);
background-color: var(--bg-color-stream-screen);
}
img.stream-image-active {
cursor: crosshair;
-webkit-filter: none;
-moz-filter: none;
filter: none;
}
img.stream-image-inactive {
cursor: wait;
-webkit-filter: grayscale(100%) brightness(75%);
-moz-filter: grayscale(100%) brightness(75%);
filter: grayscale(100%) brightness(75%);
}

177
kvmd/web/css/vars.css Normal file
View File

@ -0,0 +1,177 @@
:root {
--dark-border: 1px solid #17191d;
--grey-border: 1px solid #202225;
--black-border: 1px solid black;
--micro-shadow: 1px 2px 4px 0 rgba(0, 0, 0, 0.4);
--small-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2);
--big-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.4);
--bg-color-normal: #36393f;
--bg-color-light: #484b51;
--bg-color-gray: #3b3e43;
--bg-color-dark: #17191d;
--bg-color-ctl: #202225;
--bg-color-hovered: #1a1c1f;
--bg-color-selected: #171717;
--bg-color-progress: #171717;
--fg-color-normal: #c3c3c3;
--fg-color-dark: #aaaaaa;
--fg-color-intensive: white;
--fg-color-inactive: #6c7481;
--fg-color-selected: #6c7481;
--fg-color-progress: #436a8a;
--bg-color-stream-screen: black;
}
body {
margin: 0;
overflow: hidden;
color: var(--fg-color-normal);
background-color: var(--bg-color-normal);
font-family: sans-serif !important;
}
img#logo {
-webkit-filter: invert(0.7);
-moz-filter: invert(0.7);
filter: invert(0.7);
vertical-align: middle;
padding: 13px 15px;
}
ul#ctl {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
box-shadow: var(--small-shadow);
list-style-type: none;
margin: 0;
padding: 0;
background-color: var(--bg-color-ctl);
position: fixed;
top: 0;
width: 100%;
z-index: 10;
}
ul#ctl li.ctl-logo {
float: left;
}
ul#ctl li.ctl-right-actions {
float: right;
}
ul#ctl img {
vertical-align: middle;
margin-right: 10px;
height: 20px;
}
ul#ctl li a.ctl-item {
cursor: pointer;
border-left: var(--black-border);
display: inline-block;
color: var(--fg-color-normal);
padding: 15px 16px;
text-decoration: none;
height: 20px;
}
ul#ctl li a.ctl-item:hover:not(.active) {
background-color: var(--bg-color-hovered);
}
div.ctl-dropdown-content {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
overflow: hidden;
white-space: nowrap;
border: var(--dark-border);
-webkit-border-radius: 0 0 8px 8px;
-moz-border-radius: 0 0 8px 8px;
border-radius: 0 0 8px 8px;
position: absolute;
background-color: var(--bg-color-ctl);
min-width: 180px;
box-shadow: var(--big-shadow);
z-index: 9;
}
div.ctl-dropdown-content div.buttons-row {
margin: 0;
padding: 0;
font-size: 0;
}
div.ctl-dropdown-content button {
box-shadow: none;
border: none;
color: var(--fg-color-normal);
background-color: var(--bg-color-normal);
display: block;
width: 100%;
height: 30px;
font-size: 16px;
text-align: left;
padding: 0 15px;
outline: none;
cursor: pointer;
}
div.ctl-dropdown-content button:enabled:hover {
color: var(--fg-color-intensive);
background-color: var(--bg-color-dark) !important;
}
div.ctl-dropdown-content button:disabled {
color: var(--fg-color-inactive);
cursor: default;
}
div.ctl-dropdown-content button:active {
color: var(--fg-color-selected) !important;
}
div.ctl-dropdown-content button.row50 {
display: inline-block;
width: 50%;
}
div.ctl-dropdown-content button.row25 {
display: inline-block;
width: 25%;
}
div.ctl-dropdown-content button.row50:not(:first-child), button.row25:not(:first-child) {
border-left: var(--dark-border);
}
div.ctl-dropdown-content hr {
margin: 0;
display: block;
height: 1px;
border: 0;
padding: 0;
background-color: var(--bg-color-dark);
}
div.ctl-dropdown-content-text {
margin: 10px 15px 10px 15px;
font-size: 14px;
}
ul#footer {
list-style-type: none;
bottom: 0;
position: fixed;
width: 100%;
padding: 0;
font-size: 0.7em;
color: var(--fg-color-inactive);
z-index: -10;
}
ul#footer li {
padding: 0 10px;
}
ul#footer li.footer-left {
float: left;
}
ul#footer li.footer-right {
float: right;
}
ul#footer li a {
text-decoration: underline dotted;
color: var(--fg-color-inactive);
}
ul#footer li a:hover {
text-decoration: underline;
color: var(--fg-color-inactive);
}

33
kvmd/web/css/windows.css Normal file
View File

@ -0,0 +1,33 @@
div.window {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
position: absolute;
border: var(--dark-border);
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
box-sizing: border-box;
box-shadow: var(--big-shadow);
display: inline-block;
background-color: var(--bg-color-light);
padding: 3px 10px 10px 10px;
-webkit-transform: translate(-50%);
-moz-transform: translate(-50%);
transform: translate(-50%);
}
div.window-header {
color: var(--fg-color-dark);
font-size: 0.8em;
cursor: move;
padding-left: 6px;
padding-bottom: 4px;
}
div.window hr.window-sep {
margin: 0 0 6px 0;
display: block;
border: none;
border-top: 1px solid var(--bg-color-normal);
}

View File

@ -9,7 +9,13 @@
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">
<link rel="stylesheet" href="css/vars.css">
<link rel="stylesheet" href="css/main.css">
<link rel="stylesheet" href="css/windows.css">
<link rel="stylesheet" href="css/leds.css">
<link rel="stylesheet" href="css/stream.css">
<link rel="stylesheet" href="css/msd.css">
<link rel="stylesheet" href="css/keyboard.css">
</head>
<script src="js/tools.js"></script>
@ -162,14 +168,141 @@
</li>
</ul>
<div class="window">
<div class="window" style="left:50%; top:70px">
<div class="window-header">Stream</div>
<!-- <hr class="window-sep"> -->
<img id="stream-image" class="stream-image-inactive" alt="Loading..." src="/streamer/?action=stream"/>
</div>
<ul id="bottom">
<li id="kvmd-version" class="bottom-left"></li>
<li class="bottom-right"><a target="_blank" href="https://github.com/mdevaev/pi-kvm">Pi-KVM Project</a></li>
<div class="window" style="left:75%; top:60%">
<div class="window-header">Virtual Keyboard</div>
<hr class="window-sep">
<div id="keyboard">
<div class="keyboard-block">
<div class="keyboard-row">
<div id="Escape" class="key small"><p>Esc</p></div>
<div class="empty-key" style="width:24px"></div>
<div id="F1" class="key small"><p>F1</p></div>
<div id="F2" class="key small"><p>F2</p></div>
<div id="F3" class="key small"><p>F3</p></div>
<div id="F4" class="key small"><p>F4</p></div>
<div class="empty-key" style="width:10px"></div>
<div id="F5" class="key small"><p>F5</p></div>
<div id="F6" class="key small"><p>F6</p></div>
<div id="F7" class="key small"><p>F7</p></div>
<div id="F8" class="key small"><p>F8</p></div>
<div class="empty-key" style="width:10px"></div>
<div id="F9" class="key small"><p>F9</p></div>
<div id="F10" class="key small"><p>F10</p></div>
<div id="F11" class="key small"><p>F11</p></div>
<div id="F12" class="key small"><p>F12</p></div>
</div>
<div class="keyboard-row">
<div id="Backquote" class="key"><p>~<br>`</p></div>
<div id="Digit1" class="key"><p>!<br>1</p></div>
<div id="Digit2" class="key"><p>@<br>2</p></div>
<div id="Digit3" class="key"><p>#<br>3</p></div>
<div id="Digit4" class="key"><p>$<br>4</p></div>
<div id="Digit5" class="key"><p>%<br>5</p></div>
<div id="Digit6" class="key"><p>^<br>6</p></div>
<div id="Digit7" class="key"><p>&amp;<br>7</p></div>
<div id="Digit8" class="key"><p>*<br>8</p></div>
<div id="Digit9" class="key"><p>(<br>9</p></div>
<div id="Digit0" class="key"><p>)<br>0</p></div>
<div id="Minus" class="key"><p>_<br>-</p></div>
<div id="Equal" class="key"><p>+<br>=</p></div>
<div id="Backspace" class="key wide-2 right"><p>&#8612;</p></div>
</div>
<div class="keyboard-row">
<div id="Tab" class="key wide-2 left"><p>&#8676;<br>&#8677;</p></div>
<div id="KeyQ" class="key single"><p>Q</p></div>
<div id="KeyW" class="key single"><p>W</p></div>
<div id="KeyE" class="key single"><p>E</p></div>
<div id="KeyR" class="key single"><p>R</p></div>
<div id="KeyT" class="key single"><p>T</p></div>
<div id="KeyY" class="key single"><p>Y</p></div>
<div id="KeyU" class="key single"><p>U</p></div>
<div id="KeyI" class="key single"><p>I</p></div>
<div id="KeyO" class="key single"><p>O</p></div>
<div id="KeyP" class="key single"><p>P</p></div>
<div id="BracketLeft" class="key"><p>{<br>[</p></div>
<div id="BracketRight" class="key"><p>}<br>]</p></div>
<div id="Backslash" class="key"><p>|<br>\</p></div>
</div>
<div class="keyboard-row">
<div id="CapsLock" class="key wide-3 left small"><p>Caps Lock</p></div>
<div id="KeyA" class="key single"><p>A</p></div>
<div id="KeyS" class="key single"><p>S</p></div>
<div id="KeyD" class="key single"><p>D</p></div>
<div id="KeyF" class="key single"><p>F</p></div>
<div id="KeyG" class="key single"><p>G</p></div>
<div id="KeyH" class="key single"><p>H</p></div>
<div id="KeyJ" class="key single"><p>J</p></div>
<div id="KeyK" class="key single"><p>K</p></div>
<div id="KeyL" class="key single"><p>L</p></div>
<div id="Semicolon" class="key"><p>:<br>;</p></div>
<div id="Quote" class="key"><p>"<br>'</p></div>
<div id="Enter" class="key wide-3 right small"><p>Enter<br>&crarr;</p></div>
</div>
<div class="keyboard-row">
<div id="ShiftLeft" class="key wide-4 left small"><p>Shift</p></div>
<div id="KeyZ" class="key single"><p>Z</p></div>
<div id="KeyX" class="key single"><p>X</p></div>
<div id="KeyC" class="key single"><p>C</p></div>
<div id="KeyV" class="key single"><p>V</p></div>
<div id="KeyB" class="key single"><p>B</p></div>
<div id="KeyN" class="key single"><p>N</p></div>
<div id="KeyM" class="key single"><p>M</p></div>
<div id="Comma" class="key"><p>&lt;<br>,</p></div>
<div id="Period" class="key"><p>&gt;<br>.</p></div>
<div id="Slash" class="key"><p>?<br>/</p></div>
<div id="ShiftRight" class="key wide-4 right small"><p>Shift</p></div>
</div>
<div class="keyboard-row">
<div id="ControlLeft" class="key wide-1 left small"><p>Ctrl</p></div>
<div id="MetaLeft" class="key wide-1 left small"><p>Win</p></div>
<div id="AltLeft" class="key wide-1 left small"><p>Alt</p></div>
<div id="Space" class="key wide-5"></div>
<div id="AltRight" class="key wide-1 right small"><p>Alt</p></div>
<div id="MetaRight" class="key wide-1 right small"><p>Win</p></div>
<div id="ControlRight" class="key wide-1 right small"><p>Ctrl</p></div>
</div>
</div>
<div class="keyboard-block">
<div class="keyboard-row">
<div class="empty-key"></div>
<div class="empty-key"></div>
<div id="PrintScreen" class="key small"><p>PrtSc</p></div>
</div>
<div class="keyboard-row">
<div id="Insert" class="key small"><p>Ins</p></div>
<div id="Home" class="key small"><p>Home</p></div>
<div id="PageUp" class="key small"><p>PgUp</p></div>
</div>
<div class="keyboard-row">
<div id="Delete" class="key small"><p>Del</p></div>
<div id="End" class="key small"><p>End</p></div>
<div id="PageDown" class="key small"><p>PgDn</p></div>
</div>
<div class="keyboard-row">
</div>
<div class="keyboard-row">
<div class="empty-key"></div>
<div id="ArrowUp" class="key"><p>&uarr;</p></div>
<div class="empty-key"></div>
</div>
<div class="keyboard-row">
<div id="ArrowLeft" class="key"><p>&larr;</p></div>
<div id="ArrowDown" class="key"><p>&darr;</p></div>
<div id="ArrowRight" class="key"><p>&rarr;</p></div>
</div>
</div>
</div>
</div>
<ul id="footer">
<li id="kvmd-version" class="footer-left"></li>
<li class="footer-right"><a target="_blank" href="https://github.com/mdevaev/pi-kvm">Pi-KVM Project</a></li>
</ul>
</body>
</html>

View File

@ -16,12 +16,24 @@ var keyboard = new function() {
var __keyHandler = function(ws, event, state) {
// https://github.com/wesbos/keycodes/blob/gh-pages/scripts.js
tools.debug("Key", (state ? "pressed:" : "released:"), event)
event.preventDefault();
ws.send(JSON.stringify({
event_type: "key",
key: event.code,
state: state,
}));
el_key = $(event.code);
if (el_key) {
tools.debug("Key", (state ? "pressed:" : "released:"), event);
if (state) {
el_key.style.boxShadow = "none";
el_key.style.color = "var(--fg-color-selected)";
el_key.style.backgroundColor = "var(--bg-color-dark)";
} else {
el_key.removeAttribute("style");
}
event.preventDefault();
ws.send(JSON.stringify({
event_type: "key",
key: event.code,
state: state,
}));
}
};
};