diff --git a/src/lib/components/chat/MessageInput.svelte b/src/lib/components/chat/MessageInput.svelte index ab7524d5d8..97e01a8034 100644 --- a/src/lib/components/chat/MessageInput.svelte +++ b/src/lib/components/chat/MessageInput.svelte @@ -1095,7 +1095,10 @@ shiftKey = true; } - if (matchKeybinding(e) === Shortcut.TOGGLE_DICTATION) { + if ( + $settings?.keyboardShortcuts !== false && + matchKeybinding(e) === Shortcut.TOGGLE_DICTATION + ) { e.preventDefault(); if (recording) { // Confirm and stop recording diff --git a/src/lib/components/chat/Settings/Shortcuts.svelte b/src/lib/components/chat/Settings/Shortcuts.svelte index 2cc9093ebb..f0c093f206 100644 --- a/src/lib/components/chat/Settings/Shortcuts.svelte +++ b/src/lib/components/chat/Settings/Shortcuts.svelte @@ -14,6 +14,7 @@ } from '$lib/shortcuts'; import type { KeybindingsMap, ShortcutDefinition } from '$lib/shortcuts'; import { settings } from '$lib/stores'; + import Switch from '$lib/components/common/Switch.svelte'; import ShortcutItem from '../ShortcutItem.svelte'; type ShortcutEntry = { @@ -29,12 +30,16 @@ const i18n: I18nStore = getContext('i18n'); + export let saveSettings: (updated: Record) => Promise; + let categorizedShortcuts: CategorizedShortcuts = {}; let isMac = false; let recordingShortcut: Shortcut | null = null; + let enableKeyboardShortcuts = true; onMount(() => { isMac = /Mac/i.test(navigator.userAgent); + enableKeyboardShortcuts = $settings?.keyboardShortcuts ?? true; }); $: { @@ -112,6 +117,31 @@ +
+
+
+ {$i18n.t('Enable Keyboard Shortcuts')} +
+ +
+ { + saveSettings({ keyboardShortcuts: enableKeyboardShortcuts }); + }} + /> +
+
+

+ {$i18n.t('When disabled, keyboard shortcuts will not trigger any actions.')} +

+
+
diff --git a/src/lib/components/chat/SettingsModal.svelte b/src/lib/components/chat/SettingsModal.svelte index c8bff36160..79321cc8fb 100644 --- a/src/lib/components/chat/SettingsModal.svelte +++ b/src/lib/components/chat/SettingsModal.svelte @@ -1171,7 +1171,7 @@ {:else if selectedTab === 'notifications'} {:else if selectedTab === 'shortcuts'} - + {:else if selectedTab === 'connections'} ) => { diff --git a/src/lib/components/common/HotkeyHint.svelte b/src/lib/components/common/HotkeyHint.svelte index 539b6cbd9f..dffdcf346f 100644 --- a/src/lib/components/common/HotkeyHint.svelte +++ b/src/lib/components/common/HotkeyHint.svelte @@ -2,13 +2,15 @@ import { onMount } from 'svelte'; import { formatChord, isConfigurableShortcut, keybindings, shortcuts } from '$lib/shortcuts'; import type { Shortcut } from '$lib/shortcuts'; + import { settings } from '$lib/stores'; export let name: string; export let className = ''; let isMac = false; let mounted = false; - let isVisible = true; + + $: isVisible = $settings?.keyboardShortcuts !== false; onMount(() => { isMac = /Mac/i.test(navigator.userAgent); diff --git a/src/lib/i18n/locales/en-US/translation.json b/src/lib/i18n/locales/en-US/translation.json index 9a78416377..92398e29f6 100644 --- a/src/lib/i18n/locales/en-US/translation.json +++ b/src/lib/i18n/locales/en-US/translation.json @@ -907,6 +907,7 @@ "Enable Code Execution": "", "Enable Code Interpreter": "", "Enable Image Generation": "", + "Enable Keyboard Shortcuts": "", "Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "", "Enable Memory Mapping (mmap) to load model data. This option allows the system to use disk storage as an extension of RAM by treating disk files as if they were in RAM. This can improve model performance by allowing for faster data access. However, it may not work correctly with all systems and can consume a significant amount of disk space.": "", "Enable Message Queue": "", @@ -2869,6 +2870,7 @@ "What's New in": "", "What's on your mind?": "", "When": "", + "When disabled, keyboard shortcuts will not trigger any actions.": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "", "Whisper (Local)": "", "Who can share to this group": "", diff --git a/src/lib/stores/index.ts b/src/lib/stores/index.ts index 37757ef42b..fc3dfac5be 100644 --- a/src/lib/stores/index.ts +++ b/src/lib/stores/index.ts @@ -251,6 +251,7 @@ type Settings = { splitLargeDeltas?: boolean; chatDirection?: 'LTR' | 'RTL' | 'auto'; ctrlEnterToSend?: boolean; + keyboardShortcuts?: boolean; renderMarkdownInPreviews?: boolean; renderMarkdownInUserMessages?: boolean; renderMarkdownInAssistantMessages?: boolean; diff --git a/src/routes/(app)/+layout.svelte b/src/routes/(app)/+layout.svelte index f79ea0f98d..5a62f5d800 100644 --- a/src/routes/(app)/+layout.svelte +++ b/src/routes/(app)/+layout.svelte @@ -248,6 +248,10 @@ const setupKeyboardShortcuts = () => { document.addEventListener('keydown', async (event) => { + if ($settings?.keyboardShortcuts === false) { + return; + } + const shortcut = matchKeybinding(event); if (shortcut === Shortcut.SEARCH) { console.log('Shortcut triggered: SEARCH');