mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-20 23:22:05 +08:00
feat(SelectionAssistant): shortcut key to toggle on/off (#6983)
* feat: add toggle selection assistant functionality and corresponding shortcuts - Implemented toggleEnabled method in SelectionService to manage the selection assistant state. - Registered new shortcut for toggling the selection assistant in ShortcutService. - Updated StoreSyncService to sync the selection assistant state across renderer windows. - Added localization for the toggle selection assistant feature in multiple languages. - Adjusted ShortcutSettings to conditionally display the toggle selection assistant shortcut based on the platform. - Included toggle selection assistant in the initial state of shortcuts in the store. * fix: shortcut key * fix: accelerator name
This commit is contained in:
parent
26d018b1b7
commit
f6a935f14f
@ -14,6 +14,7 @@ import type {
|
|||||||
|
|
||||||
import type { ActionItem } from '../../renderer/src/types/selectionTypes'
|
import type { ActionItem } from '../../renderer/src/types/selectionTypes'
|
||||||
import { ConfigKeys, configManager } from './ConfigManager'
|
import { ConfigKeys, configManager } from './ConfigManager'
|
||||||
|
import storeSyncService from './StoreSyncService'
|
||||||
|
|
||||||
let SelectionHook: SelectionHookConstructor | null = null
|
let SelectionHook: SelectionHookConstructor | null = null
|
||||||
try {
|
try {
|
||||||
@ -334,6 +335,20 @@ export class SelectionService {
|
|||||||
this.logInfo('SelectionService Quitted')
|
this.logInfo('SelectionService Quitted')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle the enabled state of the selection service
|
||||||
|
* Will sync the new enabled store to all renderer windows
|
||||||
|
*/
|
||||||
|
public toggleEnabled(enabled: boolean | undefined = undefined) {
|
||||||
|
if (!this.selectionHook) return
|
||||||
|
|
||||||
|
const newEnabled = enabled === undefined ? !configManager.getSelectionAssistantEnabled() : enabled
|
||||||
|
|
||||||
|
configManager.setSelectionAssistantEnabled(newEnabled)
|
||||||
|
|
||||||
|
//sync the new enabled state to all renderer windows
|
||||||
|
storeSyncService.syncToRenderer('selectionStore/setSelectionEnabled', newEnabled)
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Create and configure the toolbar window
|
* Create and configure the toolbar window
|
||||||
* Sets up window properties, event handlers, and loads the toolbar UI
|
* Sets up window properties, event handlers, and loads the toolbar UI
|
||||||
|
|||||||
@ -4,10 +4,15 @@ import { BrowserWindow, globalShortcut } from 'electron'
|
|||||||
import Logger from 'electron-log'
|
import Logger from 'electron-log'
|
||||||
|
|
||||||
import { configManager } from './ConfigManager'
|
import { configManager } from './ConfigManager'
|
||||||
|
import selectionService from './SelectionService'
|
||||||
import { windowService } from './WindowService'
|
import { windowService } from './WindowService'
|
||||||
|
|
||||||
let showAppAccelerator: string | null = null
|
let showAppAccelerator: string | null = null
|
||||||
let showMiniWindowAccelerator: string | null = null
|
let showMiniWindowAccelerator: string | null = null
|
||||||
|
let selectionAssistantToggleAccelerator: string | null = null
|
||||||
|
|
||||||
|
//indicate if the shortcuts are registered on app boot time
|
||||||
|
let isRegisterOnBoot = true
|
||||||
|
|
||||||
// store the focus and blur handlers for each window to unregister them later
|
// store the focus and blur handlers for each window to unregister them later
|
||||||
const windowOnHandlers = new Map<BrowserWindow, { onFocusHandler: () => void; onBlurHandler: () => void }>()
|
const windowOnHandlers = new Map<BrowserWindow, { onFocusHandler: () => void; onBlurHandler: () => void }>()
|
||||||
@ -28,6 +33,12 @@ function getShortcutHandler(shortcut: Shortcut) {
|
|||||||
return () => {
|
return () => {
|
||||||
windowService.toggleMiniWindow()
|
windowService.toggleMiniWindow()
|
||||||
}
|
}
|
||||||
|
case 'selection_assistant_toggle':
|
||||||
|
return () => {
|
||||||
|
if (selectionService) {
|
||||||
|
selectionService.toggleEnabled()
|
||||||
|
}
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@ -93,11 +104,14 @@ const convertShortcutRecordedByKeyboardEventKeyValueToElectronGlobalShortcutForm
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function registerShortcuts(window: BrowserWindow) {
|
export function registerShortcuts(window: BrowserWindow) {
|
||||||
|
if (isRegisterOnBoot) {
|
||||||
window.once('ready-to-show', () => {
|
window.once('ready-to-show', () => {
|
||||||
if (configManager.getLaunchToTray()) {
|
if (configManager.getLaunchToTray()) {
|
||||||
registerOnlyUniversalShortcuts()
|
registerOnlyUniversalShortcuts()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
isRegisterOnBoot = false
|
||||||
|
}
|
||||||
|
|
||||||
//only for clearer code
|
//only for clearer code
|
||||||
const registerOnlyUniversalShortcuts = () => {
|
const registerOnlyUniversalShortcuts = () => {
|
||||||
@ -124,7 +138,10 @@ export function registerShortcuts(window: BrowserWindow) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// only register universal shortcuts when needed
|
// only register universal shortcuts when needed
|
||||||
if (onlyUniversalShortcuts && !['show_app', 'mini_window'].includes(shortcut.key)) {
|
if (
|
||||||
|
onlyUniversalShortcuts &&
|
||||||
|
!['show_app', 'mini_window', 'selection_assistant_toggle'].includes(shortcut.key)
|
||||||
|
) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,6 +163,10 @@ export function registerShortcuts(window: BrowserWindow) {
|
|||||||
showMiniWindowAccelerator = formatShortcutKey(shortcut.shortcut)
|
showMiniWindowAccelerator = formatShortcutKey(shortcut.shortcut)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
case 'selection_assistant_toggle':
|
||||||
|
selectionAssistantToggleAccelerator = formatShortcutKey(shortcut.shortcut)
|
||||||
|
break
|
||||||
|
|
||||||
//the following ZOOMs will register shortcuts seperately, so will return
|
//the following ZOOMs will register shortcuts seperately, so will return
|
||||||
case 'zoom_in':
|
case 'zoom_in':
|
||||||
globalShortcut.register('CommandOrControl+=', () => handler(window))
|
globalShortcut.register('CommandOrControl+=', () => handler(window))
|
||||||
@ -192,6 +213,14 @@ export function registerShortcuts(window: BrowserWindow) {
|
|||||||
convertShortcutRecordedByKeyboardEventKeyValueToElectronGlobalShortcutFormat(showMiniWindowAccelerator)
|
convertShortcutRecordedByKeyboardEventKeyValueToElectronGlobalShortcutFormat(showMiniWindowAccelerator)
|
||||||
handler && globalShortcut.register(accelerator, () => handler(window))
|
handler && globalShortcut.register(accelerator, () => handler(window))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (selectionAssistantToggleAccelerator) {
|
||||||
|
const handler = getShortcutHandler({ key: 'selection_assistant_toggle' } as Shortcut)
|
||||||
|
const accelerator = convertShortcutRecordedByKeyboardEventKeyValueToElectronGlobalShortcutFormat(
|
||||||
|
selectionAssistantToggleAccelerator
|
||||||
|
)
|
||||||
|
handler && globalShortcut.register(accelerator, () => handler(window))
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Logger.error('[ShortcutService] Failed to unregister shortcuts')
|
Logger.error('[ShortcutService] Failed to unregister shortcuts')
|
||||||
}
|
}
|
||||||
@ -217,6 +246,7 @@ export function unregisterAllShortcuts() {
|
|||||||
try {
|
try {
|
||||||
showAppAccelerator = null
|
showAppAccelerator = null
|
||||||
showMiniWindowAccelerator = null
|
showMiniWindowAccelerator = null
|
||||||
|
selectionAssistantToggleAccelerator = null
|
||||||
windowOnHandlers.forEach((handlers, window) => {
|
windowOnHandlers.forEach((handlers, window) => {
|
||||||
window.off('focus', handlers.onFocusHandler)
|
window.off('focus', handlers.onFocusHandler)
|
||||||
window.off('blur', handlers.onBlurHandler)
|
window.off('blur', handlers.onBlurHandler)
|
||||||
|
|||||||
@ -49,6 +49,23 @@ export class StoreSyncService {
|
|||||||
this.windowIds = this.windowIds.filter((id) => id !== windowId)
|
this.windowIds = this.windowIds.filter((id) => id !== windowId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sync an action to all renderer windows
|
||||||
|
* @param type Action type, like 'settings/setTray'
|
||||||
|
* @param payload Action payload
|
||||||
|
*
|
||||||
|
* NOTICE: DO NOT use directly in ConfigManager, may cause infinite sync loop
|
||||||
|
*/
|
||||||
|
public syncToRenderer(type: string, payload: any): void {
|
||||||
|
const action: StoreSyncAction = {
|
||||||
|
type,
|
||||||
|
payload
|
||||||
|
}
|
||||||
|
|
||||||
|
//-1 means the action is from the main process, will be broadcast to all windows
|
||||||
|
this.broadcastToOtherWindows(-1, action)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register IPC handlers for store sync communication
|
* Register IPC handlers for store sync communication
|
||||||
* Handles window subscription, unsubscription and action broadcasting
|
* Handles window subscription, unsubscription and action broadcasting
|
||||||
|
|||||||
@ -1701,6 +1701,7 @@
|
|||||||
"exit_fullscreen": "Exit Fullscreen",
|
"exit_fullscreen": "Exit Fullscreen",
|
||||||
"key": "Key",
|
"key": "Key",
|
||||||
"mini_window": "Quick Assistant",
|
"mini_window": "Quick Assistant",
|
||||||
|
"selection_assistant_toggle": "Toggle Selection Assistant",
|
||||||
"new_topic": "New Topic",
|
"new_topic": "New Topic",
|
||||||
"press_shortcut": "Press Shortcut",
|
"press_shortcut": "Press Shortcut",
|
||||||
"reset_defaults": "Reset Defaults",
|
"reset_defaults": "Reset Defaults",
|
||||||
|
|||||||
@ -1689,6 +1689,7 @@
|
|||||||
"exit_fullscreen": "フルスクリーンを終了",
|
"exit_fullscreen": "フルスクリーンを終了",
|
||||||
"key": "キー",
|
"key": "キー",
|
||||||
"mini_window": "クイックアシスタント",
|
"mini_window": "クイックアシスタント",
|
||||||
|
"selection_assistant_toggle": "選択アシスタントを切り替え",
|
||||||
"new_topic": "新しいトピック",
|
"new_topic": "新しいトピック",
|
||||||
"press_shortcut": "ショートカットを押す",
|
"press_shortcut": "ショートカットを押す",
|
||||||
"reset_defaults": "デフォルトのショートカットをリセット",
|
"reset_defaults": "デフォルトのショートカットをリセット",
|
||||||
|
|||||||
@ -1689,6 +1689,7 @@
|
|||||||
"exit_fullscreen": "Выйти из полноэкранного режима",
|
"exit_fullscreen": "Выйти из полноэкранного режима",
|
||||||
"key": "Клавиша",
|
"key": "Клавиша",
|
||||||
"mini_window": "Быстрый помощник",
|
"mini_window": "Быстрый помощник",
|
||||||
|
"selection_assistant_toggle": "Переключить помощник выделения",
|
||||||
"new_topic": "Новый топик",
|
"new_topic": "Новый топик",
|
||||||
"press_shortcut": "Нажмите сочетание клавиш",
|
"press_shortcut": "Нажмите сочетание клавиш",
|
||||||
"reset_defaults": "Сбросить настройки по умолчанию",
|
"reset_defaults": "Сбросить настройки по умолчанию",
|
||||||
|
|||||||
@ -1701,6 +1701,7 @@
|
|||||||
"exit_fullscreen": "退出全屏",
|
"exit_fullscreen": "退出全屏",
|
||||||
"key": "按键",
|
"key": "按键",
|
||||||
"mini_window": "快捷助手",
|
"mini_window": "快捷助手",
|
||||||
|
"selection_assistant_toggle": "开关划词助手",
|
||||||
"new_topic": "新建话题",
|
"new_topic": "新建话题",
|
||||||
"press_shortcut": "按下快捷键",
|
"press_shortcut": "按下快捷键",
|
||||||
"reset_defaults": "重置默认快捷键",
|
"reset_defaults": "重置默认快捷键",
|
||||||
|
|||||||
@ -1691,6 +1691,7 @@
|
|||||||
"copy_last_message": "複製上一則訊息",
|
"copy_last_message": "複製上一則訊息",
|
||||||
"key": "按鍵",
|
"key": "按鍵",
|
||||||
"mini_window": "快捷助手",
|
"mini_window": "快捷助手",
|
||||||
|
"selection_assistant_toggle": "開關劃詞助手",
|
||||||
"new_topic": "新增話題",
|
"new_topic": "新增話題",
|
||||||
"press_shortcut": "按下快捷鍵",
|
"press_shortcut": "按下快捷鍵",
|
||||||
"reset_defaults": "重設預設快捷鍵",
|
"reset_defaults": "重設預設快捷鍵",
|
||||||
|
|||||||
@ -18,10 +18,17 @@ const ShortcutSettings: FC = () => {
|
|||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
const { shortcuts } = useShortcuts()
|
const { shortcuts: originalShortcuts } = useShortcuts()
|
||||||
const inputRefs = useRef<Record<string, InputRef>>({})
|
const inputRefs = useRef<Record<string, InputRef>>({})
|
||||||
const [editingKey, setEditingKey] = useState<string | null>(null)
|
const [editingKey, setEditingKey] = useState<string | null>(null)
|
||||||
|
|
||||||
|
//TODO: if shortcut is not available on all the platforms, block the shortcut here
|
||||||
|
let shortcuts = originalShortcuts
|
||||||
|
if (!isWindows) {
|
||||||
|
//Selection Assistant only available on Windows now
|
||||||
|
shortcuts = shortcuts.filter((s) => s.key !== 'selection_assistant_toggle')
|
||||||
|
}
|
||||||
|
|
||||||
const handleClear = (record: Shortcut) => {
|
const handleClear = (record: Shortcut) => {
|
||||||
dispatch(
|
dispatch(
|
||||||
updateShortcut({
|
updateShortcut({
|
||||||
|
|||||||
@ -1508,6 +1508,24 @@ const migrateConfig = {
|
|||||||
state.llm.translateModel = SYSTEM_MODELS.defaultModel[2]
|
state.llm.translateModel = SYSTEM_MODELS.defaultModel[2]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add selection_assistant_toggle shortcut after mini_window if it doesn't exist
|
||||||
|
if (state.shortcuts) {
|
||||||
|
const miniWindowIndex = state.shortcuts.shortcuts.findIndex((shortcut) => shortcut.key === 'mini_window')
|
||||||
|
const hasSelectionAssistant = state.shortcuts.shortcuts.some(
|
||||||
|
(shortcut) => shortcut.key === 'selection_assistant_toggle'
|
||||||
|
)
|
||||||
|
|
||||||
|
if (miniWindowIndex !== -1 && !hasSelectionAssistant) {
|
||||||
|
state.shortcuts.shortcuts.splice(miniWindowIndex + 1, 0, {
|
||||||
|
key: 'selection_assistant_toggle',
|
||||||
|
shortcut: [],
|
||||||
|
editable: true,
|
||||||
|
enabled: false,
|
||||||
|
system: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return state
|
return state
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return state
|
return state
|
||||||
|
|||||||
@ -31,6 +31,14 @@ const initialState: ShortcutsState = {
|
|||||||
enabled: false,
|
enabled: false,
|
||||||
system: true
|
system: true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
//enable/disable selection assistant
|
||||||
|
key: 'selection_assistant_toggle',
|
||||||
|
shortcut: [],
|
||||||
|
editable: true,
|
||||||
|
enabled: false,
|
||||||
|
system: true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'new_topic',
|
key: 'new_topic',
|
||||||
shortcut: [isMac ? 'Command' : 'Ctrl', 'N'],
|
shortcut: [isMac ? 'Command' : 'Ctrl', 'N'],
|
||||||
@ -45,6 +53,7 @@ const initialState: ShortcutsState = {
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
system: false
|
system: false
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
key: 'toggle_show_topics',
|
key: 'toggle_show_topics',
|
||||||
shortcut: [isMac ? 'Command' : 'Ctrl', ']'],
|
shortcut: [isMac ? 'Command' : 'Ctrl', ']'],
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user