/// The webview piece inspired by Keyboard project on https://codepen.io/ricardoolivaalonso/pen/KKwqLQy and
/// modified by ai also other parts are generated by ai and modified by me to work with wallopino
///
/// See line 38 to 51 to see how forwarding and attaching happends
///
///
///
use std::time::Duration;
use tao::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
platform::windows::WindowExtWindows,
window::WindowBuilder,
};
use wry::WebViewBuilder;
fn main() -> Result<(), Box<dyn std::error::Error>> {
std::fs::write("./index.html", html())?;
std::fs::write("./style.css", css())?;
std::fs::write("./script.js", js())?;
let mut html_dir = std::env::current_dir()?.into_os_string();
html_dir.push("/index.html");
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_title("Black Hole")
.with_inner_size(tao::dpi::LogicalSize::new(1000.0, 700.0))
.build(&event_loop)?;
let _webview = WebViewBuilder::new()
.with_url(format!("file://{}", html_dir.to_string_lossy()))
.build(&window)?;
// this part attaches it to desktop
let hwnd = window.hwnd();
// Create a mouse forwarder object
// In webView apps, events will be ignored if we send them to root hwnd so
// we redirect them to Chrome_WidgetWin_1 child
let event_forwarder =
wallopino::EventForwarder::new(hwnd, Some("Chrome_WidgetWin_1"), true, false)?;
// Start forwarding events
event_forwarder.forward_events()?;
// Create attacher object
let mut attacher = wallopino::AttachWindow::auto_attach(hwnd, true)?;
attacher.start_watcher(Duration::from_millis(100))?;
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => {
*control_flow = ControlFlow::Exit;
}
_ => {}
}
});
}
fn html() -> &'static str {
r#"<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Keyboard - Type something</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="main flex" id="m">
<div class="keyboard flex" id="k">
<div class="screen flex" id="s"></div>
<div class="keyboard__front face"></div>
<div class="keyboard__back face"></div>
<div class="keyboard__right face"></div>
<div class="keyboard__left face"></div>
<div class="keyboard__top face">
<div class="keys"><div class="key flex"><div class="key__front face--key-b3 face"></div><div class="key__back face--key-b1 face"></div><div class="key__right face--key-b1 face"></div><div class="key__left face--key-b2 face"></div><div class="key__top face--key-b1 face"></div><div class="key__bottom face--key-b2 face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key key--w2 flex"><div class="key__front key__front--w2 face--key-b3 face"></div><div class="key__back key__back--w2 face--key-b1 face"></div><div class="key__right key__right--w2 face--key-b1 face"></div><div class="key__left key__left--w2 face--key-b2 face"></div><div class="key__top key__top--w2 face--key-b1 face"></div><div class="key__bottom key__bottom--w2 face--key-b2 face"></div></div></div><div class="keys"><div class="key key--w2 flex"><div class="key__front key__front--w2 face--key-b3 face"></div><div class="key__back key__back--w2 face--key-b1 face"></div><div class="key__right key__right--w2 face--key-b1 face"></div><div class="key__left key__left--w2 face--key-b2 face"></div><div class="key__top key__top--w2 face--key-b1 face"></div><div class="key__bottom key__bottom--w2 face--key-b2 face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face--key-b3 face"></div><div class="key__back face--key-b1 face"></div><div class="key__right face--key-b1 face"></div><div class="key__left face--key-b2 face"></div><div class="key__top face--key-b1 face"></div><div class="key__bottom face--key-b2 face"></div></div></div><div class="keys"><div class="key key--w3 flex"><div class="key__front key__front--w3 face--key-b3 face"></div><div class="key__back key__back--w3 face--key-b1 face"></div><div class="key__right key__right--w3 face--key-b1 face"></div><div class="key__left key__left--w3 face--key-b2 face"></div><div class="key__top key__top--w3 face--key-b1 face"></div><div class="key__bottom key__bottom--w3 face--key-b2 face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key key--w2 flex"><div class="key__front key__front--w2 face--key-o3 face"></div><div class="key__back key__back--w2 face--key-o1 face"></div><div class="key__right key__right--w2 face--key-o1 face"></div><div class="key__left key__left--w2 face--key-o2 face"></div><div class="key__top key__top--w2 face--key-o1 face"></div><div class="key__bottom key__bottom--w2 face--key-o2 face"></div></div></div><div class="keys"><div class="key key--w2 flex"><div class="key__front key__front--w2 face--key-b3 face"></div><div class="key__back key__back--w2 face--key-b1 face"></div><div class="key__right key__right--w2 face--key-b1 face"></div><div class="key__left key__left--w2 face--key-b2 face"></div><div class="key__top key__top--w2 face--key-b1 face"></div><div class="key__bottom key__bottom--w2 face--key-b2 face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key flex"><div class="key__front face"></div><div class="key__back face"></div><div class="key__right face"></div><div class="key__left face"></div><div class="key__top face"></div><div class="key__bottom face"></div></div><div class="key key--w3 flex"><div class="key__front key__front--w3 face--key-b3 face"></div><div class="key__back key__back--w3 face--key-b1 face"></div><div class="key__right key__right--w3 face--key-b1 face"></div><div class="key__left key__left--w3 face--key-b2 face"></div><div class="key__top key__top--w3 face--key-b1 face"></div><div class="key__bottom key__bottom--w3 face--key-b2 face"></div></div></div><div class="keys"><div class="key flex"><div class="key__front face--key-b3 face"></div><div class="key__back face--key-b1 face"></div><div class="key__right face--key-b1 face"></div><div class="key__left face--key-b2 face"></div><div class="key__top face--key-b1 face"></div><div class="key__bottom face--key-b2 face"></div></div><div class="key flex"><div class="key__front face--key-o3 face"></div><div class="key__back face--key-o1 face"></div><div class="key__right face--key-o1 face"></div><div class="key__left face--key-o2 face"></div><div class="key__top face--key-o1 face"></div><div class="key__bottom face--key-o2 face"></div></div><div class="key flex"><div class="key__front face--key-b3 face"></div><div class="key__back face--key-b1 face"></div><div class="key__right face--key-b1 face"></div><div class="key__left face--key-b2 face"></div><div class="key__top face--key-b1 face"></div><div class="key__bottom face--key-b2 face"></div></div><div class="key flex"><div class="key__front face--key-b3 face"></div><div class="key__back face--key-b1 face"></div><div class="key__right face--key-b1 face"></div><div class="key__left face--key-b2 face"></div><div class="key__top face--key-b1 face"></div><div class="key__bottom face--key-b2 face"></div></div><div class="key key--w6 flex"><div class="key__front key__front--w6 face"></div><div class="key__back key__back--w6 face"></div><div class="key__right key__right--w6 face"></div><div class="key__left key__left--w6 face"></div><div class="key__top key__top--w6 face"></div><div class="key__bottom key__bottom--w6 face"></div></div><div class="key flex"><div class="key__front face--key-b3 face"></div><div class="key__back face--key-b1 face"></div><div class="key__right face--key-b1 face"></div><div class="key__left face--key-b2 face"></div><div class="key__top face--key-b1 face"></div><div class="key__bottom face--key-b2 face"></div></div><div class="key flex"><div class="key__front face--key-b3 face"></div><div class="key__back face--key-b1 face"></div><div class="key__right face--key-b1 face"></div><div class="key__left face--key-b2 face"></div><div class="key__top face--key-b1 face"></div><div class="key__bottom face--key-b2 face"></div></div><div class="key flex"><div class="key__front face--key-b3 face"></div><div class="key__back face--key-b1 face"></div><div class="key__right face--key-b1 face"></div><div class="key__left face--key-b2 face"></div><div class="key__top face--key-b1 face"></div><div class="key__bottom face--key-b2 face"></div></div><div class="key flex"><div class="key__front face--key-b3 face"></div><div class="key__back face--key-b1 face"></div><div class="key__right face--key-b1 face"></div><div class="key__left face--key-b2 face"></div><div class="key__top face--key-b1 face"></div><div class="key__bottom face--key-b2 face"></div></div><div class="key flex"><div class="key__front face--key-b3 face"></div><div class="key__back face--key-b1 face"></div><div class="key__right face--key-b1 face"></div><div class="key__left face--key-b2 face"></div><div class="key__top face--key-b1 face"></div><div class="key__bottom face--key-b2 face"></div></div></div>
</div>
<div class="keyboard__bottom face"></div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
"#
}
fn css() -> &'static str {
r##"/* Compiled from the original CodePen SCSS without changing its design. */
*, *::after, *::before { margin: 0; padding: 0; box-sizing: border-box; transform-style: preserve-3d; }
body { width: 100%; height: 100vh; display: flex; justify-content: center; align-items: center; background-color: #1a1919; overflow: hidden; font-family: sans-serif; font-weight: bolder; color: rgba(7, 71, 76, 0.7); text-transform: uppercase; letter-spacing: 2px; }
.main { width: 800px; height: 600px; position: relative; cursor: pointer; margin-top: 200px; }
@media(max-width: 1000px){ .main{ transform: scale(.75); } }
@media(max-width: 800px){ .main{ transform: scale(.5); } }
@media(max-width: 700px){ .main{ transform: scale(.4); } }
@media(max-width: 500px){ .main{ transform: scale(.3); } }
.flex { display: flex; justify-content: center; align-items: center; }
.face { position: absolute; }
.screen { width: 303.030303px; height: 240px; transform: translateZ(100px) translateY(-200px) translateZ(50px) rotateX(270deg); background-color: #A9DFFD; border-radius: 10px; box-shadow: 0 0 5px rgba(169,223,253,.8),0 0 10px rgba(169,223,253,.7),0 0 15px rgba(169,223,253,.6),0 0 20px rgba(169,223,253,.5),0 0 40px rgba(169,223,253,.4),0 0 60px rgba(169,223,253,.3); animation: screen 1s ease-in alternate infinite; }
.keyboard { width: 500px; height: 160px; transform: perspective(10000px) rotateX(50deg) rotateZ(-25deg); }
.keyboard__front { width: 500px; height: 25px; transform: rotateX(-90deg) translateZ(80px); background-color: #9C9C9C; }
.keyboard__back { width: 500px; height: 25px; transform: rotateX(90deg) translateZ(80px); background-color: #FFFFFB; }
.keyboard__top { display:flex; flex-direction:column; justify-content:space-around; width:500px; height:160px; transform:rotateY(0deg) translateZ(12.5px); background-image:linear-gradient(to bottom,#dbf2fe,#343232); }
.keyboard__bottom { width:500px; height:160px; transform:rotateY(180deg) translateZ(12.5px); background-color:#EAE7E5; box-shadow:-20px 40px 0 #0d0c0c,0 40px 0 #0d0c0c,5px 0 0 #0d0c0c,5px 40px 0 #0d0c0c; }
.keyboard__right { width:25px; height:160px; transform:rotateY(90deg) translateZ(250px); background-color:#FFFFFB; }
.keyboard__left { width:25px; height:160px; transform:rotateY(90deg) translateZ(-250px); background-color:#EAE7E5; }
.keys { display:flex; justify-content:space-between; flex-wrap:wrap; width:100%; transform:translateZ(7.5px); padding:0 2px; }
.key { width:30px; height:27px; transition:.05s ease; }
.key--w2 { width:60px; }
.key--w3 { width:90px; }
.key--w6 { width:195px; }
.key__front { width:30px; height:15px; transform:rotateX(-90deg) translateZ(13.5px); background-color:#838383; }
.key__front--w2 { width:60px; }.key__front--w3 { width:90px; }.key__front--w6 { width:195px; }
.key__back { width:30px; height:15px; transform:rotateX(90deg) translateZ(13.5px); background-color:#FFFFFB; }
.key__back--w2 { width:60px; }.key__back--w3 { width:90px; }.key__back--w6 { width:195px; }
.key__top { width:30px; height:27px; transform:rotateY(0deg) translateZ(7.5px); background-color:#FFFFFB; background-image:linear-gradient(to bottom,#f4fbff,#FFFFFB); }
.key__top--w2 { width:60px; }.key__top--w3 { width:90px; }.key__top--w6 { width:195px; }
.key__bottom { width:30px; height:27px; transform:rotateY(180deg) translateZ(7.5px); background-color:#838383; }
.key__bottom--w2 { width:60px; }.key__bottom--w3 { width:90px; }.key__bottom--w6 { width:195px; }
.key__right { width:15px; height:27px; transform:rotateY(90deg) translateZ(15px); background-color:#838383; }
.key__right--w2 { transform:rotateY(90deg) translateZ(30px); }.key__right--w3 { transform:rotateY(90deg) translateZ(45px); }.key__right--w6 { transform:rotateY(90deg) translateZ(97.5px); }
.key__left { width:15px; height:27px; transform:rotateY(90deg) translateZ(-15px); background-image:linear-gradient(to bottom,#c5c5c5,#b8b8b8); }
.key__left--w2 { transform:rotateY(90deg) translateZ(-30px); }.key__left--w3 { transform:rotateY(90deg) translateZ(-45px); }.key__left--w6 { transform:rotateY(90deg) translateZ(-97.5px); }
.face--key-b1 { background:#A9DFFD; }
.face--key-b2 { background-image:linear-gradient(to bottom,#a7dcfa,#8FD2F8); }
.face--key-b3 { background-color:#426585; }
.face--key-o1 { background:#FFA28E; }
.face--key-o2 { background-image:linear-gradient(to bottom,#bc7377,#B46266); }
.face--key-o3 { background-color:#8E3E43; }
.key--down { display:flex; justify-content:center; align-items:center; transform:translateZ(-5px); transition:.05s ease; }
.key--down > .key__top { background:#ffccc1; }
.screen {
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
}
@keyframes screen { 0%,90%,96%{background-color:#A9DFFD;} 93%,100%{background-color:rgba(143,210,248,.8);} }
"##
}
fn js() -> &'static str {
r##"const m = document.querySelector("#m");
const k = document.querySelector("#k");
const s = document.querySelector("#s");
const kd = document.querySelectorAll(".key");
let con = 0;
// Keep the original camera / keyboard interaction untouched.
const base = (e) => {
const x = e.pageX / window.innerWidth - 0.5;
const y = e.pageY / window.innerHeight - 0.5;
k.style.transform = `
perspective(10000px)
rotateX(${y * 10 + 60}deg)
rotateZ(-${x * 40 + 35}deg)
`;
};
// Physical keyboard layout -> existing virtual-key indexes.
// Nothing in the keyboard CSS/geometry is changed.
const keyMap = new Map([
// Number row / symbols
["Backquote", 0],
["Digit1", 1], ["Digit2", 2], ["Digit3", 3], ["Digit4", 4],
["Digit5", 5], ["Digit6", 6], ["Digit7", 7], ["Digit8", 8],
["Digit9", 9], ["Digit0", 10], ["Minus", 11], ["Equal", 12],
["Backspace", 13],
// QWERTY row
["Tab", 14],
["KeyQ", 15], ["KeyW", 16], ["KeyE", 17], ["KeyR", 18],
["KeyT", 19], ["KeyY", 20], ["KeyU", 21], ["KeyI", 22],
["KeyO", 23], ["KeyP", 24], ["BracketLeft", 25], ["BracketRight", 26],
["Backslash", 27],
// Home row
["CapsLock", 28],
["KeyA", 29], ["KeyS", 30], ["KeyD", 31], ["KeyF", 32],
["KeyG", 33], ["KeyH", 34], ["KeyJ", 35], ["KeyK", 36],
["KeyL", 37], ["Semicolon", 38], ["Quote", 38],
["Enter", 39],
// Bottom letter row
["ShiftLeft", 40],
["KeyZ", 41], ["KeyX", 42], ["KeyC", 43], ["KeyV", 44],
["KeyB", 45], ["KeyN", 46], ["KeyM", 47], ["Comma", 48],
["Period", 49], ["Slash", 50],
["ShiftRight", 51],
// Modifier / space row
["ControlLeft", 52], ["ControlRight", 61],
["MetaLeft", 53], ["MetaRight", 58],
["AltLeft", 54], ["AltRight", 57],
["Space", 56],
["ContextMenu", 59],
// A few browsers / layouts report the numpad keys separately.
// They animate the corresponding visible number keys.
["Numpad1", 1], ["Numpad2", 2], ["Numpad3", 3], ["Numpad4", 4],
["Numpad5", 5], ["Numpad6", 6], ["Numpad7", 7], ["Numpad8", 8],
["Numpad9", 9], ["Numpad0", 10]
]);
// Additional compatibility mapping for keyboard events where `code` is unavailable.
const keyCodeMap = {
192: 0,
49: 1, 50: 2, 51: 3, 52: 4, 53: 5, 54: 6, 55: 7, 56: 8, 57: 9, 48: 10,
189: 11, 187: 12, 8: 13,
9: 14,
81: 15, 87: 16, 69: 17, 82: 18, 84: 19, 89: 20, 85: 21, 73: 22, 79: 23, 80: 24,
219: 25, 221: 26, 220: 27,
20: 28,
65: 29, 83: 30, 68: 31, 70: 32, 71: 33, 72: 34, 74: 35, 75: 36, 76: 37,
186: 38, 222: 38, 13: 39,
16: 40, 90: 41, 88: 42, 67: 43, 86: 44, 66: 45, 78: 46, 77: 47,
188: 48, 190: 49, 191: 50,
17: 52, 91: 53, 18: 54, 32: 56, 93: 59
};
const getVirtualIndex = (e) => {
if (keyMap.has(e.code)) return keyMap.get(e.code);
return keyCodeMap[e.keyCode];
};
const pressVirtualKey = (index) => {
if (index == null || !kd[index]) return;
kd[index].classList.add("key--down");
};
const releaseVirtualKey = (index) => {
if (index == null || !kd[index]) return;
kd[index].classList.remove("key--down");
};
const addKey = (e) => {
const index = getVirtualIndex(e);
pressVirtualKey(index);
// Preserve the original text capture behavior, extended to the number row.
// Letters are kept in the original A-Z behavior; numbers and -/= use e.key
// so shifted variants still reflect the actual physical key being pressed.
const kc = e.keyCode;
const printableNumberRow =
(kc >= 48 && kc <= 57) || kc === 189 || kc === 187;
if ((kc >= 65 && kc <= 90) || kc === 32 || printableNumberRow) {
if (kc === 32) {
s.innerHTML += " ";
} else if (printableNumberRow) {
s.innerHTML += e.key;
} else {
s.innerHTML += String.fromCharCode(kc);
}
con++;
if (con > 10) {
s.innerHTML = "";
con = 0;
}
}
// Backspace clears the screen, exactly like the original.
if (kc === 8) {
s.innerHTML = "";
con = 0;
}
};
const removeKey = (e) => {
releaseVirtualKey(getVirtualIndex(e));
};
m.addEventListener("mousemove", base);
window.addEventListener("keydown", addKey);
window.addEventListener("keyup", removeKey);
// Also release all virtual keys when the page loses focus so a held modifier
// cannot remain visually pressed after Alt+Tab or another focus change.
window.addEventListener("blur", () => {
kd.forEach((key) => key.classList.remove("key--down"));
});
"##
}