From f92edadb615eec9c8099a45adefc96c3b4a809b4 Mon Sep 17 00:00:00 2001 From: icarus Date: Fri, 15 Aug 2025 14:02:09 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8DEscape=E9=94=AE?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E5=86=92=E6=B3=A1=E9=97=AE=E9=A2=98=E5=B9=B6?= =?UTF-8?q?=E6=94=B9=E8=BF=9B=E5=85=A8=E5=B1=8F=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复多个组件中Escape键事件未阻止冒泡的问题 添加全屏控制IPC通道 将全屏退出逻辑移至渲染进程处理 移除主进程中冗余的全屏退出处理代码 --- packages/shared/IpcChannel.ts | 1 + src/main/ipc.ts | 4 ++ src/main/services/WindowService.ts | 40 +++++++++---------- src/preload/index.ts | 1 + .../src/components/CollapsibleSearchBar.tsx | 1 + src/renderer/src/components/ContentSearch.tsx | 1 + .../src/components/EditableNumber/index.tsx | 1 + .../Popups/SelectModelPopup/popup.tsx | 1 + .../src/components/QuickPanel/view.tsx | 1 + src/renderer/src/components/TopView/index.tsx | 22 +++++++++- src/renderer/src/hooks/useInPlaceEdit.ts | 1 + .../src/pages/home/Inputbar/Inputbar.tsx | 1 + .../pages/settings/ProviderSettings/index.tsx | 1 + 13 files changed, 54 insertions(+), 22 deletions(-) diff --git a/packages/shared/IpcChannel.ts b/packages/shared/IpcChannel.ts index bae5c54a7e..20bc852e7e 100644 --- a/packages/shared/IpcChannel.ts +++ b/packages/shared/IpcChannel.ts @@ -35,6 +35,7 @@ export enum IpcChannel { App_InstallBunBinary = 'app:install-bun-binary', App_LogToMain = 'app:log-to-main', App_SaveData = 'app:save-data', + App_SetFullScreen = 'app:set-full-screen', App_MacIsProcessTrusted = 'app:mac-is-process-trusted', App_MacRequestProcessTrust = 'app:mac-request-process-trust', diff --git a/src/main/ipc.ts b/src/main/ipc.ts index 98d384c7cc..f094e8d580 100644 --- a/src/main/ipc.ts +++ b/src/main/ipc.ts @@ -191,6 +191,10 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) { }) } + ipcMain.handle(IpcChannel.App_SetFullScreen, (_, value: boolean): void => { + mainWindow.setFullScreen(value) + }) + ipcMain.handle(IpcChannel.Config_Set, (_, key: string, value: any, isNotify: boolean = false) => { configManager.set(key, value, isNotify) }) diff --git a/src/main/services/WindowService.ts b/src/main/services/WindowService.ts index 185901322f..e2c2dc4866 100644 --- a/src/main/services/WindowService.ts +++ b/src/main/services/WindowService.ts @@ -223,26 +223,26 @@ export class WindowService { }) // 添加Escape键退出全屏的支持 - mainWindow.webContents.on('before-input-event', (event, input) => { - // 当按下Escape键且窗口处于全屏状态时退出全屏 - if (input.key === 'Escape' && !input.alt && !input.control && !input.meta && !input.shift) { - if (mainWindow.isFullScreen()) { - // 获取 shortcuts 配置 - const shortcuts = configManager.getShortcuts() - const exitFullscreenShortcut = shortcuts.find((s) => s.key === 'exit_fullscreen') - if (exitFullscreenShortcut == undefined) { - mainWindow.setFullScreen(false) - return - } - if (exitFullscreenShortcut?.enabled) { - event.preventDefault() - mainWindow.setFullScreen(false) - return - } - } - } - return - }) + // mainWindow.webContents.on('before-input-event', (event, input) => { + // // 当按下Escape键且窗口处于全屏状态时退出全屏 + // if (input.key === 'Escape' && !input.alt && !input.control && !input.meta && !input.shift) { + // if (mainWindow.isFullScreen()) { + // // 获取 shortcuts 配置 + // const shortcuts = configManager.getShortcuts() + // const exitFullscreenShortcut = shortcuts.find((s) => s.key === 'exit_fullscreen') + // if (exitFullscreenShortcut == undefined) { + // mainWindow.setFullScreen(false) + // return + // } + // if (exitFullscreenShortcut?.enabled) { + // event.preventDefault() + // mainWindow.setFullScreen(false) + // return + // } + // } + // } + // return + // }) } private setupWebContentsHandlers(mainWindow: BrowserWindow) { diff --git a/src/preload/index.ts b/src/preload/index.ts index 9b46576476..594bade1db 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -76,6 +76,7 @@ const api = { clearCache: () => ipcRenderer.invoke(IpcChannel.App_ClearCache), logToMain: (source: LogSourceWithContext, level: LogLevel, message: string, data: any[]) => ipcRenderer.invoke(IpcChannel.App_LogToMain, source, level, message, data), + setFullScreen: (value: boolean): Promise => ipcRenderer.invoke(IpcChannel.App_SetFullScreen, value), mac: { isProcessTrusted: (): Promise => ipcRenderer.invoke(IpcChannel.App_MacIsProcessTrusted), requestProcessTrust: (): Promise => ipcRenderer.invoke(IpcChannel.App_MacRequestProcessTrust) diff --git a/src/renderer/src/components/CollapsibleSearchBar.tsx b/src/renderer/src/components/CollapsibleSearchBar.tsx index 0b7c038a68..3ce3b436be 100644 --- a/src/renderer/src/components/CollapsibleSearchBar.tsx +++ b/src/renderer/src/components/CollapsibleSearchBar.tsx @@ -62,6 +62,7 @@ const CollapsibleSearchBar: React.FC = ({ onSearch, i onChange={(e) => handleTextChange(e.target.value)} onKeyDown={(e) => { if (e.key === 'Escape') { + e.stopPropagation() handleTextChange('') if (!searchText) setSearchVisible(false) } diff --git a/src/renderer/src/components/ContentSearch.tsx b/src/renderer/src/components/ContentSearch.tsx index 6842312137..637af96de4 100644 --- a/src/renderer/src/components/ContentSearch.tsx +++ b/src/renderer/src/components/ContentSearch.tsx @@ -282,6 +282,7 @@ export const ContentSearch = React.forwardRef( implementation.searchNext() } } else if (event.key === 'Escape') { + event.stopPropagation() implementation.disable() } }, diff --git a/src/renderer/src/components/EditableNumber/index.tsx b/src/renderer/src/components/EditableNumber/index.tsx index 3cc0f09507..220cf5fb57 100644 --- a/src/renderer/src/components/EditableNumber/index.tsx +++ b/src/renderer/src/components/EditableNumber/index.tsx @@ -63,6 +63,7 @@ const EditableNumber: FC = ({ if (e.key === 'Enter') { handleBlur() } else if (e.key === 'Escape') { + e.stopPropagation() setInputValue(value) setIsEditing(false) } diff --git a/src/renderer/src/components/Popups/SelectModelPopup/popup.tsx b/src/renderer/src/components/Popups/SelectModelPopup/popup.tsx index e7557f5e5e..3ea309f6a0 100644 --- a/src/renderer/src/components/Popups/SelectModelPopup/popup.tsx +++ b/src/renderer/src/components/Popups/SelectModelPopup/popup.tsx @@ -256,6 +256,7 @@ const PopupContainer: React.FC = ({ model, resolve, modelFilter }) => { break case 'Escape': e.preventDefault() + e.stopPropagation() setOpen(false) resolve(undefined) break diff --git a/src/renderer/src/components/QuickPanel/view.tsx b/src/renderer/src/components/QuickPanel/view.tsx index c955453903..a129477599 100644 --- a/src/renderer/src/components/QuickPanel/view.tsx +++ b/src/renderer/src/components/QuickPanel/view.tsx @@ -456,6 +456,7 @@ export const QuickPanelView: React.FC = ({ setInputText }) => { } break case 'Escape': + e.stopPropagation() handleClose('esc') break } diff --git a/src/renderer/src/components/TopView/index.tsx b/src/renderer/src/components/TopView/index.tsx index 91d5cc42cd..8c8b48a22c 100644 --- a/src/renderer/src/components/TopView/index.tsx +++ b/src/renderer/src/components/TopView/index.tsx @@ -1,5 +1,7 @@ +import { loggerService } from '@logger' import TopViewMinappContainer from '@renderer/components/MinApp/TopViewMinappContainer' import { useAppInit } from '@renderer/hooks/useAppInit' +import { useShortcuts } from '@renderer/hooks/useShortcuts' import { message, Modal } from 'antd' import React, { PropsWithChildren, useCallback, useEffect, useRef, useState } from 'react' @@ -24,6 +26,8 @@ type ElementItem = { element: React.FC | React.ReactNode } +const logger = loggerService.withContext('TopView') + const TopViewContainer: React.FC = ({ children }) => { const [elements, setElements] = useState([]) const elementsRef = useRef([]) @@ -31,6 +35,8 @@ const TopViewContainer: React.FC = ({ children }) => { const [messageApi, messageContextHolder] = message.useMessage() const [modal, modalContextHolder] = Modal.useModal() + const { shortcuts } = useShortcuts() + const enableQuitFullScreen = shortcuts.find((item) => item.key === 'exit_fullscreen')?.enabled useAppInit() @@ -72,8 +78,20 @@ const TopViewContainer: React.FC = ({ children }) => { ) }, []) + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + logger.debug('keydown', e) + if (!enableQuitFullScreen) return + + if (e.key === 'Escape' && !e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey) { + window.api.setFullScreen(false) + } + }, + [enableQuitFullScreen] + ) + return ( - <> +
{children} {messageContextHolder} {modalContextHolder} @@ -83,7 +101,7 @@ const TopViewContainer: React.FC = ({ children }) => { {typeof Element === 'function' ? : Element} ))} - +
) } diff --git a/src/renderer/src/hooks/useInPlaceEdit.ts b/src/renderer/src/hooks/useInPlaceEdit.ts index 3af085f99a..077b6d21cb 100644 --- a/src/renderer/src/hooks/useInPlaceEdit.ts +++ b/src/renderer/src/hooks/useInPlaceEdit.ts @@ -66,6 +66,7 @@ export function useInPlaceEdit(options: UseInPlaceEditOptions): UseInPlaceEditRe saveEdit() } else if (e.key === 'Escape') { e.preventDefault() + e.stopPropagation() cancelEdit() } }, diff --git a/src/renderer/src/pages/home/Inputbar/Inputbar.tsx b/src/renderer/src/pages/home/Inputbar/Inputbar.tsx index c31d5579fa..bb16201a22 100644 --- a/src/renderer/src/pages/home/Inputbar/Inputbar.tsx +++ b/src/renderer/src/pages/home/Inputbar/Inputbar.tsx @@ -400,6 +400,7 @@ const Inputbar: FC = ({ assistant: _assistant, setActiveTopic, topic }) = if (expanded) { if (event.key === 'Escape') { + event.stopPropagation() return onToggleExpanded() } } diff --git a/src/renderer/src/pages/settings/ProviderSettings/index.tsx b/src/renderer/src/pages/settings/ProviderSettings/index.tsx index 98d8120557..5fdfaecd64 100644 --- a/src/renderer/src/pages/settings/ProviderSettings/index.tsx +++ b/src/renderer/src/pages/settings/ProviderSettings/index.tsx @@ -466,6 +466,7 @@ const ProvidersList: FC = () => { onChange={(e) => setSearchText(e.target.value)} onKeyDown={(e) => { if (e.key === 'Escape') { + e.stopPropagation() setSearchText('') } }}