doomkeys.ts
examples/doom/sim/doomkeys.ts · raw · open the example · all examples · site home
Exports: DoomKeyDoomKeyEventtranslateKeymouseButtonMaskKEY_BINDINGS_HELP
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 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
// Browser KeyboardEvent -> Doom key codes (doomkeys.h).
//
// Doom events carry two values: data1 is the key identifier bound to
// actions (movement, fire, menus) and data2 is the typed character used by
// menus, chat, and cheat codes. WASD is mapped to the arrow/strafe keys in
// data1 while still reporting the letter in data2, so "idkfa" keeps working.
export const DoomKey = {
RIGHTARROW: 0xae,
LEFTARROW: 0xac,
UPARROW: 0xad,
DOWNARROW: 0xaf,
STRAFE_L: 0xa0,
STRAFE_R: 0xa1,
USE: 0xa2,
FIRE: 0xa3,
ESCAPE: 27,
ENTER: 13,
TAB: 9,
F1: 0x80 + 0x3b,
F2: 0x80 + 0x3c,
F3: 0x80 + 0x3d,
F4: 0x80 + 0x3e,
F5: 0x80 + 0x3f,
F6: 0x80 + 0x40,
F7: 0x80 + 0x41,
F8: 0x80 + 0x42,
F9: 0x80 + 0x43,
F10: 0x80 + 0x44,
F11: 0x80 + 0x57,
F12: 0x80 + 0x58,
BACKSPACE: 0x7f,
PAUSE: 0xff,
EQUALS: 0x3d,
MINUS: 0x2d,
RSHIFT: 0x80 + 0x36,
RCTRL: 0x80 + 0x1d,
RALT: 0x80 + 0x38,
CAPSLOCK: 0x80 + 0x3a,
HOME: 0x80 + 0x47,
END: 0x80 + 0x4f,
PGUP: 0x80 + 0x49,
PGDN: 0x80 + 0x51,
INS: 0x80 + 0x52,
DEL: 0x80 + 0x53,
} as const;
export interface DoomKeyEvent {
key: number;
typed: number;
}
const CODE_TO_KEY: Record<string, number> = {
ArrowUp: DoomKey.UPARROW,
ArrowDown: DoomKey.DOWNARROW,
ArrowLeft: DoomKey.LEFTARROW,
ArrowRight: DoomKey.RIGHTARROW,
KeyW: DoomKey.UPARROW,
KeyS: DoomKey.DOWNARROW,
KeyA: DoomKey.STRAFE_L,
KeyD: DoomKey.STRAFE_R,
KeyQ: DoomKey.LEFTARROW,
KeyE: DoomKey.RIGHTARROW,
Space: DoomKey.USE,
ControlLeft: DoomKey.FIRE,
ControlRight: DoomKey.FIRE,
ShiftLeft: DoomKey.RSHIFT,
ShiftRight: DoomKey.RSHIFT,
AltLeft: DoomKey.RALT,
AltRight: DoomKey.RALT,
Escape: DoomKey.ESCAPE,
Enter: DoomKey.ENTER,
NumpadEnter: DoomKey.ENTER,
Tab: DoomKey.TAB,
Backspace: DoomKey.BACKSPACE,
Pause: DoomKey.PAUSE,
Equal: DoomKey.EQUALS,
Minus: DoomKey.MINUS,
NumpadAdd: DoomKey.EQUALS,
NumpadSubtract: DoomKey.MINUS,
CapsLock: DoomKey.CAPSLOCK,
Home: DoomKey.HOME,
End: DoomKey.END,
PageUp: DoomKey.PGUP,
PageDown: DoomKey.PGDN,
Insert: DoomKey.INS,
Delete: DoomKey.DEL,
F1: DoomKey.F1,
F2: DoomKey.F2,
F3: DoomKey.F3,
F4: DoomKey.F4,
F5: DoomKey.F5,
F6: DoomKey.F6,
F7: DoomKey.F7,
F8: DoomKey.F8,
F9: DoomKey.F9,
F10: DoomKey.F10,
F11: DoomKey.F11,
F12: DoomKey.F12,
};
// Returns undefined for keys Doom has no use for.
export function translateKey(event: KeyboardEvent): DoomKeyEvent | undefined {
const typed = typedChar(event);
const mapped = CODE_TO_KEY[event.code];
if (mapped !== undefined) {
return { key: mapped, typed };
}
// Printable ASCII: Doom uses the lowercase character as the key id.
if (event.key.length === 1) {
const code = event.key.toLowerCase().charCodeAt(0);
if (code >= 32 && code < 127) {
return { key: code, typed };
}
}
return undefined;
}
function typedChar(event: KeyboardEvent): number {
if (event.key.length === 1) {
const code = event.key.charCodeAt(0);
return code >= 32 && code < 127 ? code : 0;
}
switch (event.key) {
case "Enter":
return 13;
case "Backspace":
return 0x7f;
case "Escape":
return 27;
case "Tab":
return 9;
default:
return 0;
}
}
// Mouse buttons in Doom's ev_mouse data1 order: fire, strafe, forward.
export function mouseButtonMask(buttons: number): number {
let mask = 0;
if (buttons & 1) mask |= 1; // left -> fire
if (buttons & 2) mask |= 2; // right -> strafe
if (buttons & 4) mask |= 4; // middle -> forward
return mask;
}
export const KEY_BINDINGS_HELP = [
"W/S or arrows: move, A/D: strafe, Q/E or arrows: turn",
"Mouse: turn, left button: fire, right button: strafe",
"Ctrl: fire, Space: use, Shift: run, Alt: strafe modifier",
"1-7: weapons, Tab: map, Esc: menu, Enter/Y/N: menu select",
"F2/F3 save/load, F5 detail, F6 quicksave, F9 quickload, Pause",
];