all repos — sz-chrome-remote-extension @ master

pi-chrome, patched to drive a signed-in browser on another host through a broker, with an MCP server

test-suite/challenges/21-keyboard-modifiers.html (view raw)

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
<!doctype html>
<meta charset="utf-8">
<title>21 keyboard modifiers</title>
<link rel="stylesheet" href="../_style.css">
<script src="../_lib.js"></script>
<body>
<main>
  <p>Goal: focus the input and type a capital <code>A</code> via <b>Shift+a</b>
     (not Caps Lock, not pasted, not assigned). Page asserts a real Shift chord:
     <code>keydown</code> for <code>Shift</code> arrives <em>before</em> <code>keydown</code> for
     <code>A</code>; the <code>A</code> event has <code>shiftKey=true</code>,
     <code>key==="A"</code>, <code>code==="KeyA"</code>, <code>getModifierState("Shift")===true</code>;
     and <code>keyup</code> for Shift arrives <em>after</em> <code>keyup</code> for <code>A</code>.</p>
  <input id="t" placeholder="type Shift+a" style="font-size:18px;padding:8px 12px;width:240px">
</main>
<script>
Challenge.init({ id: "keyboard-modifiers", instructions: "type capital A using Shift+a chord" });
const t = document.getElementById("t");

const log = [];
for (const name of ["keydown","keypress","keyup","input"]) {
  t.addEventListener(name, (e) => {
    log.push({
      name,
      key: e.key, code: e.code,
      shiftKey: e.shiftKey, isTrusted: e.isTrusted,
      modShift: e.getModifierState ? e.getModifierState("Shift") : null,
      t: e.timeStamp,
    });
  });
}

// input fires before keyup. Grade only when Shift is released so a valid chord
// cannot fail merely because its release events have not happened yet.
t.addEventListener("keyup", (event) => {
  if (event.key !== "Shift") return;
  const bad = [];
  if (t.value !== "A") bad.push(`value=${JSON.stringify(t.value)} (need 'A')`);
  const downShift = log.find(e => e.name === "keydown" && e.key === "Shift");
  const downA     = log.find(e => e.name === "keydown" && e.code === "KeyA");
  const upShift   = log.find(e => e.name === "keyup"   && e.key === "Shift");
  const upA       = log.find(e => e.name === "keyup"   && e.code === "KeyA");

  if (!downShift) bad.push("no keydown for Shift");
  if (!downA)     bad.push("no keydown for KeyA");
  if (!upShift)   bad.push("no keyup for Shift");
  if (!upA)       bad.push("no keyup for KeyA");

  if (downShift && downA && downShift.t > downA.t) bad.push("Shift keydown after A keydown");
  if (upShift && upA && upShift.t < upA.t) bad.push("Shift keyup before A keyup");

  if (downA) {
    if (downA.key !== "A")            bad.push(`A keydown.key="${downA.key}" (need 'A')`);
    if (downA.code !== "KeyA")        bad.push(`A keydown.code="${downA.code}"`);
    if (!downA.shiftKey)              bad.push("A keydown.shiftKey=false");
    if (downA.modShift !== true)      bad.push("getModifierState('Shift')!==true on A keydown");
    if (!downA.isTrusted)             bad.push("A keydown isTrusted=false");
  }
  if (downShift) {
    if (!downShift.isTrusted)         bad.push("Shift keydown isTrusted=false");
  }

  Challenge.log("chord", { log });
  if (bad.length) Challenge.fail(...bad);
  else Challenge.pass("Shift+a chord, modifiers + ordering correct");
});
</script>
</body>