Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | 1x 1x 1x 1x 1x 25x 118x 378x 25x 25x 25x 25x 150x 166x 83x 83x 25x 25x 29x 7x 9x 8x 30x 25x 225x 175x 25x 172x 25x 150x 200x 200x 25x 378x 378x 25x 119x 25x 66x 66x 48x 66x | import { Keyboard } from "./keyboard.js";
import { showNotice } from "./reporting.js";
import { noteEvent } from "./analytics.js";
import { keyCodes } from "../keymap.js";
import { Shortcuts } from "./shortcuts.js";
const PasteBoxId = "paste-text";
/** The eight accessibility switches, on the number keys. */
const SwitchKeys = ["K1", "K2", "K3", "K4", "K5", "K6", "K7", "K8"];
const TypingTargets = 'input, textarea, select, [contenteditable]:not([contenteditable="false"])';
// Where keys are for the page, not the machine: the paste box, and the media window's controls.
const KeyboardSinks = `#${PasteBoxId}, #media-panel`;
// The media window's own shortcuts have to answer from inside it, or it cannot be re-aimed from
// the keyboard at all. The paste box keeps every key, because on a Mac Alt is Option and types
// an accented character rather than nothing.
const ShortcutSinks = `#${PasteBoxId}`;
/**
* Builds the emulated keyboard and wires the browser's shortcuts around it,
* exposing it as `keyboard` for whoever needs the machine's keys.
*/
export class KeyboardSetup {
/**
* @param {object} opts
* @param {object} opts.actions what each shortcut does, supplied late-bound:
* toggleDebugger, toggleFast, openRewind, openPrinter, openMedia,
* pause, resume, paste, onAnyKeyDown
* @param {import("./accessibility-switches.js").AccessibilitySwitches} opts.accessibilitySwitches
*/
constructor({ actions, accessibilitySwitches, processor, dbgr, keyLayout }) {
const keyboard = (this.keyboard = new Keyboard({
processor,
inputEnabledFunction: () => !!document.activeElement?.closest(KeyboardSinks),
shortcutsBlockedFunction: () => !!document.activeElement?.closest(ShortcutSinks),
keyLayout,
dbgr,
}));
keyboard.addEventListener("notice", showNotice);
keyboard.addEventListener("pause", () => actions.pause());
keyboard.addEventListener("resume", () => actions.resume());
keyboard.addEventListener("break", (e) => {
// F12/Break: Reset processor
if (e.detail) noteEvent("keyboard", "press", "break");
});
const onDown = (note, action) => (down) => {
if (down) {
if (note) noteEvent("keyboard", "press", note);
action();
}
};
const alt = { alt: true, ctrl: false };
const runners = {
toggleDebugger: () => actions.toggleDebugger(),
// `running` is pushed in from the loop, so it stays true whatever stopped the machine.
togglePause: () => (keyboard.running ? keyboard.pauseEmulation() : keyboard.resumeEmulation()),
toggleFast: () => actions.toggleFast(),
openPrinter: () => actions.openPrinter(),
openRewind: () => actions.openRewind(),
openMediaTape: () => actions.openMedia("tape"),
};
for (const shortcut of Shortcuts) {
if (!shortcut.key) continue;
if (shortcut.run === "openMediaDrive") {
// The only shortcut whose shift state changes what it does, rather than which key it is.
keyboard.registerKeyHandler(
keyCodes[shortcut.key],
(down, _code, shift) => {
if (down) actions.openMedia(shift ? 1 : 0);
},
alt,
);
continue;
}
keyboard.registerKeyHandler(
keyCodes[shortcut.key],
onDown(shortcut.note ?? null, runners[shortcut.run]),
alt,
);
}
// Alt means the underlying key is never forwarded to the BBC Micro (keyboard.js bails
// out early when a handler fires), so typing numbers works normally.
const handleSwitch = (index) => (down) => accessibilitySwitches.setSwitch(index, down);
SwitchKeys.forEach((name, index) => keyboard.registerKeyHandler(keyCodes[name], handleSwitch(index), alt));
document.addEventListener("keydown", (evt) => {
actions.onAnyKeyDown();
keyboard.keyDown(evt);
});
document.addEventListener("keypress", (evt) => keyboard.keyPress(evt));
document.addEventListener("keyup", (evt) => keyboard.keyUp(evt));
document.addEventListener("paste", (evt) => {
const target = document.activeElement;
if (target && target.id !== PasteBoxId && target.matches(TypingTargets)) return;
const text = evt.clipboardData?.getData("text/plain");
if (text) actions.paste(text);
});
}
}
|