register
Category: Global Hotkeys
Namespace: web.hotkey.register
Description
Registers a system-wide global hotkey with Windows. Once registered, the hotkey fires web.events.onHotkey whenever the key combination is pressed — even if the app is minimized, hidden in the system tray, or another application has focus.
Syntax
const success = await web.hotkey.register({
id: 1,
key: 'H',
modifiers: 'ctrl+alt',
passthrough: false // optional, default false
});
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
id |
integer | Yes | — | Unique hotkey identifier, >= 1. Used to identify which hotkey fired in the onHotkey callback. No upper limit. |
key |
string | Yes | — | The key to listen for. See Supported Keys below. |
modifiers |
string | No | '' |
One or more modifier keys joined with +. Omit or pass '' for no modifier. See Supported Modifiers below. |
passthrough |
boolean | No | false |
When true, uses a low-level keyboard hook (WH_KEYBOARD_LL) instead of RegisterHotKey. The key is not consumed — it still reaches whatever application currently has focus. Useful for soundboards where you want sounds to play while the user is typing in another app. See Passthrough Mode below. |
Supported Modifiers
Combine any of these with +:
| Modifier | Description |
|---|---|
ctrl |
Ctrl key |
alt |
Alt key |
shift |
Shift key |
win |
Windows key |
Examples: 'ctrl+alt', 'ctrl+shift', 'alt+shift', 'ctrl+alt+shift', 'win'
Passing '' or omitting modifiers registers the hotkey with no modifier (MOD_NONE) — the hotkey fires whenever that key is pressed anywhere in Windows, regardless of other keys held. Useful for soundboards and gaming overlays where you want raw key presses to trigger actions.
Supported Keys
Letters: A through Z
Digits: 0 through 9
Function keys: F1 through F12
Special keys:
| Key name | Description |
|---|---|
SPACE |
Spacebar |
ENTER or RETURN |
Enter key |
ESC or ESCAPE |
Escape key |
TAB |
Tab key |
DELETE |
Delete key |
INSERT |
Insert key |
HOME |
Home key |
END |
End key |
PAGEUP |
Page Up key |
PAGEDOWN |
Page Down key |
UP |
Up arrow |
DOWN |
Down arrow |
LEFT |
Left arrow |
RIGHT |
Right arrow |
Key names are case-insensitive — 'h', 'H', and 'Home' all work.
Returns
boolean — true if the hotkey was registered successfully, false if the key combination is already taken by another application.
Note: Returns
false, does NOT throw an error. Always check the return value.
Examples
Basic — register a single hotkey
document.addEventListener('DOMContentLoaded', async () => {
web.events.onHotkey = function(id) {
if (id === 1) alert('Ctrl+Alt+H was pressed!');
};
await web.hotkey.register({ id: 1, key: 'H', modifiers: 'ctrl+alt' });
});
Restore app from minimized — bring to front with a hotkey
document.addEventListener('DOMContentLoaded', async () => {
// Pressing Ctrl+Shift+R anywhere in Windows restores this app
web.events.onHotkey = async function(id) {
if (id === 1) {
await web.app.windowRestore();
}
};
const ok = await web.hotkey.register({ id: 1, key: 'R', modifiers: 'ctrl+shift' });
if (ok) {
console.log('Press Ctrl+Shift+R to restore this app from anywhere');
}
});
Multiple hotkeys — different actions per key
document.addEventListener('DOMContentLoaded', async () => {
web.events.onHotkey = async function(id) {
switch (id) {
case 1:
// Bring app to front
await web.app.windowRestore();
break;
case 2:
// Quick-capture clipboard text
const text = await web.clipboard.readText();
addToLog(text);
break;
case 3:
// Toggle app visibility
const state = await web.window.getState();
if (state === 'minimized') {
await web.app.windowRestore();
} else {
await web.app.windowMinimize();
}
break;
}
};
await web.hotkey.register({ id: 1, key: 'F12', modifiers: 'ctrl+shift' });
await web.hotkey.register({ id: 2, key: 'C', modifiers: 'ctrl+alt' });
await web.hotkey.register({ id: 3, key: 'H', modifiers: 'ctrl+alt' });
});
Handle registration failure gracefully
const ok = await web.hotkey.register({ id: 1, key: 'SPACE', modifiers: 'ctrl+alt' });
if (!ok) {
// Try a fallback key combination
const ok2 = await web.hotkey.register({ id: 1, key: 'SPACE', modifiers: 'ctrl+shift' });
if (!ok2) {
console.log('Could not register any hotkey — all combos taken');
}
}
Re-register with a different key — user-configurable hotkey
// If id 1 is already registered, calling register again with the same id
// automatically unregisters the old key combo first, then registers the new one.
// No need to call unregister() manually.
await web.hotkey.register({ id: 1, key: 'H', modifiers: 'ctrl+alt' });
// ...later, user changes preference...
await web.hotkey.register({ id: 1, key: 'J', modifiers: 'ctrl+alt' });
// Now Ctrl+Alt+J fires id 1, Ctrl+Alt+H is released
Soundboard / gaming overlay — register many bare keys with no modifiers
// Register every bound key as a no-modifier global hotkey.
// Fires even when the app is minimized behind a full-screen game.
const soundMap = { 1: 'kick', 2: 'snare', 3: 'hihat', 4: 'laser' };
web.events.onHotkey = function(id) {
playSound(soundMap[id]);
};
await web.hotkey.register({ id: 1, key: 'Q', modifiers: '' });
await web.hotkey.register({ id: 2, key: 'W', modifiers: '' });
await web.hotkey.register({ id: 3, key: 'E', modifiers: '' });
await web.hotkey.register({ id: 4, key: 'R', modifiers: '' });
// ...register as many as you need
⚠️ Bare key hotkeys steal the key from every app. Use this pattern only for dedicated hardware (macro pads, stream decks, numpads) or when the app is in an exclusive "hotkey mode" that the user explicitly enables and can toggle off.
Passthrough mode — sounds play while still typing in another app
// With passthrough: true the key is observed via WH_KEYBOARD_LL.
// The sound fires but the keypress is NOT consumed — 's' still types in Word/Notepad.
web.events.onHotkey = function(id) {
playSound(soundMap[id]);
};
await web.hotkey.register({ id: 1, key: 'Q', modifiers: '', passthrough: true });
await web.hotkey.register({ id: 2, key: 'W', modifiers: '', passthrough: true });
await web.hotkey.register({ id: 3, key: 'E', modifiers: '', passthrough: true });
Passthrough Mode
By default (passthrough: false) the hotkey is registered with Windows RegisterHotKey. This intercepts the key — it never reaches the foreground application. This is intentional for most hotkey use cases (shortcuts, restore-from-tray, etc.) but is undesirable when the user is actively typing.
When passthrough: true:
- The key is watched via a low-level keyboard hook (
WH_KEYBOARD_LL) instead ofRegisterHotKey web.events.onHotkeyfires normally when the key is pressed in any app- The key is not consumed — it still reaches the focused application (e.g. types
sinto Word) - When your own app has focus, the browser's
keydownevent already fires — the hook skips firing the callback to avoid double-triggering modifiersis ignored in passthrough mode (the hook fires on bare VK code only)unregisterandunregisterAllwork the same for passthrough and standard hotkeys
| Mode | Key consumed? | Works in background? | Modifier support |
|---|---|---|---|
Standard (passthrough: false) |
Yes — key stolen from other apps | Yes | Yes |
Passthrough (passthrough: true) |
No — key reaches foreground app | Yes | No |
Notes
- If you register an ID that's already registered, the old key combo is automatically unregistered and replaced with the new one
- Key combinations claimed by Windows itself (like
Ctrl+Alt+Delete) or by other running applications will causeregisterto returnfalse - Common "safe" combinations with modifiers:
Ctrl+Alt+<letter>,Ctrl+Shift+F<n>,Win+Shift+<letter> - No-modifier hotkeys (
modifiers: '') are supported and useful for gaming/soundboard use cases, but they intercept the key globally — use with care - The hotkey fires regardless of which application has focus — this is a Windows-level feature, not a browser feature
- All hotkeys are automatically cleaned up when the app exits