Skip to content

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):

KeyAction
SpaceToggle playback
fToggle fullscreen
mToggle mute
/ Seek ±5 seconds
/ Volume ±5%
v / 5Cycle subtitle tracks

Adding custom bindings alongside DesktopUiPlugin

Subclass KeyHandlerPlugin and override the binding group methods, then register it alongside DesktopUiPlugin:

TypeScript
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:

TypeScript
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 have tabindex="0" or another means of receiving keyboard focus. Keys fire only while the container (or a child inside it) has focus. Without tabindex="0" the container is never focused and no key events reach the plugin.

HTML
<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:

TypeScript
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

TypeScript
const keyHandler = player.getPlugin(KeyHandlerPlugin);

// Remove a specific key:
keyHandler.unbind('c');

// Replace all bindings with an empty set:
player.addPlugin(KeyHandlerPlugin, { extend: false });