Keyboard Shortcuts
Custom keyboard bindings: adding a shortcut the default set doesn’t cover, replacing an existing binding, or wiring keyboard input in a custom UI without DesktopUiPlugin.
Prerequisites: Video Quick Start.
Default bindings
When KeyHandlerPlugin is registered alongside DesktopUiPlugin, it installs these bindings by default (the video player subclass extends the base set):
| Key | Action |
|---|---|
| Space | Toggle playback |
f | Toggle fullscreen |
m | Toggle mute |
← / → | Seek ±5 seconds |
↑ / ↓ | Volume ±5% |
v / 5 | Cycle subtitle tracks |
Adding custom bindings alongside DesktopUiPlugin
Subclass KeyHandlerPlugin and override the binding group methods, then register it alongside DesktopUiPlugin:
import nmplayer from '@nomercy-entertainment/nomercy-video-player';
import { DesktopUiPlugin, KeyHandlerPlugin } from '@nomercy-entertainment/nomercy-video-player/plugins';
// KeyHandlerPlugin<T> is generic over the playlist item type, not the player type.
class MyKeyHandler extends KeyHandlerPlugin {
// Different id so both this and the built-in can coexist,
// or use 'video-key-handler' (the built-in id) to replace the default.
static override readonly id = 'my-key-handler';
protected override addPlaybackKeys(): void {
super.addPlaybackKeys(); // keep all the default bindings
// Add extra bindings using this.bind(key, handler):
this.bind('n', () => { void this.player.next(); }); // 'n' for next
this.bind('p', () => { void this.player.previous(); }); // 'p' for previous
this.bind('t', () => { this.player.toggleTheater(); }); // 't' for theater
}
}
const player = nmplayer('player')
.addPlugin(DesktopUiPlugin)
.addPlugin(MyKeyHandler)
.setup({ playlist: [] });
Standalone KeyHandlerPlugin (no DesktopUiPlugin)
For custom UIs that don’t use DesktopUiPlugin, register KeyHandlerPlugin directly:
import { nmplayer } from '@nomercy-entertainment/nomercy-video-player';
import { KeyHandlerPlugin } from '@nomercy-entertainment/nomercy-video-player/plugins';
const player = nmplayer('main')
.addPlugin(KeyHandlerPlugin)
.setup({
playlist: [{ id: '1', url: '...m3u8' }],
});
// Bind keys via the plugin after registration:
const keyHandler = player.getPlugin(KeyHandlerPlugin);
keyHandler.bind(' ', (playerInstance) => playerInstance.togglePlayback()); // Space = toggle
keyHandler.bind('f', (playerInstance) => playerInstance.toggleFullscreen()); // f = fullscreen
keyHandler.bind('ArrowLeft', (playerInstance) => playerInstance.rewind(10)); // ← = seek back 10s
keyHandler.bind('ArrowRight', (playerInstance) => playerInstance.forward(10)); // → = seek forward 10s
Key name format
Key names follow the KeyboardEvent.key standard. Common values:
| Key | .key value |
|---|---|
| Space | ' ' (a single space) |
| Arrow keys | 'ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown' |
| Letters | 'a'…'z' (lowercase) |
| F keys | 'F1'…'F12' |
| Escape | 'Escape' |
| Enter | 'Enter' |
Conflict resolution
KeyHandlerPlugin captures keyboard events on document by default.
Set scope: 'container' to scope them to the player element only.
Note on
scope: 'container': the container element must havetabindex="0"or another means of receiving keyboard focus. Keys fire only while the container (or a child inside it) has focus. Withouttabindex="0"the container is never focused and no key events reach the plugin.
<div id="player" tabindex="0" style="width: 100%; aspect-ratio: 16/9;"></div>
If you have page-level key handlers (e.g. a search input), the player should not steal those events.
Use the when option to suppress all key handling when a condition is true — for example, while a modal is open or when focus is inside a specific element:
let modalOpen = false;
player.addPlugin(KeyHandlerPlugin, {
// Return false to block all key handling for that event.
when: (e) => {
if (modalOpen) return false;
const tag = (e.target as HTMLElement)?.tagName;
return tag !== 'INPUT' && tag !== 'TEXTAREA';
},
});
// Suspend key handling while a modal is open:
modalOpen = true;
// Restore when closed:
modalOpen = false;
Removing a binding
const keyHandler = player.getPlugin(KeyHandlerPlugin);
// Remove a specific key:
keyHandler.unbind('c');
// Replace all bindings with an empty set:
player.addPlugin(KeyHandlerPlugin, { extend: false });
What to read next
- Desktop UI: full list of default bindings and how DesktopUiPlugin manages them
- Plugin Authoring: writing a plugin that hooks into the key handler event stream
- Recipes: Media Session: pairing keyboard shortcuts with system media keys