Skip to content

Global Windows keyboard listener for Deno with zero dependencies.

License

Notifications You must be signed in to change notification settings

nktkas/keyboard-hook

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

36 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

keyboard-hook

JSR

Global Windows keyboard listener for Deno with zero dependencies.

Usage example

import { KeyboardHook, VirtualKeyCodes } from "@nktkas/keyboard-hook";

const hook = new KeyboardHook();
hook.addEventListener("keydown", (event) => {
    console.log("Key down:", VirtualKeyCodes[event.detail.vkCode]);
});
hook.addEventListener("keyup", (event) => {
    console.log("Key up:", VirtualKeyCodes[event.detail.vkCode]);
});
hook.addEventListener("syskeydown", (event) => {
    console.log("System key down:", VirtualKeyCodes[event.detail.vkCode]);
});
hook.addEventListener("syskeyup", (event) => {
    console.log("System key up:", VirtualKeyCodes[event.detail.vkCode]);
});

// When done, clean up resources
// hook.close();

API

/** Contains information about a low-level keyboard input event. */
export interface KeyboardEvent {
    /** A {@link VirtualKeyCodes | virtual-key code}. */
    vkCode: keyof typeof VirtualKeyCodes;
    /** A hardware scan code for the key. */
    scanCode: number;
    /** The extended-key flag, event-injected flags, context code, and transition-state flag. */
    flags: Flags;
    /** Time since the system started, in milliseconds. */
    time: number;
}

/** Disassembled KBDLLHOOKSTRUCT flags. */
export interface Flags {
    /** Set if the key is an extended key (e.g., right Alt, right Ctrl) */
    extended: boolean;
    /** Set if the event was generated by SendInput with KEYEVENTF_LOWER_IL_INJECTED */
    lowerIlInjected: boolean;
    /** Set if the event was injected */
    injected: boolean;
    /** Set if Alt key is pressed */
    altDown: boolean;
    /** Set if the key is being released (up event) */
    up: boolean;
}

/** A class to globally listen for keyboard events in Windows. */
export class KeyboardHook extends EventTarget {
    /** Strictly typed addEventListener. */
    addEventListener(
        type: "keydown" | "keyup" | "syskeydown" | "syskeyup",
        listener: (event: CustomEvent<KeyEvent>) => void,
    ): void;

    /** Stops the keyboard hook and cleans up resources. */
    close(): void;
}

/** Enumeration of virtual-key codes and their corresponding names. */
export const VirtualKeyCodes = {
    /** Left mouse button */
    0x01: "LBUTTON",
    /** Right mouse button */
    0x02: "RBUTTON",
    /** Control-break processing */
    0x03: "CANCEL",
    /** Middle mouse button */
    0x04: "MBUTTON",
    /** X1 mouse button */
    0x05: "XBUTTON1",
    /** X2 mouse button */
    0x06: "XBUTTON2",
    /** Backspace key */
    0x08: "BACK",
    /** Tab key */
    0x09: "TAB",
    /** Clear key */
    0x0C: "CLEAR",
    /** Enter key */
    0x0D: "RETURN",
    /** Shift key */
    0x10: "SHIFT",
    /** Ctrl key */
    0x11: "CONTROL",
    /** Alt key */
    0x12: "MENU",
    /** Pause key */
    0x13: "PAUSE",
    /** Caps lock key */
    0x14: "CAPITAL",
    /** IME Kana mode */
    0x15: "KANA",
    /** IME On */
    0x16: "IME_ON",
    /** IME Junja mode */
    0x17: "JUNJA",
    /** IME final mode */
    0x18: "FINAL",
    /** IME Kanji mode */
    0x19: "KANJI",
    /** IME Off */
    0x1A: "IME_OFF",
    /** Esc key */
    0x1B: "ESCAPE",
    /** IME convert */
    0x1C: "CONVERT",
    /** IME nonconvert */
    0x1D: "NONCONVERT",
    /** IME accept */
    0x1E: "ACCEPT",
    /** IME mode change request */
    0x1F: "MODECHANGE",
    /** Spacebar key */
    0x20: "SPACE",
    /** Page up key */
    0x21: "PRIOR",
    /** Page down key */
    0x22: "NEXT",
    /** End key */
    0x23: "END",
    /** Home key */
    0x24: "HOME",
    /** Left arrow key */
    0x25: "LEFT",
    /** Up arrow key */
    0x26: "UP",
    /** Right arrow key */
    0x27: "RIGHT",
    /** Down arrow key */
    0x28: "DOWN",
    /** Select key */
    0x29: "SELECT",
    /** Print key */
    0x2A: "PRINT",
    /** Execute key */
    0x2B: "EXECUTE",
    /** Print screen key */
    0x2C: "SNAPSHOT",
    /** Insert key */
    0x2D: "INSERT",
    /** Delete key */
    0x2E: "DELETE",
    /** Help key */
    0x2F: "HELP",
    /** 0 key */
    0x30: "0",
    /** 1 key */
    0x31: "1",
    /** 2 key */
    0x32: "2",
    /** 3 key */
    0x33: "3",
    /** 4 key */
    0x34: "4",
    /** 5 key */
    0x35: "5",
    /** 6 key */
    0x36: "6",
    /** 7 key */
    0x37: "7",
    /** 8 key */
    0x38: "8",
    /** 9 key */
    0x39: "9",
    /** A key */
    0x41: "A",
    /** B key */
    0x42: "B",
    /** C key */
    0x43: "C",
    /** D key */
    0x44: "D",
    /** E key */
    0x45: "E",
    /** F key */
    0x46: "F",
    /** G key */
    0x47: "G",
    /** H key */
    0x48: "H",
    /** I key */
    0x49: "I",
    /** J key */
    0x4A: "J",
    /** K key */
    0x4B: "K",
    /** L key */
    0x4C: "L",
    /** M key */
    0x4D: "M",
    /** N key */
    0x4E: "N",
    /** O key */
    0x4F: "O",
    /** P key */
    0x50: "P",
    /** Q key */
    0x51: "Q",
    /** R key */
    0x52: "R",
    /** S key */
    0x53: "S",
    /** T key */
    0x54: "T",
    /** U key */
    0x55: "U",
    /** V key */
    0x56: "V",
    /** W key */
    0x57: "W",
    /** X key */
    0x58: "X",
    /** Y key */
    0x59: "Y",
    /** Z key */
    0x5A: "Z",
    /** Left Windows logo key */
    0x5B: "LWIN",
    /** Right Windows logo key */
    0x5C: "RWIN",
    /** Application key */
    0x5D: "APPS",
    /** Computer Sleep key */
    0x5F: "SLEEP",
    /** Numeric keypad 0 key */
    0x60: "NUMPAD0",
    /** Numeric keypad 1 key */
    0x61: "NUMPAD1",
    /** Numeric keypad 2 key */
    0x62: "NUMPAD2",
    /** Numeric keypad 3 key */
    0x63: "NUMPAD3",
    /** Numeric keypad 4 key */
    0x64: "NUMPAD4",
    /** Numeric keypad 5 key */
    0x65: "NUMPAD5",
    /** Numeric keypad 6 key */
    0x66: "NUMPAD6",
    /** Numeric keypad 7 key */
    0x67: "NUMPAD7",
    /** Numeric keypad 8 key */
    0x68: "NUMPAD8",
    /** Numeric keypad 9 key */
    0x69: "NUMPAD9",
    /** Multiply key */
    0x6A: "MULTIPLY",
    /** Add key */
    0x6B: "ADD",
    /** Separator key */
    0x6C: "SEPARATOR",
    /** Subtract key */
    0x6D: "SUBTRACT",
    /** Decimal key */
    0x6E: "DECIMAL",
    /** Divide key */
    0x6F: "DIVIDE",
    /** F1 key */
    0x70: "F1",
    /** F2 key */
    0x71: "F2",
    /** F3 key */
    0x72: "F3",
    /** F4 key */
    0x73: "F4",
    /** F5 key */
    0x74: "F5",
    /** F6 key */
    0x75: "F6",
    /** F7 key */
    0x76: "F7",
    /** F8 key */
    0x77: "F8",
    /** F9 key */
    0x78: "F9",
    /** F10 key */
    0x79: "F10",
    /** F11 key */
    0x7A: "F11",
    /** F12 key */
    0x7B: "F12",
    /** F13 key */
    0x7C: "F13",
    /** F14 key */
    0x7D: "F14",
    /** F15 key */
    0x7E: "F15",
    /** F16 key */
    0x7F: "F16",
    /** F17 key */
    0x80: "F17",
    /** F18 key */
    0x81: "F18",
    /** F19 key */
    0x82: "F19",
    /** F20 key */
    0x83: "F20",
    /** F21 key */
    0x84: "F21",
    /** F22 key */
    0x85: "F22",
    /** F23 key */
    0x86: "F23",
    /** F24 key */
    0x87: "F24",
    /** Num lock key */
    0x90: "NUMLOCK",
    /** Scroll lock key */
    0x91: "SCROLL",
    /** Left Shift key */
    0xA0: "LSHIFT",
    /** Right Shift key */
    0xA1: "RSHIFT",
    /** Left Ctrl key */
    0xA2: "LCONTROL",
    /** Right Ctrl key */
    0xA3: "RCONTROL",
    /** Left Alt key */
    0xA4: "LMENU",
    /** Right Alt key */
    0xA5: "RMENU",
    /** Browser Back key */
    0xA6: "BROWSER_BACK",
    /** Browser Forward key */
    0xA7: "BROWSER_FORWARD",
    /** Browser Refresh key */
    0xA8: "BROWSER_REFRESH",
    /** Browser Stop key */
    0xA9: "BROWSER_STOP",
    /** Browser Search key */
    0xAA: "BROWSER_SEARCH",
    /** Browser Favorites key */
    0xAB: "BROWSER_FAVORITES",
    /** Browser Start and Home key */
    0xAC: "BROWSER_HOME",
    /** Volume Mute key */
    0xAD: "VOLUME_MUTE",
    /** Volume Down key */
    0xAE: "VOLUME_DOWN",
    /** Volume Up key */
    0xAF: "VOLUME_UP",
    /** Next Track key */
    0xB0: "MEDIA_NEXT_TRACK",
    /** Previous Track key */
    0xB1: "MEDIA_PREV_TRACK",
    /** Stop Media key */
    0xB2: "MEDIA_STOP",
    /** Play/Pause Media key */
    0xB3: "MEDIA_PLAY_PAUSE",
    /** Start Mail key */
    0xB4: "LAUNCH_MAIL",
    /** Select Media key */
    0xB5: "LAUNCH_MEDIA_SELECT",
    /** Start Application 1 key */
    0xB6: "LAUNCH_APP1",
    /** Start Application 2 key */
    0xB7: "LAUNCH_APP2",
    /** Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the ;: key */
    0xBA: "OEM_1",
    /** For any country/region, the + key */
    0xBB: "OEM_PLUS",
    /** For any country/region, the , key */
    0xBC: "OEM_COMMA",
    /** For any country/region, the - key */
    0xBD: "OEM_MINUS",
    /** For any country/region, the . key */
    0xBE: "OEM_PERIOD",
    /** Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the /? key */
    0xBF: "OEM_2",
    /** Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the ~ key */
    0xC0: "OEM_3",
    /** Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the [{ key */
    0xDB: "OEM_4",
    /** Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the \| key */
    0xDC: "OEM_5",
    /** Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the ]} key */
    0xDD: "OEM_6",
    /** Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '" key */
    0xDE: "OEM_7",
    /** Used for miscellaneous characters; it can vary by keyboard. */
    0xDF: "OEM_8",
    /** The <> keys on the US standard keyboard, or the \| key on the non-US 102-key keyboard */
    0xE2: "OEM_102",
    /** IME PROCESS key */
    0xE5: "PROCESSKEY",
    /** Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT, SendInput, WM_KEYDOWN, and WM_KEYUP */
    0xE7: "PACKET",
    /** Attn key */
    0xF6: "ATTN",
    /** CrSel key */
    0xF7: "CRSEL",
    /** ExSel key */
    0xF8: "EXSEL",
    /** Erase EOF key */
    0xF9: "EREOF",
    /** Play key */
    0xFA: "PLAY",
    /** Zoom key */
    0xFB: "ZOOM",
    /** Reserved */
    0xFC: "NONAME",
    /** PA1 key */
    0xFD: "PA1",
    /** Clear key */
    0xFE: "OEM_CLEAR",
} as const;

Benchmarks

Keyhold

deno run --allow-ffi .\benchmarks\keyhold.ts
Emit to Receive Latency (ms):
┌───────────────┬───────┬───────┬────────┬───────┬───────────┬───────────┬───────┐
│ Duration (ms) │ Min   │ Avg   │ Median │ Stdev │ 95th %ile │ 99th %ile │ Max   │
├───────────────┼───────┼───────┼────────┼───────┼───────────┼───────────┼───────┤
│ 1000          │ 0.026 │ 0.044 │ 0.037  │ 0.028 │ 0.061     │ 0.238     │ 0.303 │
│ 2000          │ 0.025 │ 0.035 │ 0.029  │ 0.018 │ 0.048     │ 0.060     │ 0.269 │
│ 5000          │ 0.024 │ 0.033 │ 0.027  │ 0.017 │ 0.047     │ 0.054     │ 0.485 │
│ 10000         │ 0.024 │ 0.034 │ 0.029  │ 0.012 │ 0.048     │ 0.058     │ 0.429 │
└───────────────┴───────┴───────┴────────┴───────┴───────────┴───────────┴───────┘

Keypress

deno run --allow-ffi .\benchmarks\keypress.ts
Keydown Latency (ms):
┌───────────┬───────┬───────┬────────┬───────────┬───────────┬───────┐
│ Rate (/s) │ Min   │ Avg   │ Median │ 95th %ile │ 99th %ile │ Max   │
├───────────┼───────┼───────┼────────┼───────────┼───────────┼───────┤
│ 5         │ 0.317 │ 0.460 │ 0.439  │ 0.648     │ 0.682     │ 0.682 │
│ 10        │ 0.285 │ 0.513 │ 0.518  │ 0.685     │ 0.829     │ 0.829 │
│ 20        │ 0.256 │ 0.504 │ 0.535  │ 0.699     │ 0.801     │ 0.833 │
│ 50        │ 0.227 │ 0.362 │ 0.323  │ 0.591     │ 0.685     │ 0.812 │
│ 100       │ 0.212 │ 0.322 │ 0.302  │ 0.501     │ 0.620     │ 0.679 │
└───────────┴───────┴───────┴────────┴───────────┴───────────┴───────┘

Keyup Latency (ms):
┌───────────┬───────┬───────┬────────┬───────────┬───────────┬───────┐
│ Rate (/s) │ Min   │ Avg   │ Median │ 95th %ile │ 99th %ile │ Max   │
├───────────┼───────┼───────┼────────┼───────────┼───────────┼───────┤
│ 5         │ 0.154 │ 0.217 │ 0.206  │ 0.301     │ 0.428     │ 0.428 │
│ 10        │ 0.140 │ 0.291 │ 0.270  │ 0.462     │ 0.611     │ 0.611 │
│ 20        │ 0.117 │ 0.279 │ 0.250  │ 0.475     │ 0.578     │ 0.588 │
│ 50        │ 0.082 │ 0.173 │ 0.140  │ 0.394     │ 0.474     │ 0.515 │
│ 100       │ 0.080 │ 0.130 │ 0.118  │ 0.186     │ 0.415     │ 0.514 │
└───────────┴───────┴───────┴────────┴───────────┴───────────┴───────┘

Related

@nktkas/mouse-hook - Global Windows mouse listener for Deno with zero dependencies.

@nktkas/windows-screenshot - Windows screen capture for Deno with zero dependencies.

About

Global Windows keyboard listener for Deno with zero dependencies.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published