From c8ae87b082265ec46fc2146b34b786cf546ca38b Mon Sep 17 00:00:00 2001 From: Cyril Date: Fri, 24 Apr 2026 14:26:58 +0200 Subject: [PATCH] =?UTF-8?q?=E2=99=BF(frontend)=20restore=20toolbar=20short?= =?UTF-8?q?cuts=20inside=20PiP=20window?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Forward PiP keydown events and register PiP-specific handlers. --- .../features/pip/components/PipControlBar.tsx | 12 ++++- .../pip/components/PipReactionsToggle.tsx | 8 +++- .../src/features/pip/components/PipView.tsx | 4 ++ .../pip/hooks/usePipKeyboardShortcuts.ts | 45 +++++++++++++++++++ 4 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 src/frontend/src/features/pip/hooks/usePipKeyboardShortcuts.ts diff --git a/src/frontend/src/features/pip/components/PipControlBar.tsx b/src/frontend/src/features/pip/components/PipControlBar.tsx index 19d9a01d..2a4e9b1d 100644 --- a/src/frontend/src/features/pip/components/PipControlBar.tsx +++ b/src/frontend/src/features/pip/components/PipControlBar.tsx @@ -1,6 +1,8 @@ import { styled } from '@/styled-system/jsx' -import { useRef, useMemo } from 'react' +import { useRef, useMemo, useCallback } from 'react' import { useTranslation } from 'react-i18next' +import { useRegisterKeyboardShortcut } from '@/features/shortcuts/useRegisterKeyboardShortcut' +import { findFirstFocusable } from '@/utils/dom' import { AudioDevicesControl } from '@/features/rooms/livekit/components/controls/Device/AudioDevicesControl' import { VideoDeviceControl } from '@/features/rooms/livekit/components/controls/Device/VideoDeviceControl' import { ScreenShareToggle } from '@/features/rooms/livekit/components/controls/ScreenShareToggle' @@ -64,6 +66,14 @@ export const PipControlBar = ({ [width, showScreenShare] ) + useRegisterKeyboardShortcut({ + id: 'focus-toolbar', + handler: useCallback(() => { + const doc = containerRef.current?.ownerDocument ?? document + findFirstFocusable(doc.getElementById('pip-control-bar'))?.focus() + }, []), + }) + return ( { const { t } = useTranslation('rooms', { keyPrefix: 'controls.reactions' }) const { showReactionsToolbar: isOpen } = useSnapshot(pipLayoutStore) - const toggle = () => { + const toggle = useCallback(() => { pipLayoutStore.showReactionsToolbar = !pipLayoutStore.showReactionsToolbar - } + }, []) + + useRegisterKeyboardShortcut({ id: 'reaction', handler: toggle }) return ( { // Escape closes the side panel instead of the whole PiP window. useEscapeDismiss(containerRef, isSidePanelOpen, closePanel) + // Forward keyboard shortcuts (Ctrl+D, Ctrl+E, etc.) to the main store. + usePipKeyboardShortcuts(containerRef) + // Side panels open via a menu item that unmounts on click; fall back to the // options button so focus returns somewhere visible. const resolveTrigger = useCallback((activeEl: HTMLElement | null) => { diff --git a/src/frontend/src/features/pip/hooks/usePipKeyboardShortcuts.ts b/src/frontend/src/features/pip/hooks/usePipKeyboardShortcuts.ts new file mode 100644 index 00000000..de9f337c --- /dev/null +++ b/src/frontend/src/features/pip/hooks/usePipKeyboardShortcuts.ts @@ -0,0 +1,45 @@ +import { useEffect, type RefObject } from 'react' +import { keyboardShortcutsStore } from '@/stores/keyboardShortcuts' +import { formatShortcutKey } from '@/features/shortcuts/utils' +import { isMacintosh } from '@/utils/livekit' + +/** + * Mirror the main-window keyboard shortcuts inside the PiP document. + * + * The central `useKeyboardShortcuts` hook listens on `window`, which is the + * main document's window. Keydown events from the PiP document never reach + * it. This hook attaches the same dispatch logic to the PiP document so that + * Ctrl+D (mic), Ctrl+E (cam), etc. work identically in both contexts. + */ +export const usePipKeyboardShortcuts = ( + containerRef: RefObject +) => { + useEffect(() => { + const doc = containerRef.current?.ownerDocument + if (!doc || doc === document) return + + const onKeyDown = (e: KeyboardEvent) => { + const { key, metaKey, ctrlKey, shiftKey, altKey } = e + if (!key) return + + const shortcutKey = formatShortcutKey({ + key, + ctrlKey: ctrlKey || (isMacintosh() && metaKey), + shiftKey, + altKey, + }) + + let handler = keyboardShortcutsStore.shortcuts.get(shortcutKey) + if (!handler && shortcutKey === 'ctrl+shift+?') { + handler = keyboardShortcutsStore.shortcuts.get('ctrl+shift+/') + } + if (!handler) return + + e.preventDefault() + handler() + } + + doc.addEventListener('keydown', onKeyDown) + return () => doc.removeEventListener('keydown', onKeyDown) + }, [containerRef]) +}