diff --git a/web/src/components/card/ExportCard.tsx b/web/src/components/card/ExportCard.tsx index 9115e0509..cf0685caa 100644 --- a/web/src/components/card/ExportCard.tsx +++ b/web/src/components/card/ExportCard.tsx @@ -70,7 +70,10 @@ export default function ExportCard({ (editName.update?.length ?? 0) > 0 ) { submitRename(); + return true; } + + return false; }, ); diff --git a/web/src/components/card/ReviewCard.tsx b/web/src/components/card/ReviewCard.tsx index 09929cec5..d3f3b6d24 100644 --- a/web/src/components/card/ReviewCard.tsx +++ b/web/src/components/card/ReviewCard.tsx @@ -109,6 +109,7 @@ export default function ReviewCard({ useKeyboardListener(["Shift"], (_, modifiers) => { bypassDialogRef.current = modifiers.shift; + return false; }); const handleDelete = useCallback(() => { diff --git a/web/src/components/filter/ReviewActionGroup.tsx b/web/src/components/filter/ReviewActionGroup.tsx index 4db8a31c0..f91f75461 100644 --- a/web/src/components/filter/ReviewActionGroup.tsx +++ b/web/src/components/filter/ReviewActionGroup.tsx @@ -75,6 +75,7 @@ export default function ReviewActionGroup({ useKeyboardListener(["Shift"], (_, modifiers) => { setBypassDialog(modifiers.shift); + return false; }); const handleDelete = useCallback(() => { diff --git a/web/src/components/filter/SearchActionGroup.tsx b/web/src/components/filter/SearchActionGroup.tsx index ad6d6ccc8..0ba024792 100644 --- a/web/src/components/filter/SearchActionGroup.tsx +++ b/web/src/components/filter/SearchActionGroup.tsx @@ -62,6 +62,7 @@ export default function SearchActionGroup({ useKeyboardListener(["Shift"], (_, modifiers) => { setBypassDialog(modifiers.shift); + return false; }); const handleDelete = useCallback(() => { diff --git a/web/src/components/overlay/PtzControlPanel.tsx b/web/src/components/overlay/PtzControlPanel.tsx index b4219842b..5deb62fd3 100644 --- a/web/src/components/overlay/PtzControlPanel.tsx +++ b/web/src/components/overlay/PtzControlPanel.tsx @@ -83,7 +83,7 @@ export default function PtzControlPanel({ ], (key, modifiers) => { if (modifiers.repeat || !key) { - return; + return true; } if (["1", "2", "3", "4", "5", "6", "7", "8", "9"].includes(key)) { @@ -95,34 +95,36 @@ export default function PtzControlPanel({ ) { sendPtz(`preset_${ptz.presets[presetNumber - 1]}`); } - return; + return true; } if (!modifiers.down) { sendPtz("STOP"); - return; + return true; } switch (key) { case "ArrowLeft": sendPtz("MOVE_LEFT"); - break; + return true; case "ArrowRight": sendPtz("MOVE_RIGHT"); - break; + return true; case "ArrowUp": sendPtz("MOVE_UP"); - break; + return true; case "ArrowDown": sendPtz("MOVE_DOWN"); - break; + return true; case "+": sendPtz(modifiers.shift ? "FOCUS_IN" : "ZOOM_IN"); - break; + return true; case "-": sendPtz(modifiers.shift ? "FOCUS_OUT" : "ZOOM_OUT"); - break; + return true; } + + return false; }, ); diff --git a/web/src/components/overlay/detail/ReviewDetailDialog.tsx b/web/src/components/overlay/detail/ReviewDetailDialog.tsx index 63755c738..f796f03f5 100644 --- a/web/src/components/overlay/detail/ReviewDetailDialog.tsx +++ b/web/src/components/overlay/detail/ReviewDetailDialog.tsx @@ -175,6 +175,8 @@ export default function ReviewDetailDialog({ if (key == "Esc" && modifiers.down && !modifiers.repeat) { setIsOpen(false); } + + return true; }); const Overlay = isDesktop ? Sheet : MobilePage; diff --git a/web/src/components/player/GenericVideoPlayer.tsx b/web/src/components/player/GenericVideoPlayer.tsx index 4d6cb4ee5..25399771b 100644 --- a/web/src/components/player/GenericVideoPlayer.tsx +++ b/web/src/components/player/GenericVideoPlayer.tsx @@ -60,7 +60,7 @@ export function GenericVideoPlayer({ ["ArrowDown", "ArrowLeft", "ArrowRight", "ArrowUp", " ", "f", "m"], (key, modifiers) => { if (!modifiers.down || modifiers.repeat) { - return; + return true; } switch (key) { @@ -92,6 +92,8 @@ export function GenericVideoPlayer({ } break; } + + return true; }, ); diff --git a/web/src/components/player/VideoControls.tsx b/web/src/components/player/VideoControls.tsx index 12e6a75d8..d3bb1aa04 100644 --- a/web/src/components/player/VideoControls.tsx +++ b/web/src/components/player/VideoControls.tsx @@ -144,7 +144,7 @@ export default function VideoControls({ const onKeyboardShortcut = useCallback( (key: string | null, modifiers: KeyModifiers) => { if (!modifiers.down) { - return; + return true; } switch (key) { @@ -174,6 +174,8 @@ export default function VideoControls({ onPlayPause(!isPlaying); break; } + + return true; }, // only update when preview only changes // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/web/src/hooks/use-keyboard-listener.tsx b/web/src/hooks/use-keyboard-listener.tsx index d5f68bda3..555720e30 100644 --- a/web/src/hooks/use-keyboard-listener.tsx +++ b/web/src/hooks/use-keyboard-listener.tsx @@ -9,8 +9,7 @@ export type KeyModifiers = { export default function useKeyboardListener( keys: string[], - listener: (key: string | null, modifiers: KeyModifiers) => void, - preventDefault: boolean = true, + listener: (key: string | null, modifiers: KeyModifiers) => boolean, ) { const keyDownListener = useCallback( (e: KeyboardEvent) => { @@ -27,13 +26,13 @@ export default function useKeyboardListener( }; if (keys.includes(e.key)) { + const preventDefault = listener(e.key, modifiers); if (preventDefault) e.preventDefault(); - listener(e.key, modifiers); } else if (e.key === "Shift" || e.key === "Control" || e.key === "Meta") { listener(null, modifiers); } }, - [keys, listener, preventDefault], + [keys, listener], ); const keyUpListener = useCallback( diff --git a/web/src/pages/Exports.tsx b/web/src/pages/Exports.tsx index 5c7b4f5c1..bfaeac971 100644 --- a/web/src/pages/Exports.tsx +++ b/web/src/pages/Exports.tsx @@ -117,7 +117,7 @@ function Exports() { ["ArrowDown", "ArrowUp", "PageDown", "PageUp"], (key, modifiers) => { if (!modifiers.down) { - return; + return true; } switch (key) { @@ -146,6 +146,8 @@ function Exports() { }); break; } + + return true; }, ); diff --git a/web/src/pages/FaceLibrary.tsx b/web/src/pages/FaceLibrary.tsx index 38fbd105f..1e42ac4b8 100644 --- a/web/src/pages/FaceLibrary.tsx +++ b/web/src/pages/FaceLibrary.tsx @@ -117,8 +117,6 @@ export default function FaceLibrary() { const [addFace, setAddFace] = useState(false); // input focus for keyboard shortcuts - const [inputFocused, setInputFocused] = useState(false); - const onUploadImage = useCallback( (file: File) => { const formData = new FormData(); @@ -275,7 +273,7 @@ export default function FaceLibrary() { ["a", "Escape", "ArrowDown", "ArrowUp", "PageDown", "PageUp"], (key, modifiers) => { if (!modifiers.down) { - return; + return true; } switch (key) { @@ -288,23 +286,25 @@ export default function FaceLibrary() { ...(pageToggle === "train" ? trainImages : faceImages), ]); } + + return true; } break; case "Escape": setSelectedFaces([]); - break; + return true; case "ArrowDown": contentRef.current?.scrollBy({ top: 100, behavior: "smooth", }); - break; + return true; case "ArrowUp": contentRef.current?.scrollBy({ top: -100, behavior: "smooth", }); - break; + return true; case "PageDown": contentRef.current?.scrollBy({ top: contentRef.current.clientHeight / 2, @@ -316,10 +316,11 @@ export default function FaceLibrary() { top: -contentRef.current.clientHeight / 2, behavior: "smooth", }); - break; + return true; } + + return false; }, - !inputFocused, ); useEffect(() => { @@ -446,7 +447,6 @@ export default function FaceLibrary() { selectedFaces={selectedFaces} onClickFaces={onClickFaces} onRefresh={refreshFaces} - setInputFocused={setInputFocused} /> ) : ( void; onRefresh: () => void; - setInputFocused: React.Dispatch>; }; function TrainingGrid({ config, @@ -659,7 +658,6 @@ function TrainingGrid({ selectedFaces, onClickFaces, onRefresh, - setInputFocused, }: TrainingGridProps) { const { t } = useTranslation(["views/faceLibrary"]); @@ -734,7 +732,7 @@ function TrainingGrid({ setSimilarity={undefined} setSearchPage={setDialogTab} setSearch={(search) => setSelectedEvent(search as unknown as Event)} - setInputFocused={setInputFocused} + setInputFocused={() => {}} />
{ if (!modifiers.down) { - return; + return true; } switch (key) { case "f": toggleFullscreen(); - break; + return true; } + + return false; }); // document title diff --git a/web/src/pages/Logs.tsx b/web/src/pages/Logs.tsx index 4ee713fe5..97aa3bc5f 100644 --- a/web/src/pages/Logs.tsx +++ b/web/src/pages/Logs.tsx @@ -337,7 +337,7 @@ function Logs() { ["PageDown", "PageUp", "ArrowDown", "ArrowUp"], (key, modifiers) => { if (!key || !modifiers.down || !lazyLogWrapperRef.current) { - return; + return true; } const container = @@ -346,7 +346,7 @@ function Logs() { const logLineHeight = container?.querySelector(".log-line")?.clientHeight; if (!logLineHeight) { - return; + return true; } const scrollAmount = key.includes("Page") @@ -354,6 +354,7 @@ function Logs() { : logLineHeight; const direction = key.includes("Down") ? 1 : -1; container?.scrollBy({ top: scrollAmount * direction }); + return true; }, ); diff --git a/web/src/views/classification/ModelTrainingView.tsx b/web/src/views/classification/ModelTrainingView.tsx index 6fe3a38f6..6e2d1606f 100644 --- a/web/src/views/classification/ModelTrainingView.tsx +++ b/web/src/views/classification/ModelTrainingView.tsx @@ -237,13 +237,13 @@ export default function ModelTrainingView({ model }: ModelTrainingViewProps) { useKeyboardListener( ["a", "Escape", "ArrowDown", "ArrowUp", "PageDown", "PageUp"], (key, modifiers) => { - if (modifiers.repeat || !modifiers.down) { - return; + if (!modifiers.down) { + return true; } switch (key) { case "a": - if (modifiers.ctrl) { + if (modifiers.ctrl && !modifiers.repeat) { if (selectedImages.length) { setSelectedImages([]); } else { @@ -253,36 +253,39 @@ export default function ModelTrainingView({ model }: ModelTrainingViewProps) { : dataset?.[pageToggle] || []), ]); } + return true; } break; case "Escape": setSelectedImages([]); - break; + return true; case "ArrowDown": contentRef.current?.scrollBy({ top: 100, behavior: "smooth", }); - break; + return true; case "ArrowUp": contentRef.current?.scrollBy({ top: -100, behavior: "smooth", }); - break; + return true; case "PageDown": contentRef.current?.scrollBy({ top: contentRef.current.clientHeight / 2, behavior: "smooth", }); - break; + return true; case "PageUp": contentRef.current?.scrollBy({ top: -contentRef.current.clientHeight / 2, behavior: "smooth", }); - break; + return true; } + + return false; }, ); diff --git a/web/src/views/events/EventView.tsx b/web/src/views/events/EventView.tsx index c2e8ee88a..fde16ff44 100644 --- a/web/src/views/events/EventView.tsx +++ b/web/src/views/events/EventView.tsx @@ -654,13 +654,14 @@ function DetectionReview({ ["a", "r", "ArrowDown", "ArrowUp", "PageDown", "PageUp"], (key, modifiers) => { if (!modifiers.down) { - return; + return true; } switch (key) { case "a": if (modifiers.ctrl && !modifiers.repeat) { onSelectAllReviews(); + return true; } break; case "r": @@ -673,32 +674,34 @@ function DetectionReview({ }); setSelectedReviews([]); } - break; + return true; case "ArrowDown": contentRef.current?.scrollBy({ top: 100, behavior: "smooth", }); - break; + return true; case "ArrowUp": contentRef.current?.scrollBy({ top: -100, behavior: "smooth", }); - break; + return true; case "PageDown": contentRef.current?.scrollBy({ top: contentRef.current.clientHeight / 2, behavior: "smooth", }); - break; + return true; case "PageUp": contentRef.current?.scrollBy({ top: -contentRef.current.clientHeight / 2, behavior: "smooth", }); - break; + return true; } + + return false; }, ); diff --git a/web/src/views/live/LiveCameraView.tsx b/web/src/views/live/LiveCameraView.tsx index eef1c663a..1e427435c 100644 --- a/web/src/views/live/LiveCameraView.tsx +++ b/web/src/views/live/LiveCameraView.tsx @@ -309,21 +309,25 @@ export default function LiveCameraView({ useKeyboardListener(["m"], (key, modifiers) => { if (!modifiers.down) { - return; + return true; } switch (key) { case "m": if (supportsAudioOutput) { setAudio(!audio); + return true; } break; case "t": if (supports2WayTalk) { setMic(!mic); + return true; } break; } + + return false; }); // layout state diff --git a/web/src/views/search/SearchView.tsx b/web/src/views/search/SearchView.tsx index b97967043..c6c43b197 100644 --- a/web/src/views/search/SearchView.tsx +++ b/web/src/views/search/SearchView.tsx @@ -308,14 +308,19 @@ export default function SearchView({ const onKeyboardShortcut = useCallback( (key: string | null, modifiers: KeyModifiers) => { - if (!modifiers.down || !uniqueResults || inputFocused) { - return; + if (inputFocused) { + return false; + } + + if (!modifiers.down || !uniqueResults) { + return true; } switch (key) { case "a": if (modifiers.ctrl && !modifiers.repeat) { onSelectAllObjects(); + return true; } break; case "ArrowLeft": @@ -334,7 +339,7 @@ export default function SearchView({ setSearchDetail(uniqueResults[newIndex]); } - break; + return true; case "ArrowRight": if (uniqueResults.length > 0) { const currentIndex = searchDetail @@ -350,32 +355,34 @@ export default function SearchView({ setSearchDetail(uniqueResults[newIndex]); } - break; + return true; case "ArrowDown": contentRef.current?.scrollBy({ top: 100, behavior: "smooth", }); - break; + return true; case "ArrowUp": contentRef.current?.scrollBy({ top: -100, behavior: "smooth", }); - break; + return true; case "PageDown": contentRef.current?.scrollBy({ top: contentRef.current.clientHeight / 2, behavior: "smooth", }); - break; + return true; case "PageUp": contentRef.current?.scrollBy({ top: -contentRef.current.clientHeight / 2, behavior: "smooth", }); - break; + return true; } + + return false; }, [uniqueResults, inputFocused, onSelectAllObjects, searchDetail], ); @@ -391,7 +398,6 @@ export default function SearchView({ "PageUp", ], onKeyboardShortcut, - !inputFocused, ); // scroll into view