diff --git a/public/config.json b/public/config.json index 4bd2d00..de5b431 100644 --- a/public/config.json +++ b/public/config.json @@ -35,6 +35,7 @@ "play": "space", "undo": "ctrl+z", "redo": "ctrl+shift+z", + "select_all": "ctrl+a", "copy": "ctrl+c", "cut": "ctrl+x", "paste": "ctrl+v", diff --git a/src/core/config/ConfigManager.ts b/src/core/config/ConfigManager.ts index c94a560..841d552 100644 --- a/src/core/config/ConfigManager.ts +++ b/src/core/config/ConfigManager.ts @@ -41,6 +41,7 @@ interface AppConfig { play: string; undo: string; redo: string; + select_all: string; copy: string; cut: string; paste: string; @@ -195,6 +196,7 @@ export class ConfigManager { play: 'space', undo: 'ctrl+z', redo: 'ctrl+shift+z', + select_all: 'ctrl+a', copy: 'ctrl+c', cut: 'ctrl+x', paste: 'ctrl+v', diff --git a/src/hooks/useGlobalKeyboardHandler.ts b/src/hooks/useGlobalKeyboardHandler.ts index 3911dd3..ac38500 100644 --- a/src/hooks/useGlobalKeyboardHandler.ts +++ b/src/hooks/useGlobalKeyboardHandler.ts @@ -4,6 +4,7 @@ import { handleCopyOperation, handlePasteOperation } from '../util/copyPasteUtil import { saveProject } from '../util/saveUtil'; import { ConfigManager } from '../core/config/ConfigManager'; import { useProjectStore } from '../stores/projectStore'; +import { selectAllNotesInActiveRegion } from '../util/selectionUtil'; /** * Global keyboard handler for copy/paste, undo/redo, play/pause, and save operations @@ -56,6 +57,7 @@ export const useGlobalKeyboardHandler = () => { const redoShortcut = configManager.get('hotkeys.main.redo') as string; const copyShortcut = configManager.get('hotkeys.main.copy') as string; const pasteShortcut = configManager.get('hotkeys.main.paste') as string; + const selectAllShortcut = configManager.get('hotkeys.main.select_all') as string; const playShortcut = configManager.get('hotkeys.main.play') as string; const saveShortcut = configManager.get('hotkeys.main.save') as string; @@ -109,6 +111,13 @@ export const useGlobalKeyboardHandler = () => { return; } + // Check for select-all-notes shortcut (only when piano roll is open) + if (selectAllShortcut && matchesKeyboardShortcut(event, selectAllShortcut)) { + event.preventDefault(); + selectAllNotesInActiveRegion(); + return; + } + // Check for play/pause shortcut if (playShortcut && matchesKeyboardShortcut(event, playShortcut)) { event.preventDefault(); diff --git a/src/util/selectionUtil.ts b/src/util/selectionUtil.ts new file mode 100644 index 0000000..c636643 --- /dev/null +++ b/src/util/selectionUtil.ts @@ -0,0 +1,56 @@ +import { KGCore } from '../core/KGCore'; +import { useProjectStore } from '../stores/projectStore'; +import { KGMidiRegion } from '../core/region/KGMidiRegion'; +import { KGTrack } from '../core/track/KGTrack'; +import { KGMidiNote } from '../core/midi/KGMidiNote'; + +/** + * Select all notes in the active region if the piano roll is visible. + * Logs the count and region id on success. + * Returns true if selection was performed; false otherwise. + */ +export const selectAllNotesInActiveRegion = (): boolean => { + const { showPianoRoll, activeRegionId, updateTrack } = useProjectStore.getState(); + if (!showPianoRoll || !activeRegionId) { + return false; + } + + try { + const core = KGCore.instance(); + const project = core.getCurrentProject(); + const tracks = project.getTracks(); + + let parentTrack: KGTrack | null = null; + let activeRegion: KGMidiRegion | null = null; + + for (const track of tracks) { + const region = track.getRegions().find(r => r.getId() === activeRegionId); + if (region && region instanceof KGMidiRegion) { + parentTrack = track as KGTrack; + activeRegion = region as KGMidiRegion; + break; + } + } + + if (!activeRegion || !parentTrack) { + return false; + } + + // Clear previous selection and select all notes in the region + core.clearSelectedItems(); + const notes: KGMidiNote[] = activeRegion.getNotes(); + notes.forEach((n: KGMidiNote) => n.select()); + core.addSelectedItems(notes); + + // Update track to persist selection state in model/UI + updateTrack(parentTrack); + + console.log(`Selected all notes: count=${notes.length}, regionId=${activeRegionId}`); + return true; + } catch (error) { + console.error('Select all notes failed:', error); + return false; + } +}; + +