From de71d1ef46e7c118ca8933f571d81ab7e8e9964f Mon Sep 17 00:00:00 2001 From: Hunter Austin Date: Tue, 5 Dec 2023 23:20:35 -0500 Subject: [PATCH 1/5] Prevent default actions for hotkeys --- src/controllers/playback/video/index.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/controllers/playback/video/index.js b/src/controllers/playback/video/index.js index 2e277de642..1a9774845b 100644 --- a/src/controllers/playback/video/index.js +++ b/src/controllers/playback/video/index.js @@ -1248,21 +1248,25 @@ export default function (view) { break; case 'k': case 'K': + e.preventDefault(); playbackManager.playPause(currentPlayer); showOsd(btnPlayPause); break; case 'ArrowUp': case 'Up': + e.preventDefault(); playbackManager.volumeUp(currentPlayer); break; case 'ArrowDown': case 'Down': + e.preventDefault(); playbackManager.volumeDown(currentPlayer); break; case 'l': case 'L': case 'ArrowRight': case 'Right': + e.preventDefault(); playbackManager.fastForward(currentPlayer); showOsd(btnFastForward); break; @@ -1270,28 +1274,33 @@ export default function (view) { case 'J': case 'ArrowLeft': case 'Left': + e.preventDefault(); playbackManager.rewind(currentPlayer); showOsd(btnRewind); break; case 'f': case 'F': if (!e.ctrlKey && !e.metaKey) { + e.preventDefault(); playbackManager.toggleFullscreen(currentPlayer); } break; case 'm': case 'M': + e.preventDefault(); playbackManager.toggleMute(currentPlayer); break; case 'p': case 'P': if (e.shiftKey) { + e.preventDefault(); playbackManager.previousTrack(currentPlayer); } break; case 'n': case 'N': if (e.shiftKey) { + e.preventDefault(); playbackManager.nextTrack(currentPlayer); } break; @@ -1330,15 +1339,18 @@ export default function (view) { case '8': case '9': { if (!isKeyModified) { + e.preventDefault(); const percent = parseInt(key, 10) * 10; playbackManager.seekPercent(percent, currentPlayer); } break; } case '>': + e.preventDefault(); playbackManager.increasePlaybackRate(currentPlayer); break; case '<': + e.preventDefault(); playbackManager.decreasePlaybackRate(currentPlayer); break; case 'PageUp': From d20c617d30a2600b76cd445e3f28a4005ceba7c9 Mon Sep 17 00:00:00 2001 From: Dmitry Lyzo Date: Sat, 14 Sep 2024 01:49:02 +0300 Subject: [PATCH 2/5] Quit immediately if not ready --- src/plugins/pdfPlayer/plugin.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/pdfPlayer/plugin.js b/src/plugins/pdfPlayer/plugin.js index 0a7d203415..f138125e82 100644 --- a/src/plugins/pdfPlayer/plugin.js +++ b/src/plugins/pdfPlayer/plugin.js @@ -89,9 +89,10 @@ export class PdfPlayer { } onWindowKeyUp(e) { + if (!this.loaded) return; + const key = keyboardnavigation.getKeyName(e); - if (!this.loaded) return; switch (key) { case 'l': case 'ArrowRight': From 4c68f500d975bb320e62d25ad07083e16401daf1 Mon Sep 17 00:00:00 2001 From: Dmitry Lyzo Date: Sat, 14 Sep 2024 01:44:52 +0300 Subject: [PATCH 3/5] Use keydown event to get actual modifiers --- src/plugins/bookPlayer/plugin.js | 12 ++++++------ src/plugins/comicsPlayer/plugin.js | 8 ++++---- src/plugins/pdfPlayer/plugin.js | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/plugins/bookPlayer/plugin.js b/src/plugins/bookPlayer/plugin.js index f43613be5c..609bb92e8d 100644 --- a/src/plugins/bookPlayer/plugin.js +++ b/src/plugins/bookPlayer/plugin.js @@ -45,7 +45,7 @@ export class BookPlayer { this.decreaseFontSize = this.decreaseFontSize.bind(this); this.previous = this.previous.bind(this); this.next = this.next.bind(this); - this.onWindowKeyUp = this.onWindowKeyUp.bind(this); + this.onWindowKeyDown = this.onWindowKeyDown.bind(this); this.addSwipeGestures = this.addSwipeGestures.bind(this); } @@ -130,7 +130,7 @@ export class BookPlayer { return true; } - onWindowKeyUp(e) { + onWindowKeyDown(e) { const key = keyboardnavigation.getKeyName(e); if (!this.loaded) return; @@ -184,8 +184,8 @@ export class BookPlayer { bindEvents() { this.bindMediaElementEvents(); - document.addEventListener('keyup', this.onWindowKeyUp); - this.rendition?.on('keyup', this.onWindowKeyUp); + document.addEventListener('keydown', this.onWindowKeyDown); + this.rendition?.on('keydown', this.onWindowKeyDown); if (browser.safari) { const player = document.getElementById('bookPlayerContainer'); @@ -214,8 +214,8 @@ export class BookPlayer { this.unbindMediaElementEvents(); } - document.removeEventListener('keyup', this.onWindowKeyUp); - this.rendition?.off('keyup', this.onWindowKeyUp); + document.removeEventListener('keydown', this.onWindowKeyDown); + this.rendition?.off('keydown', this.onWindowKeyDown); if (!browser.safari) { this.rendition?.off('rendered', (e, i) => this.addSwipeGestures(i.document.documentElement)); diff --git a/src/plugins/comicsPlayer/plugin.js b/src/plugins/comicsPlayer/plugin.js index 405bdcd941..f1a0437c5a 100644 --- a/src/plugins/comicsPlayer/plugin.js +++ b/src/plugins/comicsPlayer/plugin.js @@ -23,7 +23,7 @@ export class ComicsPlayer { this.imageMap = new Map(); this.onDialogClosed = this.onDialogClosed.bind(this); - this.onWindowKeyUp = this.onWindowKeyUp.bind(this); + this.onWindowKeyDown = this.onWindowKeyDown.bind(this); } play(options) { @@ -177,7 +177,7 @@ export class ComicsPlayer { this.swiperInstance.update(); } - onWindowKeyUp(e) { + onWindowKeyDown(e) { const key = keyboardnavigation.getKeyName(e); if (key === 'Escape') { this.stop(); @@ -196,7 +196,7 @@ export class ComicsPlayer { bindEvents() { this.bindMediaElementEvents(); - document.addEventListener('keyup', this.onWindowKeyUp); + document.addEventListener('keydown', this.onWindowKeyDown); } unbindMediaElementEvents() { @@ -211,7 +211,7 @@ export class ComicsPlayer { unbindEvents() { this.unbindMediaElementEvents(); - document.removeEventListener('keyup', this.onWindowKeyUp); + document.removeEventListener('keydown', this.onWindowKeyDown); } createMediaElement() { diff --git a/src/plugins/pdfPlayer/plugin.js b/src/plugins/pdfPlayer/plugin.js index f138125e82..f5710c3320 100644 --- a/src/plugins/pdfPlayer/plugin.js +++ b/src/plugins/pdfPlayer/plugin.js @@ -18,7 +18,7 @@ export class PdfPlayer { this.priority = 1; this.onDialogClosed = this.onDialogClosed.bind(this); - this.onWindowKeyUp = this.onWindowKeyUp.bind(this); + this.onWindowKeyDown = this.onWindowKeyDown.bind(this); this.onTouchStart = this.onTouchStart.bind(this); } @@ -88,7 +88,7 @@ export class PdfPlayer { return true; } - onWindowKeyUp(e) { + onWindowKeyDown(e) { if (!this.loaded) return; const key = keyboardnavigation.getKeyName(e); @@ -133,7 +133,7 @@ export class PdfPlayer { bindEvents() { this.bindMediaElementEvents(); - document.addEventListener('keyup', this.onWindowKeyUp); + document.addEventListener('keydown', this.onWindowKeyDown); document.addEventListener('touchstart', this.onTouchStart); } @@ -149,7 +149,7 @@ export class PdfPlayer { this.unbindMediaElementEvents(); } - document.removeEventListener('keyup', this.onWindowKeyUp); + document.removeEventListener('keydown', this.onWindowKeyDown); document.removeEventListener('touchstart', this.onTouchStart); } From b2676c1633205399021afb60821d7bb9a5f99614 Mon Sep 17 00:00:00 2001 From: Dmitry Lyzo Date: Sat, 14 Sep 2024 00:18:33 +0300 Subject: [PATCH 4/5] Prevent more default actions for hotkeys --- src/controllers/playback/video/index.js | 6 ++++++ src/plugins/bookPlayer/plugin.js | 3 +++ src/plugins/comicsPlayer/plugin.js | 1 + src/plugins/pdfPlayer/plugin.js | 3 +++ 4 files changed, 13 insertions(+) diff --git a/src/controllers/playback/video/index.js b/src/controllers/playback/video/index.js index 1a9774845b..cb02a23dea 100644 --- a/src/controllers/playback/video/index.js +++ b/src/controllers/playback/video/index.js @@ -1323,9 +1323,11 @@ export default function (view) { } break; case 'Home': + e.preventDefault(); playbackManager.seekPercent(0, currentPlayer); break; case 'End': + e.preventDefault(); playbackManager.seekPercent(100, currentPlayer); break; case '0': @@ -1354,17 +1356,21 @@ export default function (view) { playbackManager.decreasePlaybackRate(currentPlayer); break; case 'PageUp': + e.preventDefault(); playbackManager.nextChapter(currentPlayer); break; case 'PageDown': + e.preventDefault(); playbackManager.previousChapter(currentPlayer); break; case 'g': case 'G': + e.preventDefault(); subtitleSyncOverlay?.decrementOffset(); break; case 'h': case 'H': + e.preventDefault(); subtitleSyncOverlay?.incrementOffset(); break; } diff --git a/src/plugins/bookPlayer/plugin.js b/src/plugins/bookPlayer/plugin.js index 609bb92e8d..d9ea979483 100644 --- a/src/plugins/bookPlayer/plugin.js +++ b/src/plugins/bookPlayer/plugin.js @@ -138,14 +138,17 @@ export class BookPlayer { case 'l': case 'ArrowRight': case 'Right': + e.preventDefault(); this.next(); break; case 'j': case 'ArrowLeft': case 'Left': + e.preventDefault(); this.previous(); break; case 'Escape': + e.preventDefault(); if (this.tocElement) { // Close table of contents on ESC if it is open this.tocElement.destroy(); diff --git a/src/plugins/comicsPlayer/plugin.js b/src/plugins/comicsPlayer/plugin.js index f1a0437c5a..295b844bcf 100644 --- a/src/plugins/comicsPlayer/plugin.js +++ b/src/plugins/comicsPlayer/plugin.js @@ -180,6 +180,7 @@ export class ComicsPlayer { onWindowKeyDown(e) { const key = keyboardnavigation.getKeyName(e); if (key === 'Escape') { + e.preventDefault(); this.stop(); } } diff --git a/src/plugins/pdfPlayer/plugin.js b/src/plugins/pdfPlayer/plugin.js index f5710c3320..8ee7bddae8 100644 --- a/src/plugins/pdfPlayer/plugin.js +++ b/src/plugins/pdfPlayer/plugin.js @@ -97,14 +97,17 @@ export class PdfPlayer { case 'l': case 'ArrowRight': case 'Right': + e.preventDefault(); this.next(); break; case 'j': case 'ArrowLeft': case 'Left': + e.preventDefault(); this.previous(); break; case 'Escape': + e.preventDefault(); this.stop(); break; } From 3025e9bf48cccc4479a54739e83627e67cd7b82b Mon Sep 17 00:00:00 2001 From: Dmitry Lyzo Date: Tue, 10 Sep 2024 03:53:43 +0300 Subject: [PATCH 5/5] Ignore modified hotkeys --- src/controllers/playback/video/index.js | 108 +++++++++++++++--------- src/plugins/bookPlayer/plugin.js | 3 + src/plugins/comicsPlayer/plugin.js | 3 + src/plugins/pdfPlayer/plugin.js | 3 + src/scripts/keyboardNavigation.js | 3 + 5 files changed, 80 insertions(+), 40 deletions(-) diff --git a/src/controllers/playback/video/index.js b/src/controllers/playback/video/index.js index cb02a23dea..b6439216ce 100644 --- a/src/controllers/playback/video/index.js +++ b/src/controllers/playback/video/index.js @@ -1195,9 +1195,13 @@ export default function (view) { function onKeyDown(e) { clickedElement = e.target; - const key = keyboardnavigation.getKeyName(e); const isKeyModified = e.ctrlKey || e.altKey || e.metaKey; + // Skip modified keys + if (isKeyModified) return; + + const key = keyboardnavigation.getKeyName(e); + const btnPlayPause = osdBottomElement.querySelector('.btnPause'); if (e.keyCode === 32) { @@ -1219,8 +1223,10 @@ export default function (view) { switch (key) { case 'ArrowLeft': case 'ArrowRight': - showOsd(nowPlayingPositionSlider); - nowPlayingPositionSlider.dispatchEvent(new KeyboardEvent(e.type, e)); + if (!e.shiftKey) { + showOsd(nowPlayingPositionSlider); + nowPlayingPositionSlider.dispatchEvent(new KeyboardEvent(e.type, e)); + } return; case 'Enter': playbackManager.playPause(currentPlayer); @@ -1230,7 +1236,7 @@ export default function (view) { } if (layoutManager.tv && keyboardnavigation.isNavigationKey(key)) { - showOsd(); + if (!e.shiftKey) showOsd(); return; } @@ -1248,47 +1254,59 @@ export default function (view) { break; case 'k': case 'K': - e.preventDefault(); - playbackManager.playPause(currentPlayer); - showOsd(btnPlayPause); + if (!e.shiftKey) { + e.preventDefault(); + playbackManager.playPause(currentPlayer); + showOsd(btnPlayPause); + } break; case 'ArrowUp': case 'Up': - e.preventDefault(); - playbackManager.volumeUp(currentPlayer); + if (!e.shiftKey) { + e.preventDefault(); + playbackManager.volumeUp(currentPlayer); + } break; case 'ArrowDown': case 'Down': - e.preventDefault(); - playbackManager.volumeDown(currentPlayer); + if (!e.shiftKey) { + e.preventDefault(); + playbackManager.volumeDown(currentPlayer); + } break; case 'l': case 'L': case 'ArrowRight': case 'Right': - e.preventDefault(); - playbackManager.fastForward(currentPlayer); - showOsd(btnFastForward); + if (!e.shiftKey) { + e.preventDefault(); + playbackManager.fastForward(currentPlayer); + showOsd(btnFastForward); + } break; case 'j': case 'J': case 'ArrowLeft': case 'Left': - e.preventDefault(); - playbackManager.rewind(currentPlayer); - showOsd(btnRewind); + if (!e.shiftKey) { + e.preventDefault(); + playbackManager.rewind(currentPlayer); + showOsd(btnRewind); + } break; case 'f': case 'F': - if (!e.ctrlKey && !e.metaKey) { + if (!e.shiftKey) { e.preventDefault(); playbackManager.toggleFullscreen(currentPlayer); } break; case 'm': case 'M': - e.preventDefault(); - playbackManager.toggleMute(currentPlayer); + if (!e.shiftKey) { + e.preventDefault(); + playbackManager.toggleMute(currentPlayer); + } break; case 'p': case 'P': @@ -1323,12 +1341,16 @@ export default function (view) { } break; case 'Home': - e.preventDefault(); - playbackManager.seekPercent(0, currentPlayer); + if (!e.shiftKey) { + e.preventDefault(); + playbackManager.seekPercent(0, currentPlayer); + } break; case 'End': - e.preventDefault(); - playbackManager.seekPercent(100, currentPlayer); + if (!e.shiftKey) { + e.preventDefault(); + playbackManager.seekPercent(100, currentPlayer); + } break; case '0': case '1': @@ -1339,39 +1361,45 @@ export default function (view) { case '6': case '7': case '8': - case '9': { - if (!isKeyModified) { - e.preventDefault(); - const percent = parseInt(key, 10) * 10; - playbackManager.seekPercent(percent, currentPlayer); - } + case '9': { // no Shift + e.preventDefault(); + const percent = parseInt(key, 10) * 10; + playbackManager.seekPercent(percent, currentPlayer); break; } - case '>': + case '>': // Shift+. e.preventDefault(); playbackManager.increasePlaybackRate(currentPlayer); break; - case '<': + case '<': // Shift+, e.preventDefault(); playbackManager.decreasePlaybackRate(currentPlayer); break; case 'PageUp': - e.preventDefault(); - playbackManager.nextChapter(currentPlayer); + if (!e.shiftKey) { + e.preventDefault(); + playbackManager.nextChapter(currentPlayer); + } break; case 'PageDown': - e.preventDefault(); - playbackManager.previousChapter(currentPlayer); + if (!e.shiftKey) { + e.preventDefault(); + playbackManager.previousChapter(currentPlayer); + } break; case 'g': case 'G': - e.preventDefault(); - subtitleSyncOverlay?.decrementOffset(); + if (!e.shiftKey) { + e.preventDefault(); + subtitleSyncOverlay?.decrementOffset(); + } break; case 'h': case 'H': - e.preventDefault(); - subtitleSyncOverlay?.incrementOffset(); + if (!e.shiftKey) { + e.preventDefault(); + subtitleSyncOverlay?.incrementOffset(); + } break; } } diff --git a/src/plugins/bookPlayer/plugin.js b/src/plugins/bookPlayer/plugin.js index d9ea979483..733519cb38 100644 --- a/src/plugins/bookPlayer/plugin.js +++ b/src/plugins/bookPlayer/plugin.js @@ -131,6 +131,9 @@ export class BookPlayer { } onWindowKeyDown(e) { + // Skip modified keys + if (e.ctrlKey || e.altKey || e.metaKey || e.shiftKey) return; + const key = keyboardnavigation.getKeyName(e); if (!this.loaded) return; diff --git a/src/plugins/comicsPlayer/plugin.js b/src/plugins/comicsPlayer/plugin.js index 295b844bcf..0e8f599a1b 100644 --- a/src/plugins/comicsPlayer/plugin.js +++ b/src/plugins/comicsPlayer/plugin.js @@ -178,6 +178,9 @@ export class ComicsPlayer { } onWindowKeyDown(e) { + // Skip modified keys + if (e.ctrlKey || e.altKey || e.metaKey || e.shiftKey) return; + const key = keyboardnavigation.getKeyName(e); if (key === 'Escape') { e.preventDefault(); diff --git a/src/plugins/pdfPlayer/plugin.js b/src/plugins/pdfPlayer/plugin.js index 8ee7bddae8..7b7e3fa4b8 100644 --- a/src/plugins/pdfPlayer/plugin.js +++ b/src/plugins/pdfPlayer/plugin.js @@ -91,6 +91,9 @@ export class PdfPlayer { onWindowKeyDown(e) { if (!this.loaded) return; + // Skip modified keys + if (e.ctrlKey || e.altKey || e.metaKey || e.shiftKey) return; + const key = keyboardnavigation.getKeyName(e); switch (key) { diff --git a/src/scripts/keyboardNavigation.js b/src/scripts/keyboardNavigation.js index ed13e90415..8b1778ebf4 100644 --- a/src/scripts/keyboardNavigation.js +++ b/src/scripts/keyboardNavigation.js @@ -125,6 +125,9 @@ export function isInteractiveElement(element) { export function enable() { const hasMediaSession = 'mediaSession' in navigator; window.addEventListener('keydown', function (e) { + // Skip modified keys + if (e.ctrlKey || e.altKey || e.metaKey || e.shiftKey) return; + const key = getKeyName(e); // Ignore navigation keys for non-TV