From 04597908a5216aae59dd5c95a00b55728663509c Mon Sep 17 00:00:00 2001 From: Gabe Kangas Date: Thu, 2 Jun 2022 13:50:16 -0700 Subject: [PATCH] Add keyboard shortcuts for player controls. For #1892 --- web/components/video/OwncastPlayer.tsx | 47 ++++++++++++++++++++++++++ web/package-lock.json | 31 +++++++++++++++++ web/package.json | 1 + 3 files changed, 79 insertions(+) diff --git a/web/components/video/OwncastPlayer.tsx b/web/components/video/OwncastPlayer.tsx index d0aebbc62..3a8d26263 100644 --- a/web/components/video/OwncastPlayer.tsx +++ b/web/components/video/OwncastPlayer.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { useRecoilState } from 'recoil'; +import { useHotkeys } from 'react-hotkeys-hook'; import VideoJS from './player'; import ViewerPing from './viewer-ping'; import VideoPoster from './VideoPoster'; @@ -32,6 +33,52 @@ export default function OwncastPlayer(props: Props) { setLocalStorage(PLAYER_VOLUME, playerRef.current.muted() ? 0 : playerRef.current.volume()); }; + const togglePlayback = () => { + if (playerRef.current.paused()) { + playerRef.current.play(); + } else { + playerRef.current.pause(); + } + }; + + const toggleMute = () => { + if (playerRef.current.muted() || playerRef.current.volume() === 0) { + playerRef.current.volume(0.7); + } else { + playerRef.current.volume(0); + } + }; + + const toggleFullScreen = () => { + if (playerRef.current.isFullscreen()) { + playerRef.current.exitFullscreen(); + } else { + playerRef.current.requestFullscreen(); + } + }; + + // Register keyboard shortcut for the space bar to toggle playback + useHotkeys('space', togglePlayback, { + enableOnContentEditable: false, + }); + + // Register keyboard shortcut for f to toggle full screen + useHotkeys('f', toggleFullScreen, { + enableOnContentEditable: false, + }); + + // Register keyboard shortcut for the "m" key to toggle mute + useHotkeys('m', toggleMute, { + enableOnContentEditable: false, + }); + + useHotkeys('0', () => playerRef.current.volume(playerRef.current.volume() + 0.1), { + enableOnContentEditable: false, + }); + useHotkeys('9', () => playerRef.current.volume(playerRef.current.volume() - 0.1), { + enableOnContentEditable: false, + }); + const videoJsOptions = { autoplay: false, controls: true, diff --git a/web/package-lock.json b/web/package-lock.json index 4ee1f32a0..12f0ff0ef 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -32,6 +32,7 @@ "react-contenteditable": "^3.3.6", "react-crossfade-img": "^1.0.0", "react-dom": "17.0.2", + "react-hotkeys-hook": "^3.4.6", "react-linkify": "1.0.0-alpha", "react-markdown": "8.0.0", "react-markdown-editor-lite": "1.3.2", @@ -19401,6 +19402,11 @@ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" }, + "node_modules/hotkeys-js": { + "version": "3.9.3", + "resolved": "https://registry.npmjs.org/hotkeys-js/-/hotkeys-js-3.9.3.tgz", + "integrity": "sha512-s+f0xyvDmf6+DyrFQ2SY+eA7lbvMbjqkqi0I0SpMgnN5tZx7DeH8nsWhkJR4KEq3pxDPHJppDUhdt1rZFW5LeQ==" + }, "node_modules/html-encoding-sniffer": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", @@ -27282,6 +27288,18 @@ "react-dom": "^16.6.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/react-hotkeys-hook": { + "version": "3.4.6", + "resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-3.4.6.tgz", + "integrity": "sha512-SiGKHnauaAQglRA7qeiW5LTa0KoT2ssv8YGYKZQoM3P9v5JFEHJdXOSFml1N6K86oKQ8dLCLlxqBqGlSJWGmxQ==", + "dependencies": { + "hotkeys-js": "3.9.3" + }, + "peerDependencies": { + "react": ">=16.8.1", + "react-dom": ">=16.8.1" + } + }, "node_modules/react-inspector": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-5.1.1.tgz", @@ -47389,6 +47407,11 @@ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" }, + "hotkeys-js": { + "version": "3.9.3", + "resolved": "https://registry.npmjs.org/hotkeys-js/-/hotkeys-js-3.9.3.tgz", + "integrity": "sha512-s+f0xyvDmf6+DyrFQ2SY+eA7lbvMbjqkqi0I0SpMgnN5tZx7DeH8nsWhkJR4KEq3pxDPHJppDUhdt1rZFW5LeQ==" + }, "html-encoding-sniffer": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", @@ -53365,6 +53388,14 @@ "shallowequal": "^1.1.0" } }, + "react-hotkeys-hook": { + "version": "3.4.6", + "resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-3.4.6.tgz", + "integrity": "sha512-SiGKHnauaAQglRA7qeiW5LTa0KoT2ssv8YGYKZQoM3P9v5JFEHJdXOSFml1N6K86oKQ8dLCLlxqBqGlSJWGmxQ==", + "requires": { + "hotkeys-js": "3.9.3" + } + }, "react-inspector": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-5.1.1.tgz", diff --git a/web/package.json b/web/package.json index fe48813f4..746486bbe 100644 --- a/web/package.json +++ b/web/package.json @@ -36,6 +36,7 @@ "react-contenteditable": "^3.3.6", "react-crossfade-img": "^1.0.0", "react-dom": "17.0.2", + "react-hotkeys-hook": "^3.4.6", "react-linkify": "1.0.0-alpha", "react-markdown": "8.0.0", "react-markdown-editor-lite": "1.3.2",