Skip to content

Commit

Permalink
feat: global hotkey support
Browse files Browse the repository at this point in the history
  • Loading branch information
sinaru committed Dec 27, 2024
1 parent ecef37c commit 13775d5
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 0 deletions.
17 changes: 17 additions & 0 deletions src/js/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,8 @@ class Player extends Component {

this.boundUpdatePlayerHeightOnAudioOnlyMode_ = (e) => this.updatePlayerHeightOnAudioOnlyMode_(e);

this.boundGlobalKeydown_ = (e) => this.handleGlobalKeydown_(e);

// default isFullscreen_ to false
this.isFullscreen_ = false;

Expand Down Expand Up @@ -611,6 +613,10 @@ class Player extends Component {
this.on('keydown', (e) => this.handleKeyDown(e));
this.on('languagechange', (e) => this.handleLanguagechange(e));

if (this.isGlobalHotKeysEnabled()) {
Events.on(document.body, 'keydown', this.boundGlobalKeydown_);
}

this.breakpoints(this.options_.breakpoints);
this.responsive(this.options_.responsive);

Expand Down Expand Up @@ -646,6 +652,7 @@ class Player extends Component {
// Make sure all player-specific document listeners are unbound. This is
Events.off(document, this.fsApi_.fullscreenchange, this.boundDocumentFullscreenChange_);
Events.off(document, 'keydown', this.boundFullWindowOnEscKey_);
Events.off(document.body, 'keydown', this.boundGlobalKeydown_);

if (this.styleEl_ && this.styleEl_.parentNode) {
this.styleEl_.parentNode.removeChild(this.styleEl_);
Expand Down Expand Up @@ -2247,6 +2254,12 @@ class Player extends Component {
this.trigger('textdata', data);
}

handleGlobalKeydown_(event) {
if (event.target === document.body) {
this.handleKeyDown(event);
}
}

/**
* Get object for cached values.
*
Expand Down Expand Up @@ -4570,6 +4583,10 @@ class Player extends Component {
this.height(this.audioOnlyCache_.controlBarHeight);
}

isGlobalHotKeysEnabled() {
return !!(this.options_ && this.options_.userActions && this.options_.userActions.globalHotkeys);
}

enableAudioOnlyUI_() {
// Update styling immediately to show the control bar so we can get its height
this.addClass('vjs-audio-only-mode');
Expand Down
55 changes: 55 additions & 0 deletions test/unit/player-user-actions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -639,3 +639,58 @@ QUnit.test('hotkeys are NOT ignored when focus is on a button input', function(a
defaultKeyTests.mute(this.player, assert, true);
defaultKeyTests.playPause(this.player, assert, true);
});

QUnit.module('Player: User Actions: Global Hotkeys', {

beforeEach() {
this.clock = sinon.useFakeTimers();
this.player = TestHelpers.makePlayer();
},

afterEach() {
this.player.dispose();
this.clock.restore();
}
});

QUnit.test('when userActions.globalHotkeys is true, hotkeys are enabled at document.body level', function(assert) {
this.player.dispose();
this.player = TestHelpers.makePlayer({
controls: true,
userActions: {
globalHotkeys: true,
hotkeys: true
}
});

this.player.requestFullscreen = sinon.spy();

const event = new KeyboardEvent('keydown', { // eslint-disable-line no-undef
key: 'f'
});

document.body.dispatchEvent(event);

assert.strictEqual(this.player.requestFullscreen.callCount, 1, 'has gone fullscreen');
});

QUnit.test('when userActions.globalHotkeys is NOT true, hotkeys are NOT enabled at document.body level', function(assert) {
this.player.dispose();
this.player = TestHelpers.makePlayer({
controls: true,
userActions: {
globalHotkeys: false,
hotkeys: true
}
});

this.player.requestFullscreen = sinon.spy();

const event = new KeyboardEvent('keydown', { // eslint-disable-line no-undef
key: 'f'
});

document.body.dispatchEvent(event);

assert.strictEqual(this.player.requestFullscreen.callCount, 0, 'has not gone fullscreen');
});

0 comments on commit 13775d5

Please # to comment.