Skip to content

Key Handler

KeyHandlerPlugin is the video player’s keyboard binding layer. It subclasses the core’s base KeyHandlerPlugin and adds the full v1 binding set on top of the core’s cooldown, scope, when, and cleanup infrastructure. Register it explicitly on any deployment where keyboard control is needed. DesktopUiPlugin does not include or register KeyHandlerPlugin - both plugins must be added independently via addPlugin().

Plugin id

'video-key-handler'

Import

TypeScript
import { KeyHandlerPlugin } from '@nomercy-entertainment/nomercy-video-player/plugins';

What it does

All binding groups are protected methods, so you can subclass and override one group without touching the rest. Override addDefaults() to drop the entire video binding set and start from scratch.

The plugin binds the following groups by default:

GroupKeys
PlaybackSpace, MediaPlay, MediaPause, MediaPlayPause, MediaStop, MediaRewind, MediaFastForward
NavigationArrowLeft (rewind), ArrowRight (forward), disabled on TV
VolumeArrowUp / ArrowDown (desktop only, not TV or mobile), m (mute)
Media keysSubtitle / 5 / v cycles subtitles; Audio / 2 / b cycles audio tracks
Modifier seeksShift+Arrow 3s, Alt+Arrow 10s, Ctrl+Arrow 60s
Quick skip1 forward 120s, 3 forward 30s, 6 forward 60s, 9 forward 90s; TV color buttons ColorF0Red 30s, ColorF1Green 60s, ColorF2Yellow 90s, ColorF3Blue 120s
Next / PrevMediaTrackNext, MediaTrackPrevious, n, p
ChaptersShift+N (next chapter), Shift+P (previous chapter)
Fullscreenf, F11, Escape (exits fullscreen only)
Speed] faster, [ slower, = reset to 1x
Frame advancee advances one frame (~1/30s) when paused
Show timet shows current and remaining time as an OSD message
Subtitle size+ or Shift++ emits 'subtitle-size-up'; - emits 'subtitle-size-down'
Aspect ratioa, BrowserFavorites cycles aspect ratio
Stops
HelpShift+? emits 'plugin:desktop-ui:shortcuts-toggle'

Options

KeyHandlerPlugin inherits KeyHandlerOptions from the core base class. No video-specific options are added.

TypeScript
interface KeyHandlerOptions<P> {
/** Where the keydown listener is attached. Default: 'document'. */
scope?: 'document' | 'container' | HTMLElement;

/** Extra bindings merged on top of the default groups. Same combo wins over the default. */
bindings?: Record<string, (player: P) => void>;

/** When false, default bindings are cleared before opts.bindings is applied. Default: true. */
extend?: boolean;

/** Gate predicate. Return false to suppress all key handling for that event. */
when?: (e: KeyboardEvent) => boolean;

/** Minimum milliseconds between consecutive fires of the same key. Default: 300. */
cooldownMs?: number;

/** When true, hardware media keys (MediaPlay, MediaPause, etc.) are silently ignored. Default: false. */
disableMediaControls?: boolean;
}
OptionTypeDefaultDescription
scope'document' | 'container' | HTMLElement'document'Where the keydown listener is attached
bindingsRecord<string, fn>undefinedAdditional combos merged on top of the video default groups
extendbooleantruefalse clears all defaults before bindings is applied
when(e: KeyboardEvent) => booleannoneReturn false to suppress all keys for that event
cooldownMsnumber300Minimum ms between consecutive fires of the same key
disableMediaControlsbooleanfalseSuppress hardware media key handling

The disableControls and disableMediaControls flags in VideoPlayerConfig are also respected. Pass them in setup() rather than in the plugin options when the intent is to disable keyboard control globally.

Methods

These public methods are inherited from the core base class. Access the plugin instance with player.getPlugin(KeyHandlerPlugin).

MethodSignatureDescription
bind(combo: string, fn: (player) => void): voidRegister or replace a handler for a combo string
unbind(combo: string): voidRemove the handler for a combo string
replace(combo: string, fn: (player) => void): voidSemantic alias for bind
bindings(): ReadonlyMap<string, fn>Snapshot of the current binding map
scope(): EventTargetThe target the keydown listener is attached to

Registration

TypeScript
import nmplayer from '@nomercy-entertainment/nomercy-video-player';
import { KeyHandlerPlugin } from '@nomercy-entertainment/nomercy-video-player/plugins';

const player = nmplayer('player')
.addPlugin(KeyHandlerPlugin)
.setup({
baseUrl: 'https://raw.githubusercontent.com/NoMercy-Entertainment/nomercy-media/master/Films',
playlist: [
{
title: 'Big Buck Bunny',
url: '/Big.Buck.Bunny.(2008)/Big.Buck.Bunny.(2008).NoMercy.m3u8',
},
],
});

Disabling controls

Set disableControls: true in VideoPlayerConfig to suppress all keyboard bindings. Set disableMediaControls: true to suppress only the hardware media keys (MediaPlay, MediaPause, MediaStop, MediaRewind, MediaFastForward, MediaTrackNext, MediaTrackPrevious):

TypeScript
player.setup({
disableControls: false,
disableMediaControls: false,
playlist: [ /* ... */ ],
});

Subclassing

All binding groups are protected methods. Subclass KeyHandlerPlugin and override any group without rewriting the rest:

TypeScript
import { KeyHandlerPlugin as VideoKeyHandler } from '@nomercy-entertainment/nomercy-video-player/plugins';

class CustomKeyHandler extends VideoKeyHandler {
protected override addNavigationKeys(): void {
this.bind('ArrowLeft', () => {
void this.player.rewind?.(30);
});

this.bind('ArrowRight', () => {
void this.player.forward?.(30);
});
}
}

OSD messages

Bindings that change state (speed, aspect ratio) use this.message(text) to emit an OSD notification. This calls player.displayMessage(text) if the player exposes it, and always emits 'display-message' on the player so any custom OSD widget can subscribe:

TypeScript
player.on('display-message', ({ text }) => {
showOsd(text);
});

See also