diff --git a/src/frontend/src/features/rooms/livekit/components/controls/Device/ToggleDevice.tsx b/src/frontend/src/features/rooms/livekit/components/controls/Device/ToggleDevice.tsx index 84ce2277..96359e1b 100644 --- a/src/frontend/src/features/rooms/livekit/components/controls/Device/ToggleDevice.tsx +++ b/src/frontend/src/features/rooms/livekit/components/controls/Device/ToggleDevice.tsx @@ -18,6 +18,7 @@ import { useCannotUseDevice } from '../../../hooks/useCannotUseDevice' import { useDeviceIcons } from '../../../hooks/useDeviceIcons' import { useDeviceShortcut } from '../../../hooks/useDeviceShortcut' import { ToggleSource, CaptureOptionsBySource } from '@livekit/components-core' +import { getShortcutDescriptorById } from '@/features/shortcuts/catalog' type ToggleDeviceStyleProps = { variant?: NonNullable['variant'] @@ -88,12 +89,14 @@ export const ToggleDevice = ({ const deviceShortcut = useDeviceShortcut(kind) useRegisterKeyboardShortcut({ - shortcut: deviceShortcut, + id: deviceShortcut?.id, handler: async () => await toggle(), isDisabled: cannotUseDevice, }) + + const pushToTalkShortcut = getShortcutDescriptorById('push-to-talk') useLongPress({ - keyCode: kind === 'audioinput' ? 'KeyV' : undefined, + keyCode: kind === 'audioinput' ? pushToTalkShortcut?.code : undefined, onKeyDown, onKeyUp, isDisabled: cannotUseDevice, @@ -103,7 +106,9 @@ export const ToggleDevice = ({ const label = t(enabled ? 'disable' : 'enable', { keyPrefix: `selectDevice.${kind}`, }) - return deviceShortcut ? appendShortcutLabel(label, deviceShortcut) : label + return deviceShortcut?.shortcut + ? appendShortcutLabel(label, deviceShortcut.shortcut) + : label }, [enabled, kind, deviceShortcut, t]) const Icon = diff --git a/src/frontend/src/features/rooms/livekit/hooks/useDeviceShortcut.ts b/src/frontend/src/features/rooms/livekit/hooks/useDeviceShortcut.ts index b47ed3f2..f7ae37aa 100644 --- a/src/frontend/src/features/rooms/livekit/hooks/useDeviceShortcut.ts +++ b/src/frontend/src/features/rooms/livekit/hooks/useDeviceShortcut.ts @@ -1,19 +1,16 @@ import { useMemo } from 'react' -import { Shortcut } from '@/features/shortcuts/types' +import { + getShortcutDescriptorById, + ShortcutDescriptor, +} from '@/features/shortcuts/catalog' export const useDeviceShortcut = (kind: MediaDeviceKind) => { - return useMemo(() => { + return useMemo(() => { switch (kind) { case 'audioinput': - return { - key: 'd', - ctrlKey: true, - } + return getShortcutDescriptorById('toggle-microphone') case 'videoinput': - return { - key: 'e', - ctrlKey: true, - } + return getShortcutDescriptorById('toggle-camera') default: return undefined } diff --git a/src/frontend/src/features/rooms/livekit/prefabs/ControlBar/DesktopControlBar.tsx b/src/frontend/src/features/rooms/livekit/prefabs/ControlBar/DesktopControlBar.tsx index dce26463..de7897f2 100644 --- a/src/frontend/src/features/rooms/livekit/prefabs/ControlBar/DesktopControlBar.tsx +++ b/src/frontend/src/features/rooms/livekit/prefabs/ControlBar/DesktopControlBar.tsx @@ -22,7 +22,7 @@ export function DesktopControlBar({ const desktopControlBarEl = useRef(null) useRegisterKeyboardShortcut({ - shortcut: { key: 'F2' }, + id: 'focus-toolbar', handler: () => { const root = desktopControlBarEl.current if (!root) return diff --git a/src/frontend/src/features/shortcuts/catalog.ts b/src/frontend/src/features/shortcuts/catalog.ts new file mode 100644 index 00000000..ff85de56 --- /dev/null +++ b/src/frontend/src/features/shortcuts/catalog.ts @@ -0,0 +1,47 @@ +import { Shortcut } from './types' + +// Central list of current keyboard shortcuts. +// Keep a single source of truth for display and, later, customization +export type ShortcutCategory = 'navigation' | 'media' | 'interaction' + +export type ShortcutId = + | 'focus-toolbar' + | 'toggle-microphone' + | 'toggle-camera' + | 'push-to-talk' + +export const getShortcutDescriptorById = (id: ShortcutId) => + shortcutCatalog.find((item) => item.id === id) + +export type ShortcutDescriptor = { + id: ShortcutId + category: ShortcutCategory + shortcut?: Shortcut + kind?: 'press' | 'longPress' + code?: string // used when kind === 'longPress' (KeyboardEvent.code) + description?: string +} + +export const shortcutCatalog: ShortcutDescriptor[] = [ + { + id: 'focus-toolbar', + category: 'navigation', + shortcut: { key: 'F2' }, + }, + { + id: 'toggle-microphone', + category: 'media', + shortcut: { key: 'd', ctrlKey: true }, + }, + { + id: 'toggle-camera', + category: 'media', + shortcut: { key: 'e', ctrlKey: true }, + }, + { + id: 'push-to-talk', + category: 'media', + kind: 'longPress', + code: 'KeyV', + }, +] diff --git a/src/frontend/src/features/shortcuts/useRegisterKeyboardShortcut.ts b/src/frontend/src/features/shortcuts/useRegisterKeyboardShortcut.ts index f39b1141..0e8ab03c 100644 --- a/src/frontend/src/features/shortcuts/useRegisterKeyboardShortcut.ts +++ b/src/frontend/src/features/shortcuts/useRegisterKeyboardShortcut.ts @@ -1,26 +1,28 @@ import { useEffect } from 'react' import { keyboardShortcutsStore } from '@/stores/keyboardShortcuts' import { formatShortcutKey } from '@/features/shortcuts/utils' -import { Shortcut } from '@/features/shortcuts/types' +import { ShortcutId, getShortcutDescriptorById } from './catalog' export type useRegisterKeyboardShortcutProps = { - shortcut?: Shortcut + id?: ShortcutId handler: () => Promise | void isDisabled?: boolean } export const useRegisterKeyboardShortcut = ({ - shortcut, + id, handler, isDisabled = false, }: useRegisterKeyboardShortcutProps) => { useEffect(() => { - if (!shortcut) return - const formattedKey = formatShortcutKey(shortcut) + if (!id) return + const descriptor = getShortcutDescriptorById(id) + if (!descriptor?.shortcut) return + const formattedKey = formatShortcutKey(descriptor.shortcut) if (isDisabled) { keyboardShortcutsStore.shortcuts.delete(formattedKey) } else { keyboardShortcutsStore.shortcuts.set(formattedKey, handler) } - }, [handler, shortcut, isDisabled]) + }, [handler, id, isDisabled]) }