Matcher
Match keyboard events against parsed key bindings and create standalone handlers.
import {
matchesKeyboardEvent,
isInputElement,
createKeyBindHandler,
createMultiKeyBindHandler,
} from '@gentleduck/vim/matcher'
Types
MatchOptions
interface MatchOptions {
/** Ignore case when comparing the non-modifier key. Default: true */
ignoreCase?: boolean
}
SingleKeyBindOptions
interface SingleKeyBindOptions {
enabled?: boolean // Default: true
preventDefault?: boolean // Default: false
stopPropagation?: boolean // Default: false
ignoreInputs?: boolean // Default: false
}
KeyBindHandlerConfig
interface KeyBindHandlerConfig {
binding: string
handler: (event: KeyboardEvent) => void
options?: SingleKeyBindOptions
}
Functions
matchesKeyboardEvent(parsed, event, options?)
Low-level check: does this KeyboardEvent match a ParsedKeyBind?
function matchesKeyboardEvent(
parsed: ParsedKeyBind,
event: KeyboardEvent,
options?: MatchOptions
): boolean
Checks all four modifier flags (ctrlKey, altKey, metaKey, shiftKey) for exact match, then compares the non-modifier key. Handles aliases like space and esc automatically.
Example:
import { parseKeyBind } from '@gentleduck/vim/parser'
const parsed = parseKeyBind('ctrl+s')
document.addEventListener('keydown', (e) => {
if (matchesKeyboardEvent(parsed, e)) {
e.preventDefault()
save()
}
})
createKeyBindHandler or createMultiKeyBindHandler which handle options like preventDefault and ignoreInputs for you.isInputElement(el)
Returns true if the element is a text-entry input where key bindings should typically be suppressed.
function isInputElement(el: Element | null): boolean
Considers these as input elements: <input> (except button/submit/reset types), <textarea>, <select>, and any element with contentEditable.
<input type="button">, <input type="submit">, <input type="reset">) return false because they are not text-entry fields.createKeyBindHandler(config)
Creates a standalone keydown event handler for a single binding. This is the simplest way to bind a shortcut without using the full registry system.
function createKeyBindHandler(config: KeyBindHandlerConfig): (event: KeyboardEvent) => void
Example:
Create the handler with your binding and options:
const handler = createKeyBindHandler({
binding: 'Mod+S',
handler: () => save(),
options: { preventDefault: true, ignoreInputs: true },
})
Attach it to the DOM:
document.addEventListener('keydown', handler)
Clean up when no longer needed:
document.removeEventListener('keydown', handler)
createMultiKeyBindHandler(configs)
Creates a single event handler that checks multiple bindings. First match wins.
function createMultiKeyBindHandler(configs: KeyBindHandlerConfig[]): (event: KeyboardEvent) => void
Example:
const handler = createMultiKeyBindHandler([
{
binding: 'Mod+S',
handler: () => save(),
options: { preventDefault: true },
},
{
binding: 'Mod+Shift+S',
handler: () => saveAs(),
options: { preventDefault: true },
},
{
binding: 'Mod+Z',
handler: () => undo(),
options: { preventDefault: true },
},
])
document.addEventListener('keydown', handler)