import React, { useEffect } from "react"; import useModuleStore, { useThreeDStore } from "../../store/useModuleStore"; import { usePlayerStore, useToggleStore } from "../../store/useUIToggleStore"; import { useActiveSubTool, useActiveTool, useAddAction, useDeleteTool, useSaveVersion, useSelectedWallItem, useShortcutStore, useToggleView, useToolMode, useViewSceneStore, } from "../../store/builder/store"; import useCameraModeStore, { usePlayButtonStore, } from "../../store/usePlayButtonStore"; import { detectModifierKeys } from "./detectModifierKeys"; import { useSelectedZoneStore } from "../../store/visualization/useZoneStore"; import { useLogger } from "../../components/ui/log/LoggerContext"; const KeyPressListener: React.FC = () => { const { activeModule, setActiveModule } = useModuleStore(); const { setActiveSubTool } = useActiveSubTool(); const { toggleUILeft, toggleUIRight, setToggleUI } = useToggleStore(); const { setToggleThreeD } = useThreeDStore(); const { setToolMode } = useToolMode(); const { isPlaying, setIsPlaying } = usePlayButtonStore(); const { toggleView, setToggleView } = useToggleView(); const { setDeleteTool } = useDeleteTool(); const { setAddAction } = useAddAction(); const { setSelectedWallItem } = useSelectedWallItem(); const { setActiveTool } = useActiveTool(); const { clearSelectedZone } = useSelectedZoneStore(); const { showShortcuts, setShowShortcuts } = useShortcutStore(); const { setWalkMode } = useCameraModeStore(); const { setIsVersionSaved } = useSaveVersion(); const { isLogListVisible, setIsLogListVisible } = useLogger(); const { hidePlayer, setHidePlayer } = usePlayerStore(); const { viewSceneLabels, setViewSceneLabels } = useViewSceneStore(); const isTextInput = (element: Element | null): boolean => element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element?.getAttribute("contenteditable") === "true"; const handleModuleSwitch = (keyCombination: string) => { const modules: Record = { "1": "builder", "2": "simulation", "3": "visualization", "4": "market", }; const module = modules[keyCombination]; if (module && !toggleView) { console.log("hi"); setActiveTool("cursor"); setActiveSubTool("cursor"); if (module === "market") setToggleUI(false, false); setActiveModule(module); } }; const handlePrimaryTools = (key: string) => { const toolMap: Record = { V: "cursor", X: "delete", H: "free-hand", }; const tool = toolMap[key]; if (tool) { setActiveTool(tool); setActiveSubTool(tool); } }; const handleBuilderShortcuts = (key: string) => { if (activeModule !== "builder" || isPlaying) return; if (key === "TAB") { const toggleTo2D = toggleView; setToggleView(!toggleTo2D); setToggleThreeD(toggleTo2D); setToggleUI(toggleTo2D, toggleTo2D); if (toggleTo2D) { setSelectedWallItem(null); setDeleteTool(false); setAddAction(null); } setActiveTool("cursor"); setActiveSubTool("cursor"); return; } // These should only apply in 2D view const twoDToolConfigs: Record = { Q: { tool: "draw-wall", mode: "Wall" }, "6": { tool: "draw-wall", mode: "Wall" }, R: { tool: "draw-aisle", mode: "Aisle" }, "7": { tool: "draw-aisle", mode: "Aisle" }, E: { tool: "draw-zone", mode: "Zone" }, "8": { tool: "draw-zone", mode: "Zone" }, T: { tool: "draw-floor", mode: "Floor" }, "9": { tool: "draw-floor", mode: "Floor" }, }; const config = twoDToolConfigs[key]; if (toggleView && config) { setActiveTool(config.tool); setToolMode(config.mode); } // Measurement tool should work in both 2D and 3D if (key === "M") { setActiveTool("measure"); setToolMode("MeasurementScale"); } }; const handleSidebarShortcuts = (key: string) => { if (activeModule === "market") return; const updateLocalStorage = (left: boolean, right: boolean) => { localStorage.setItem("navBarUiLeft", JSON.stringify(left)); localStorage.setItem("navBarUiRight", JSON.stringify(right)); }; switch (key) { case "Ctrl+\\": if (toggleUILeft === toggleUIRight) { const newState = !toggleUILeft; setToggleUI(newState, newState); updateLocalStorage(newState, newState); } else { setToggleUI(true, true); updateLocalStorage(true, true); } break; case "Ctrl+]": setToggleUI(toggleUILeft, !toggleUIRight); updateLocalStorage(toggleUILeft, !toggleUIRight); break; case "Ctrl+[": setToggleUI(!toggleUILeft, toggleUIRight); updateLocalStorage(!toggleUILeft, toggleUIRight); break; default: break; } }; const handleKeyPress = (event: KeyboardEvent) => { console.log( "isTextInput(document.activeElement): ", isTextInput(document.activeElement) ); if (isTextInput(document.activeElement)) return; const keyCombination = detectModifierKeys(event); if ( !keyCombination || ["F5", "F11", "F12"].includes(event.key) || keyCombination === "Ctrl+R" ) return; console.log("keyCombination: ", keyCombination); event.preventDefault(); // Shortcuts specific for sidebar visibility toggle and others specific to sidebar if added handleSidebarShortcuts(keyCombination); // Active module selection (builder, simulation, etc.) handleModuleSwitch(keyCombination); // Common editing tools: cursor | delete | free-hand handlePrimaryTools(keyCombination); // Shortcuts specific to the builder module (e.g., drawing and measurement tools) handleBuilderShortcuts(keyCombination); // Shortcut to enter play mode if (keyCombination === "Ctrl+P" && !toggleView) { setIsPlaying(true); } if (keyCombination === "L") { setIsLogListVisible(!isLogListVisible); } if (keyCombination === "H") { setHidePlayer(!hidePlayer); } if (keyCombination === "ESCAPE") { setWalkMode(false); setActiveTool("cursor"); setActiveSubTool("cursor"); setIsPlaying(false); clearSelectedZone(); setShowShortcuts(false); setIsVersionSaved(false); setIsLogListVisible(false); } if (keyCombination === "Ctrl+Shift+?") { setShowShortcuts(!showShortcuts); } if (keyCombination === "U") { console.log("viewSceneLabels: ", viewSceneLabels); setViewSceneLabels((prev) => !prev); } // Placeholder for future implementation if ( ["Ctrl+Z", "Ctrl+Y", "Ctrl+Shift+Z", "Ctrl+F"].includes(keyCombination) ) { // Implement undo/redo/help/find/shortcuts } }; useEffect(() => { window.addEventListener("keydown", handleKeyPress); return () => window.removeEventListener("keydown", handleKeyPress); // eslint-disable-next-line react-hooks/exhaustive-deps }, [ activeModule, toggleUIRight, toggleUILeft, toggleView, showShortcuts, isPlaying, isLogListVisible, hidePlayer, ]); return null; }; export default KeyPressListener;