File size: 3,123 Bytes
2f6df3d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20ce68e
2f6df3d
20ce68e
 
2f6df3d
 
 
 
20ce68e
 
 
 
 
 
2f6df3d
20ce68e
 
 
 
 
 
2f6df3d
 
 
 
 
 
20ce68e
2f6df3d
 
 
 
20ce68e
2f6df3d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import test from "node:test";
import assert from "node:assert/strict";

import { readLayoutMap, resolveKeycaps } from "../src/ui/keyboard-layout.js";

const AZERTY = new Map(
  Object.entries({ KeyW: "z", KeyA: "q", KeyS: "s", KeyD: "d", KeyQ: "a", KeyE: "e" }),
);
const QWERTY = new Map(
  Object.entries({ KeyW: "w", KeyA: "a", KeyS: "s", KeyD: "d", KeyQ: "q", KeyE: "e" }),
);
const DVORAK = new Map(
  Object.entries({ KeyW: ",", KeyA: "a", KeyS: "o", KeyD: "e", KeyQ: "'", KeyE: "." }),
);

const CODES = ["KeyQ", "KeyE"];

test("resolves caps and the movement hint from the active layout", () => {
  assert.deepEqual(resolveKeycaps(CODES, QWERTY), {
    labels: { KeyW: "W", KeyA: "A", KeyS: "S", KeyD: "D", KeyQ: "Q", KeyE: "E" },
    moveHint: "arrows or WASD",
  });
  const azerty = resolveKeycaps(CODES, AZERTY);
  assert.deepEqual(azerty.labels, {
    KeyW: "Z", KeyA: "Q", KeyS: "S", KeyD: "D", KeyQ: "A", KeyE: "E",
  });
  assert.equal(azerty.moveHint, "arrows or ZQSD");

  const dvorak = resolveKeycaps(CODES, DVORAK);
  assert.equal(dvorak.labels.KeyQ, "'");
  assert.equal(dvorak.moveHint, "arrows or ,AOE");
});

test("falls back to QWERTY labels without a map", () => {
  assert.deepEqual(resolveKeycaps(CODES, null), {
    labels: { KeyW: "W", KeyA: "A", KeyS: "S", KeyD: "D", KeyQ: "Q", KeyE: "E" },
    moveHint: "arrows or WASD",
  });
  assert.equal(resolveKeycaps(["KeyX"], null).labels.KeyX, "X");
});

const ALL_QWERTY = {
  labels: { KeyW: "W", KeyA: "A", KeyS: "S", KeyD: "D", KeyQ: "Q", KeyE: "E" },
  moveHint: "arrows or WASD",
};

test("falls back entirely to QWERTY when the map misses a movement key", () => {
  const partial = new Map([["KeyW", "z"], ["KeyA", "q"], ["KeyS", "s"]]);
  assert.deepEqual(resolveKeycaps(CODES, partial), ALL_QWERTY);
});

test("falls back entirely to QWERTY when the map misses a requested key", () => {
  const partial = new Map([...AZERTY].filter(([code]) => code !== "KeyE"));
  assert.deepEqual(resolveKeycaps(CODES, partial), ALL_QWERTY);
});

test("rejects layout values that cannot sit on a keycap", () => {
  const junk = new Map(
    Object.entries({ KeyQ: "", KeyE: "  ", KeyW: "Dead", KeyA: "́", KeyS: 7 }),
  );
  assert.deepEqual(resolveKeycaps(CODES, junk), ALL_QWERTY);
});

test("a throwing map cannot break the menu", () => {
  const hostile = { get: () => { throw new Error("nope"); } };
  assert.deepEqual(resolveKeycaps(CODES, hostile), ALL_QWERTY);
});

test("readLayoutMap yields null when the API is absent or refuses", async () => {
  assert.equal(await readLayoutMap({}), null);
  assert.equal(await readLayoutMap({ keyboard: {} }), null);
  const rejects = { keyboard: { getLayoutMap: () => Promise.reject(new Error("blocked")) } };
  assert.equal(await readLayoutMap(rejects), null);
  const throws = { keyboard: { getLayoutMap: () => { throw new Error("framed"); } } };
  assert.equal(await readLayoutMap(throws), null);
});

test("readLayoutMap returns the map where the API is supported", async () => {
  const nav = { keyboard: { getLayoutMap: async () => AZERTY } };
  assert.equal(await readLayoutMap(nav), AZERTY);
});