wallopino 0.1.1

A Rust library for attaching windows behind the Windows desktop icons.
Documentation
/// 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 += "&nbsp;";
        } 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"));
});

"##
}