diff --git a/ui/package.json b/ui/package.json index 6fa14d23..5cbbfa4a 100644 --- a/ui/package.json +++ b/ui/package.json @@ -17,6 +17,7 @@ "prettier": "^2.1.2", "react": "^16.13.1", "react-dom": "^16.13.1", + "react-hotkeys-hook": "^3.0.3", "react-router": "^5.2.0", "react-router-dom": "^5.2.0", "react-scripts": "3.4.1", diff --git a/ui/src/Room.tsx b/ui/src/Room.tsx index 3d653c6f..f140c940 100644 --- a/ui/src/Room.tsx +++ b/ui/src/Room.tsx @@ -23,6 +23,7 @@ import PresentToAllIcon from '@material-ui/icons/PresentToAll'; import FullScreenIcon from '@material-ui/icons/Fullscreen'; import PeopleIcon from '@material-ui/icons/People'; import ShowMoreIcon from '@material-ui/icons/MoreVert'; +import {useHotkeys} from 'react-hotkeys-hook'; import {Video} from './Video'; import {makeStyles} from '@material-ui/core/styles'; import {ConnectedRoom} from './useRoom'; @@ -69,6 +70,7 @@ export const Room = ({ const [showMore, setShowMore] = React.useState(); const [selectedStream, setSelectedStream] = React.useState(); const [videoElement, setVideoElement] = React.useState(null); + useShowOnMouseMovement(setShowControl); React.useEffect(() => { @@ -122,6 +124,50 @@ export const Room = ({ const controlVisible = showControl || open || showMore || hoverControl; + useHotkeys('s', () => (state.hostStream ? stopShare() : share()), [state.hostStream]); + useHotkeys( + 'f', + () => { + if (selectedStream) { + videoElement?.requestFullscreen(); + } + }, + [videoElement, selectedStream] + ); + useHotkeys('c', copyLink); + useHotkeys( + 'h', + () => { + if (state.clientStreams !== undefined && state.clientStreams.length > 0) { + const currentStreamIndex = state.clientStreams.findIndex( + ({id}) => id === selectedStream + ); + const nextIndex = + currentStreamIndex === state.clientStreams.length - 1 + ? 0 + : currentStreamIndex + 1; + setSelectedStream(state.clientStreams[nextIndex].id); + } + }, + [state.clientStreams, selectedStream] + ); + useHotkeys( + 'l', + () => { + if (state.clientStreams !== undefined && state.clientStreams.length > 0) { + const currentStreamIndex = state.clientStreams.findIndex( + ({id}) => id === selectedStream + ); + const previousIndex = + currentStreamIndex === 0 + ? state.clientStreams.length - 1 + : currentStreamIndex - 1; + setSelectedStream(state.clientStreams[previousIndex].id); + } + }, + [state.clientStreams, selectedStream] + ); + return (
{controlVisible && ( diff --git a/ui/yarn.lock b/ui/yarn.lock index 05297932..fdbbb8f5 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -5157,6 +5157,11 @@ hosted-git-info@^2.1.4: resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== +hotkeys-js@3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/hotkeys-js/-/hotkeys-js-3.8.1.tgz#fa7051f73bf1dc92a8b8d580a40b247f91966376" + integrity sha512-YlhVQtyG9f1b7GhtzdhR0Pl+cImD1ZrKI6zYUa7QLd0zuThiL7RzZ+ANJyy7z+kmcCpNYBf5PjBa3CjiQ5PFpw== + hpack.js@^2.1.6: version "2.1.6" resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" @@ -8884,6 +8889,13 @@ react-error-overlay@^6.0.7: resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.7.tgz#1dcfb459ab671d53f660a991513cb2f0a0553108" integrity sha512-TAv1KJFh3RhqxNvhzxj6LeT5NWklP6rDr2a0jaTfsZ5wSZWHOGeqQyejUp3xxLfPt2UpyJEcVQB/zyPcmonNFA== +react-hotkeys-hook@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/react-hotkeys-hook/-/react-hotkeys-hook-3.0.3.tgz#5967486a4f569eb7045d2384ed0c35687ac7bdfa" + integrity sha512-kbnb820AUITXxK3qRHq612ivoNvMidIEaVAG7rUDuJMBTlJdSniJjjFl0jddL4iSKJK1d0Vqgn80uPW+spq6yQ== + dependencies: + hotkeys-js "3.8.1" + react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.0, react-is@^16.8.1, react-is@^16.8.4: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"