-
Notifications
You must be signed in to change notification settings - Fork 451
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add dynamic OS-specific shortcut system
- Implement shortcut definitions with OS-specific display values - Create useShortcuts hook for managing shortcuts and their descriptions - Update IconsSidebar to use dynamic shortcut descriptions - Integrate with electron to detect OS and handle shortcut actions fixes #234
- Loading branch information
1 parent
05ae423
commit 172f98d
Showing
7 changed files
with
224 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
export interface Shortcut { | ||
key: string | ||
action: string | ||
description: string | ||
displayValue: { | ||
mac: string | ||
other: string | ||
} | ||
} | ||
|
||
export const shortcuts: Shortcut[] = [ | ||
{ | ||
key: 'CommandOrControl+O', | ||
action: 'open-files', | ||
description: 'Open Files', | ||
displayValue: { mac: 'Cmd+O', other: 'Ctrl+O' }, | ||
}, | ||
{ | ||
key: 'CommandOrControl+N', | ||
action: 'open-new-note', | ||
description: 'New Note', | ||
displayValue: { mac: 'Cmd+N', other: 'Ctrl+N' }, | ||
}, | ||
{ | ||
key: 'CommandOrControl+P', | ||
action: 'open-search', | ||
description: 'Semantic Search', | ||
displayValue: { mac: 'Cmd+P', other: 'Ctrl+P' }, | ||
}, | ||
{ | ||
key: 'CommandOrControl+T', | ||
action: 'open-chat-bot', | ||
description: 'Open Chatbot', | ||
displayValue: { mac: 'Cmd+T', other: 'Ctrl+T' }, | ||
}, | ||
{ | ||
key: 'CommandOrControl+D', | ||
action: 'open-new-directory-modal', | ||
description: 'New Directory', | ||
displayValue: { mac: 'Cmd+D', other: 'Ctrl+D' }, | ||
}, | ||
{ | ||
key: 'CommandOrControl+Q', | ||
action: 'open-flashcard-quiz-modal', | ||
description: 'Flashcard quiz', | ||
displayValue: { mac: 'Cmd+Q', other: 'Ctrl+Q' }, | ||
}, | ||
{ | ||
key: 'CommandOrControl+,', | ||
action: 'open-settings-modal', | ||
description: 'Settings', | ||
displayValue: { mac: 'Cmd+,', other: 'Ctrl+,' }, | ||
}, | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/* eslint-disable import/no-extraneous-dependencies */ | ||
import { BrowserWindow } from 'electron' | ||
import { shortcuts } from './shortcutDefinitions' | ||
|
||
function isShortcutMatch(input: Electron.Input, shortcutKey: string): boolean { | ||
const keys = shortcutKey.split('+') | ||
const mainKey = keys.pop()?.toLowerCase() | ||
|
||
const modifiers = { | ||
control: keys.includes('Control') || keys.includes('CommandOrControl'), | ||
alt: keys.includes('Alt'), | ||
shift: keys.includes('Shift'), | ||
meta: keys.includes('Meta') || keys.includes('CommandOrControl'), | ||
} | ||
|
||
return ( | ||
input.key.toLowerCase() === mainKey && | ||
input.control === (modifiers.control || modifiers.meta) && | ||
input.alt === modifiers.alt && | ||
input.shift === modifiers.shift && | ||
(input.meta === modifiers.meta || input.control === modifiers.meta) | ||
) | ||
} | ||
|
||
export function registerGlobalShortcuts(mainWindow: BrowserWindow) { | ||
mainWindow.webContents.on('before-input-event', (event, input) => { | ||
shortcuts.forEach((shortcut) => { | ||
if (input.type === 'keyDown' && isShortcutMatch(input, shortcut.key)) { | ||
event.preventDefault() | ||
mainWindow.webContents.send(shortcut.action) | ||
} | ||
}) | ||
}) | ||
} | ||
|
||
export function unregisterGlobalShortcuts(mainWindow: BrowserWindow) { | ||
mainWindow.webContents.removeAllListeners('before-input-event') | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { useEffect, useState, useCallback, useRef } from 'react' | ||
import { shortcuts, Shortcut } from './shortcutDefinitions' | ||
import { useModalOpeners } from '../../contexts/ModalContext' | ||
import { useChatContext } from '../../contexts/ChatContext' | ||
import { useContentContext } from '@/contexts/ContentContext' | ||
|
||
function useShortcuts() { | ||
const { setIsNewDirectoryModalOpen, setIsFlashcardModeOpen, setIsSettingsModalOpen } = useModalOpeners() | ||
const { setSidebarShowing } = useChatContext() | ||
const { createUntitledNote } = useContentContext() | ||
const [shortcutMap, setShortcutMap] = useState<Record<string, string>>({}) | ||
const listenersRef = useRef<(() => void)[]>([]) | ||
|
||
const handleShortcut = useCallback( | ||
async (action: string) => { | ||
switch (action) { | ||
case 'open-new-note': | ||
await createUntitledNote() | ||
break | ||
case 'open-new-directory-modal': | ||
setIsNewDirectoryModalOpen(true) | ||
break | ||
case 'open-search': | ||
setSidebarShowing('search') | ||
break | ||
case 'open-files': | ||
setSidebarShowing('files') | ||
break | ||
case 'open-chat-bot': | ||
setSidebarShowing('chats') | ||
break | ||
case 'open-flashcard-quiz-modal': | ||
setIsFlashcardModeOpen(true) | ||
break | ||
case 'open-settings-modal': | ||
setIsSettingsModalOpen(true) | ||
break | ||
default: | ||
// Default do nothing | ||
break | ||
} | ||
}, | ||
[setSidebarShowing, setIsNewDirectoryModalOpen, setIsSettingsModalOpen, setIsFlashcardModeOpen, createUntitledNote], | ||
) | ||
|
||
useEffect(() => { | ||
async function setupShortcuts() { | ||
const platform = await window.electronUtils.getPlatform() | ||
const map: Record<string, string> = {} | ||
|
||
shortcuts.forEach((shortcut: Shortcut) => { | ||
const displayValue = platform === 'darwin' ? shortcut.displayValue.mac : shortcut.displayValue.other | ||
map[shortcut.action] = `${shortcut.description} (${displayValue})` | ||
|
||
const handler = () => { | ||
handleShortcut(shortcut.action) | ||
} | ||
const removeListener = window.ipcRenderer.receive(shortcut.action, handler) | ||
listenersRef.current.push(removeListener) | ||
}) | ||
|
||
setShortcutMap(map) | ||
} | ||
|
||
setupShortcuts() | ||
|
||
return () => { | ||
listenersRef.current.forEach((removeListener) => removeListener()) | ||
listenersRef.current = [] | ||
} | ||
}, [handleShortcut]) | ||
|
||
const getShortcutDescription = useCallback( | ||
(action: string) => { | ||
return shortcutMap[action] || '' | ||
}, | ||
[shortcutMap], | ||
) | ||
|
||
return { getShortcutDescription } | ||
} | ||
|
||
export default useShortcuts |