mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-28 13:31:32 +08:00
* Revert "feat: optimize minapp cache with LRU (#8160)"
This reverts commit f0043b4be5.
* feat: integrate logger service and enhance logging throughout the application
- Added a new LoggerService to standardize logging across the application.
- Replaced console.error and console.warn calls with logger methods for improved consistency and error tracking.
- Introduced a new IPC channel for logging messages to the main process.
- Updated various components and services to utilize the new logging system, enhancing error handling and debugging capabilities.
* refactor: enhance logging and error handling across various components
- Integrated the LoggerService for consistent logging throughout the application.
- Updated multiple components and services to utilize the new logging system, improving error tracking and debugging capabilities.
- Refactored file handling and error management in several services to enhance reliability and clarity.
- Improved the structure and readability of the codebase by removing redundant checks and simplifying logic.
* chore: update TypeScript configuration and enhance test setup
- Added test mock paths to tsconfig.web.json for improved test coverage.
- Configured Vitest to include a setup file for main tests, ensuring consistent test environment.
- Updated IPC logger context for better clarity in logging.
- Enhanced LoggerService to handle undefined values gracefully.
- Mocked LoggerService globally in renderer tests to streamline testing process.
* refactor: standardize logging across ProxyManager and ReduxService
- Replaced instances of Logger with logger for consistent logging implementation.
- Improved logging clarity in ProxyManager's configureProxy method and ReduxService's state handling.
- Enhanced error logging in ReduxService to align with the new logging system.
* refactor: reorganize LoggerService for improved clarity and consistency
- Moved the definition of SYSTEM_INFO, APP_VERSION, and DEFAULT_LEVEL to enhance code organization.
- Simplified the getIsDev function in the renderer LoggerService for better readability.
- Updated logging conditions to ensure messages are logged correctly based on context.
* docs: add usage instructions for LoggerService and clean up logging code
- Included important usage instructions for LoggerService in both English and Chinese.
- Commented out the console transport in LoggerService to streamline logging.
- Improved logging message formatting in MCPService for clarity.
- Removed redundant logging statements in SelectionService to enhance code cleanliness.
* refactor: update LoggerService documentation paths and enhance logging implementation
- Changed the documentation paths for LoggerService usage instructions to `docs/technical/how-to-use-logger-en.md` and `docs/technical/how-to-use-logger-zh.md`.
- Replaced console logging with the loggerService in various components, including `MCPSettings`, `BlockManager`, and multiple callback files, to ensure consistent logging practices across the application.
- Improved the clarity and context of log messages for better debugging and monitoring.
* docs: emphasize logger usage guidelines in documentation
- Added a note in both English and Chinese documentation to discourage the use of `console.xxx` for logging unless necessary, promoting consistent logging practices across the application.
298 lines
9.3 KiB
TypeScript
298 lines
9.3 KiB
TypeScript
import { loggerService } from '@logger'
|
|
import { handleZoomFactor } from '@main/utils/zoom'
|
|
import { Shortcut } from '@types'
|
|
import { BrowserWindow, globalShortcut } from 'electron'
|
|
|
|
import { configManager } from './ConfigManager'
|
|
import selectionService from './SelectionService'
|
|
import { windowService } from './WindowService'
|
|
|
|
const logger = loggerService.withContext('ShortcutService')
|
|
|
|
let showAppAccelerator: string | null = null
|
|
let showMiniWindowAccelerator: string | null = null
|
|
let selectionAssistantToggleAccelerator: string | null = null
|
|
let selectionAssistantSelectTextAccelerator: 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
|
|
const windowOnHandlers = new Map<BrowserWindow, { onFocusHandler: () => void; onBlurHandler: () => void }>()
|
|
|
|
function getShortcutHandler(shortcut: Shortcut) {
|
|
switch (shortcut.key) {
|
|
case 'zoom_in':
|
|
return (window: BrowserWindow) => handleZoomFactor([window], 0.1)
|
|
case 'zoom_out':
|
|
return (window: BrowserWindow) => handleZoomFactor([window], -0.1)
|
|
case 'zoom_reset':
|
|
return (window: BrowserWindow) => handleZoomFactor([window], 0, true)
|
|
case 'show_app':
|
|
return () => {
|
|
windowService.toggleMainWindow()
|
|
}
|
|
case 'mini_window':
|
|
return () => {
|
|
windowService.toggleMiniWindow()
|
|
}
|
|
case 'selection_assistant_toggle':
|
|
return () => {
|
|
if (selectionService) {
|
|
selectionService.toggleEnabled()
|
|
}
|
|
}
|
|
case 'selection_assistant_select_text':
|
|
return () => {
|
|
if (selectionService) {
|
|
selectionService.processSelectTextByShortcut()
|
|
}
|
|
}
|
|
default:
|
|
return null
|
|
}
|
|
}
|
|
|
|
function formatShortcutKey(shortcut: string[]): string {
|
|
return shortcut.join('+')
|
|
}
|
|
|
|
// convert the shortcut recorded by JS keyboard event key value to electron global shortcut format
|
|
// see: https://www.electronjs.org/zh/docs/latest/api/accelerator
|
|
const convertShortcutFormat = (shortcut: string | string[]): string => {
|
|
const accelerator = (() => {
|
|
if (Array.isArray(shortcut)) {
|
|
return shortcut
|
|
} else {
|
|
return shortcut.split('+').map((key) => key.trim())
|
|
}
|
|
})()
|
|
|
|
return accelerator
|
|
.map((key) => {
|
|
switch (key) {
|
|
// OLD WAY FOR MODIFIER KEYS, KEEP THEM HERE FOR REFERENCE
|
|
// case 'Command':
|
|
// return 'CommandOrControl'
|
|
// case 'Control':
|
|
// return 'Control'
|
|
// case 'Ctrl':
|
|
// return 'Control'
|
|
|
|
// NEW WAY FOR MODIFIER KEYS
|
|
// you can see all the modifier keys in the same
|
|
case 'CommandOrControl':
|
|
return 'CommandOrControl'
|
|
case 'Ctrl':
|
|
return 'Ctrl'
|
|
case 'Alt':
|
|
return 'Alt' // Use `Alt` instead of `Option`. The `Option` key only exists on macOS, whereas the `Alt` key is available on all platforms.
|
|
case 'Meta':
|
|
return 'Meta' // `Meta` key is mapped to the Windows key on Windows and Linux, `Cmd` on macOS.
|
|
case 'Shift':
|
|
return 'Shift'
|
|
|
|
// For backward compatibility with old data
|
|
case 'Command':
|
|
case 'Cmd':
|
|
return 'CommandOrControl'
|
|
case 'Control':
|
|
return 'Ctrl'
|
|
|
|
case 'ArrowUp':
|
|
return 'Up'
|
|
case 'ArrowDown':
|
|
return 'Down'
|
|
case 'ArrowLeft':
|
|
return 'Left'
|
|
case 'ArrowRight':
|
|
return 'Right'
|
|
case 'AltGraph':
|
|
return 'AltGr'
|
|
case 'Slash':
|
|
return '/'
|
|
case 'Semicolon':
|
|
return ';'
|
|
case 'BracketLeft':
|
|
return '['
|
|
case 'BracketRight':
|
|
return ']'
|
|
case 'Backslash':
|
|
return '\\'
|
|
case 'Quote':
|
|
return "'"
|
|
case 'Comma':
|
|
return ','
|
|
case 'Minus':
|
|
return '-'
|
|
case 'Equal':
|
|
return '='
|
|
default:
|
|
return key
|
|
}
|
|
})
|
|
.join('+')
|
|
}
|
|
|
|
export function registerShortcuts(window: BrowserWindow) {
|
|
if (isRegisterOnBoot) {
|
|
window.once('ready-to-show', () => {
|
|
if (configManager.getLaunchToTray()) {
|
|
registerOnlyUniversalShortcuts()
|
|
}
|
|
})
|
|
isRegisterOnBoot = false
|
|
}
|
|
|
|
//only for clearer code
|
|
const registerOnlyUniversalShortcuts = () => {
|
|
register(true)
|
|
}
|
|
|
|
//onlyUniversalShortcuts is used to register shortcuts that are not window specific, like show_app & mini_window
|
|
//onlyUniversalShortcuts is needed when we launch to tray
|
|
const register = (onlyUniversalShortcuts: boolean = false) => {
|
|
if (window.isDestroyed()) return
|
|
|
|
const shortcuts = configManager.getShortcuts()
|
|
if (!shortcuts) return
|
|
|
|
shortcuts.forEach((shortcut) => {
|
|
try {
|
|
if (shortcut.shortcut.length === 0) {
|
|
return
|
|
}
|
|
|
|
//if not enabled, exit early from the process.
|
|
if (!shortcut.enabled) {
|
|
return
|
|
}
|
|
|
|
// only register universal shortcuts when needed
|
|
if (
|
|
onlyUniversalShortcuts &&
|
|
!['show_app', 'mini_window', 'selection_assistant_toggle', 'selection_assistant_select_text'].includes(
|
|
shortcut.key
|
|
)
|
|
) {
|
|
return
|
|
}
|
|
|
|
const handler = getShortcutHandler(shortcut)
|
|
if (!handler) {
|
|
return
|
|
}
|
|
|
|
switch (shortcut.key) {
|
|
case 'show_app':
|
|
showAppAccelerator = formatShortcutKey(shortcut.shortcut)
|
|
break
|
|
|
|
case 'mini_window':
|
|
//available only when QuickAssistant enabled
|
|
if (!configManager.getEnableQuickAssistant()) {
|
|
return
|
|
}
|
|
showMiniWindowAccelerator = formatShortcutKey(shortcut.shortcut)
|
|
break
|
|
|
|
case 'selection_assistant_toggle':
|
|
selectionAssistantToggleAccelerator = formatShortcutKey(shortcut.shortcut)
|
|
break
|
|
|
|
case 'selection_assistant_select_text':
|
|
selectionAssistantSelectTextAccelerator = formatShortcutKey(shortcut.shortcut)
|
|
break
|
|
|
|
//the following ZOOMs will register shortcuts seperately, so will return
|
|
case 'zoom_in':
|
|
globalShortcut.register('CommandOrControl+=', () => handler(window))
|
|
globalShortcut.register('CommandOrControl+numadd', () => handler(window))
|
|
return
|
|
|
|
case 'zoom_out':
|
|
globalShortcut.register('CommandOrControl+-', () => handler(window))
|
|
globalShortcut.register('CommandOrControl+numsub', () => handler(window))
|
|
return
|
|
|
|
case 'zoom_reset':
|
|
globalShortcut.register('CommandOrControl+0', () => handler(window))
|
|
return
|
|
}
|
|
|
|
const accelerator = convertShortcutFormat(shortcut.shortcut)
|
|
|
|
globalShortcut.register(accelerator, () => handler(window))
|
|
} catch (error) {
|
|
logger.warn(`Failed to register shortcut ${shortcut.key}`)
|
|
}
|
|
})
|
|
}
|
|
|
|
const unregister = () => {
|
|
if (window.isDestroyed()) return
|
|
|
|
try {
|
|
globalShortcut.unregisterAll()
|
|
|
|
if (showAppAccelerator) {
|
|
const handler = getShortcutHandler({ key: 'show_app' } as Shortcut)
|
|
const accelerator = convertShortcutFormat(showAppAccelerator)
|
|
handler && globalShortcut.register(accelerator, () => handler(window))
|
|
}
|
|
|
|
if (showMiniWindowAccelerator) {
|
|
const handler = getShortcutHandler({ key: 'mini_window' } as Shortcut)
|
|
const accelerator = convertShortcutFormat(showMiniWindowAccelerator)
|
|
handler && globalShortcut.register(accelerator, () => handler(window))
|
|
}
|
|
|
|
if (selectionAssistantToggleAccelerator) {
|
|
const handler = getShortcutHandler({ key: 'selection_assistant_toggle' } as Shortcut)
|
|
const accelerator = convertShortcutFormat(selectionAssistantToggleAccelerator)
|
|
handler && globalShortcut.register(accelerator, () => handler(window))
|
|
}
|
|
|
|
if (selectionAssistantSelectTextAccelerator) {
|
|
const handler = getShortcutHandler({ key: 'selection_assistant_select_text' } as Shortcut)
|
|
const accelerator = convertShortcutFormat(selectionAssistantSelectTextAccelerator)
|
|
handler && globalShortcut.register(accelerator, () => handler(window))
|
|
}
|
|
} catch (error) {
|
|
logger.warn('Failed to unregister shortcuts')
|
|
}
|
|
}
|
|
|
|
// only register the event handlers once
|
|
if (undefined === windowOnHandlers.get(window)) {
|
|
// pass register() directly to listener, the func will receive Event as argument, it's not expected
|
|
const registerHandler = () => {
|
|
register()
|
|
}
|
|
window.on('focus', registerHandler)
|
|
window.on('blur', unregister)
|
|
windowOnHandlers.set(window, { onFocusHandler: registerHandler, onBlurHandler: unregister })
|
|
}
|
|
|
|
if (!window.isDestroyed() && window.isFocused()) {
|
|
register()
|
|
}
|
|
}
|
|
|
|
export function unregisterAllShortcuts() {
|
|
try {
|
|
showAppAccelerator = null
|
|
showMiniWindowAccelerator = null
|
|
selectionAssistantToggleAccelerator = null
|
|
selectionAssistantSelectTextAccelerator = null
|
|
windowOnHandlers.forEach((handlers, window) => {
|
|
window.off('focus', handlers.onFocusHandler)
|
|
window.off('blur', handlers.onBlurHandler)
|
|
})
|
|
windowOnHandlers.clear()
|
|
globalShortcut.unregisterAll()
|
|
} catch (error) {
|
|
logger.warn('Failed to unregister all shortcuts')
|
|
}
|
|
}
|