From 3c3b4a32e389eab3cf5d6e2db0957fe6986b69e8 Mon Sep 17 00:00:00 2001 From: Ovgodd Date: Thu, 12 Feb 2026 16:48:22 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8(frontend)=20support=20additional=20sh?= =?UTF-8?q?ortcuts=20to=20broaden=20accessibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for additional shortcuts to broaden accessibility and integration capabilities. Some of these are required to ensure full functionality with the RENATER SIP media gateway, allowing shortcut mapping to DTMF signals. Others improve usability for keyboard-only users; a lightweight helper will be introduced to surface available shortcuts and make them easier to discover and use. --- .../components/controls/ChatToggle.tsx | 6 ++++ .../components/controls/HandToggle.tsx | 16 ++++++--- .../components/controls/ReactionsToggle.tsx | 6 ++++ .../src/features/shortcuts/catalog.ts | 36 +++++++++++++++++++ 4 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src/frontend/src/features/rooms/livekit/components/controls/ChatToggle.tsx b/src/frontend/src/features/rooms/livekit/components/controls/ChatToggle.tsx index 37f8f360..130151f7 100644 --- a/src/frontend/src/features/rooms/livekit/components/controls/ChatToggle.tsx +++ b/src/frontend/src/features/rooms/livekit/components/controls/ChatToggle.tsx @@ -6,6 +6,7 @@ import { ToggleButton } from '@/primitives' import { chatStore } from '@/stores/chat' import { useSidePanel } from '../../hooks/useSidePanel' import { ToggleButtonProps } from '@/primitives/ToggleButton' +import { useRegisterKeyboardShortcut } from '@/features/shortcuts/useRegisterKeyboardShortcut' export const ChatToggle = ({ onPress, @@ -18,6 +19,11 @@ export const ChatToggle = ({ const { isChatOpen, toggleChat } = useSidePanel() const tooltipLabel = isChatOpen ? 'open' : 'closed' + useRegisterKeyboardShortcut({ + id: 'toggle-chat', + handler: toggleChat, + }) + return (
{ closeLowerHandToasts() }, [isHandRaised]) + const handleToggle = () => { + toggleRaisedHand() + resetToastState() + } + + useRegisterKeyboardShortcut({ + id: 'raise-hand', + handler: handleToggle, + }) + useEffect(() => { const shouldShowToast = isSpeaking && isHandRaised && !hasShownToast @@ -68,10 +79,7 @@ export const HandToggle = () => { aria-label={t(tooltipLabel)} tooltip={t(tooltipLabel)} isSelected={isHandRaised} - onPress={() => { - toggleRaisedHand() - resetToastState() - }} + onPress={handleToggle} data-attr={`controls-hand-${tooltipLabel}`} > diff --git a/src/frontend/src/features/rooms/livekit/components/controls/ReactionsToggle.tsx b/src/frontend/src/features/rooms/livekit/components/controls/ReactionsToggle.tsx index e400f6c4..57e47fc3 100644 --- a/src/frontend/src/features/rooms/livekit/components/controls/ReactionsToggle.tsx +++ b/src/frontend/src/features/rooms/livekit/components/controls/ReactionsToggle.tsx @@ -11,6 +11,7 @@ import { ReactionPortals, } from '@/features/rooms/livekit/components/ReactionPortal' import { getEmojiLabel } from '@/features/rooms/livekit/utils/reactionUtils' +import { useRegisterKeyboardShortcut } from '@/features/shortcuts/useRegisterKeyboardShortcut' import { Toolbar as RACToolbar } from 'react-aria-components' import { Participant } from 'livekit-client' import useRateLimiter from '@/hooks/useRateLimiter' @@ -41,6 +42,11 @@ export const ReactionsToggle = () => { const [isVisible, setIsVisible] = useState(false) + useRegisterKeyboardShortcut({ + id: 'reaction', + handler: () => setIsVisible((prev) => !prev), + }) + const sendReaction = async (emoji: string) => { const encoder = new TextEncoder() const payload: NotificationPayload = { diff --git a/src/frontend/src/features/shortcuts/catalog.ts b/src/frontend/src/features/shortcuts/catalog.ts index ff85de56..9be21492 100644 --- a/src/frontend/src/features/shortcuts/catalog.ts +++ b/src/frontend/src/features/shortcuts/catalog.ts @@ -9,6 +9,12 @@ export type ShortcutId = | 'toggle-microphone' | 'toggle-camera' | 'push-to-talk' + | 'toggle-chat' + | 'toggle-participants' + | 'raise-hand' + | 'recording' + | 'reaction' + | 'fullscreen' export const getShortcutDescriptorById = (id: ShortcutId) => shortcutCatalog.find((item) => item.id === id) @@ -44,4 +50,34 @@ export const shortcutCatalog: ShortcutDescriptor[] = [ kind: 'longPress', code: 'KeyV', }, + { + id: 'reaction', + category: 'interaction', + shortcut: { key: 'E', ctrlKey: true, shiftKey: true }, + }, + { + id: 'fullscreen', + category: 'interaction', + shortcut: { key: 'F', ctrlKey: true, shiftKey: true }, + }, + { + id: 'recording', + category: 'interaction', + shortcut: { key: 'L', ctrlKey: true, shiftKey: true }, + }, + { + id: 'raise-hand', + category: 'interaction', + shortcut: { key: 'H', ctrlKey: true, shiftKey: true }, + }, + { + id: 'toggle-chat', + category: 'interaction', + shortcut: { key: 'M', ctrlKey: true, shiftKey: true }, + }, + { + id: 'toggle-participants', + category: 'interaction', + shortcut: { key: 'P', ctrlKey: true, shiftKey: true }, + }, ]