navius

Keyboard Shortcuts

A global keyboard-shortcut registry you inject. Register a chord with a handler, hold the returned token for its lifetime, and dispose it to unregister, the same engine-handle idiom used across the brain.

Press mod + J, or ?, anywhere on the page.

Fired 0 times.

Last chord: none yet

How it works

KeyboardShortcutService is registered scoped by AddNavius() (the same DI shape as the toast manager). Inject it anywhere. The one hard problem it solves: a global shortcut that must call event.preventDefault() (to stop the browser's own Ctrl+K or "/" handling) has to do so synchronously, before any Blazor interop round trip resolves. So the service pushes the effective chord table down to a single JS keydown listener; JS decides preventDefault off that table and then dispatches the matched chord back to C# for handler execution.

Registering a chord

Inject the service, register on first render, and dispose the token on teardown. A handler that throws is swallowed so one bad handler cannot tear down the shared listener.

Chord syntax

A chord is a normalized, case-insensitive string of modifiers and one key joined by +. Modifiers are ctrl, alt, shift, meta and mod. mod fans out to both ctrl and meta, so one registration is cross-platform. This is an MVP: single chords only (no g d-style sequences).

Data attribute Values
mod+k Ctrl+K on Windows/Linux, Cmd+K on macOS (mod fans out to both)
shift+? Shift plus the ? key
ctrl+alt+delete Multiple explicit modifiers plus a key
escape A bare key, no modifiers

Scoping

A shortcut registered with a non-null Scope only fires while that scope is pushed; global (null-scope) shortcuts always fire. Dialogs and command palettes push a scope on open and dispose it on close, so their shortcuts are live only while they are.

API Reference

Injected (scoped, via AddNavius). Register chords and push scopes; both return an IDisposable token you dispose to undo.

Prop Type Default
Register(ShortcutOptions options, Func<Task> handler) IDisposable -
PushScope(string scope) IDisposable -
OnShortcut(string chord) Task (JSInvokable) -
DisposeAsync() ValueTask -

The record passed to Register. A null Scope means global.

Prop Type Default
Chord string required
Scope string? null (global)
PreventDefault bool true
AllowInInputs bool false
Repeat bool false