From a18335b61cfcd0f6edc90d2e0874a1bee3d43fd0 Mon Sep 17 00:00:00 2001 From: cproudlock Date: Thu, 6 Aug 2026 07:27:59 -0400 Subject: [PATCH] Step through slides with the arrow keys Somebody standing at a display who wants to hold a slide, or go back to one that has just passed, had to wait for the whole rotation to come round again. Left and right arrows step back and forward; PageUp and PageDown do the same, so a presenter remote works without being told about it. The listener is on window rather than an element because a display has nothing focused. Stepping restarts the rotation timer instead of leaving it running. Advancing by hand and then having it move again a second later, because the existing timer was nearly up, reads as the display ignoring the keypress. Ignored entirely when there is less than one slide to move to. --- plugins/slides/frontend/views/TVDashboard.vue | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/plugins/slides/frontend/views/TVDashboard.vue b/plugins/slides/frontend/views/TVDashboard.vue index 6a2ad27..dd503d0 100644 --- a/plugins/slides/frontend/views/TVDashboard.vue +++ b/plugins/slides/frontend/views/TVDashboard.vue @@ -67,9 +67,14 @@ onMounted(async () => { // Refresh slide list every 60 seconds refreshTimer = setInterval(fetchSlides, 60000) + + // On window, not on an element: the display has nothing focused, and a + // presenter remote sends the same keys as a keyboard. + window.addEventListener('keydown', onKeydown) }) onUnmounted(() => { + window.removeEventListener('keydown', onKeydown) if (slideTimer) clearTimeout(slideTimer) if (progressTimer) clearTimeout(progressTimer) if (refreshTimer) clearInterval(refreshTimer) @@ -139,6 +144,32 @@ function nextSlide() { if (slides.value.length === 0) return currentSlide.value = (currentSlide.value + 1) % slides.value.length } + +function previousSlide() { + if (slides.value.length === 0) return + const count = slides.value.length + currentSlide.value = (currentSlide.value - 1 + count) % count +} + +// Left and right arrows step through the slides by hand. Someone standing at +// the display wanting to hold a slide, or go back to one that has just passed, +// otherwise has to wait for the whole rotation to come round again. +// +// Stepping RESTARTS the timer rather than leaving it running: advancing +// manually and then having it move again a second later, because the existing +// timer was most of the way through, reads as the display ignoring you. +function onKeydown(event) { + if (slides.value.length < 2) return + if (event.key === 'ArrowRight' || event.key === 'PageDown') { + event.preventDefault() + nextSlide() + scheduleNextSlide() + } else if (event.key === 'ArrowLeft' || event.key === 'PageUp') { + event.preventDefault() + previousSlide() + scheduleNextSlide() + } +}