2024.js/lib/keys.ts

68 lines
2.1 KiB
TypeScript
Raw Normal View History

2024-01-27 23:57:36 -05:00
import { Source } from "./source";
export type KeyName = "up" | "down" | "left" | "right" | "a" | "b" | "menu";
const KEY_NAMES: Record<string, KeyName> = {
// compact keys (WASD+ZXC)
KeyZ: "a",
KeyX: "b",
KeyC: "menu",
KeyW: "up",
KeyS: "down",
KeyA: "left",
KeyD: "right",
// full-board keys (arrows+space/shift/enter)
Space: "a",
ShiftLeft: "b",
ShiftRight: "b",
Enter: "menu",
ArrowUp: "up",
ArrowDown: "down",
ArrowLeft: "left",
ArrowRight: "right",
};
/** A keypress/release event for an abstract button, or else ["focus", "release"] if for some reason future release events might not be registered. */
export type KeyEvent = [KeyName | "focus", "press" | "release"];
export function keyControl(source: HTMLElement): Source<KeyEvent> {
const tabIndex = source.getAttribute("tabIndex");
source.setAttribute(
"tabindex",
tabIndex == "" || tabIndex == null ? "-1" : tabIndex
);
return ((callback?: (keyEvent: KeyEvent) => void) => {
if (callback) {
const handle = (evt: KeyboardEvent, action: "press" | "release") => {
const keyName = KEY_NAMES[evt.code];
if (keyName != undefined) {
evt.preventDefault();
evt.stopPropagation();
callback([keyName, action]);
}
};
const keyUp = (evt: KeyboardEvent) => handle(evt, "release");
const keyDown = (evt: KeyboardEvent) => handle(evt, "press");
const focus = () => callback(["focus", "press"]);
const blur = () => callback(["focus", "release"]);
source.addEventListener("keyup", keyUp, false);
source.addEventListener("keydown", keyDown, false);
source.addEventListener("focus", focus, false);
source.addEventListener("blur", blur, false);
source.focus({ focusVisible: true } as FocusOptions);
return () => {
source.removeEventListener("keyup", keyUp, false);
source.removeEventListener("keydown", keyDown, false);
source.removeEventListener("focus", focus, false);
source.removeEventListener("blur", blur, false);
};
} else {
return ["blur", "release"];
}
}) as Source<KeyEvent>;
}