import { RemoveFrameCommand } from '../core/commands/frameCommands'; import { ui } from '../ui'; import { confirmDeleteAsset, createContainer, removeNodes, removeObjects } from './actions'; import type { EditorState } from './state'; export interface ShortcutActions { play(): void; stop(): void; togglePause(): void; } /** * Global keyboard shortcuts (see the wiki page "Keyboard"). Text fields keep their own key handling; * these only run when no focused widget consumed the key. */ export function installShortcuts(state: EditorState, actions: ShortcutActions): void { ui().focus.globalHandlers.push((event) => { const mod = event.ctrlKey || event.metaKey; const key = event.key.toLowerCase(); if (event.key === 'Escape' && state.mode === 'play') { actions.stop(); return true; } if (mod && key === 'z') { if (event.shiftKey) state.redo(); else state.undo(); return true; } if (mod && key === 'y') { state.redo(); return true; } if (mod && key === 'g') { const s = state.selection; if (s?.kind === 'object') createContainer(state, s.holderId, s.objectIds); return true; } if (event.key === 'Delete' || event.key === 'Backspace') { const s = state.selection; if (s?.kind === 'object') removeObjects(state, s.holderId, s.objectIds); else if (s?.kind === 'node') removeNodes(state, s.assetId, s.nodeIds); else if (s?.kind === 'frame') state.execute(new RemoveFrameCommand(s.assetId, s.frameId)); else if (s?.kind === 'asset') confirmDeleteAsset(state, s.assetId); return s !== null; } // Ctrl+Enter starts play and then holds/resumes it. A plain letter would be taken away from // the game, which owns the keyboard while playing. if (mod && event.key === 'Enter') { if (state.mode === 'edit') actions.play(); else actions.togglePause(); return true; } return false; }); }