2e4a4b0a by shady

:bug: 修复输入框聚焦时 Cmd+V 粘贴图片失效:按剪贴板内容分流

根因:⌘V 在 QML 里有两条互斥路径。焦点不在输入框时走顶层
Shortcut{StandardKey.Paste} 粘贴图片;焦点在 promptArea 里时,
编辑控件通过 Qt 的 ShortcutOverride 吞掉 ⌘V 走内置文本粘贴,
那个全局 Shortcut 永远拿不到事件 —— 而剪贴板里是图片、文本粘贴
贴不出东西,表现为"粘贴无效"。:clipboard: 按钮直接调 pasteFromClipboardAction
绕开按键路由,所以一直有效。

修复(按剪贴板内容分流,而非靠焦点状态):
- bridges/imagegen.py 新增 clipboardHasImage():只读 formats()/urls(),
  无副作用、不写临时文件、macOS 不碰会崩的 imageData()。
- promptArea 加 Keys.onPressed:matches(StandardKey.Paste) 且剪贴板有图
  → 粘图 + event.accepted;否则放行给 TextArea 做文本粘贴。

文本粘贴行为不变(Never break userspace)。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent f2d92337
......@@ -172,6 +172,32 @@ class ImageGenBridge(QObject):
self._tqm.cancel_task(task_id)
self.busyChanged.emit()
@Slot(result=bool)
def clipboardHasImage(self) -> bool:
"""剪贴板里是否有图片 —— 轻量、无副作用、macOS 安全。
只读 mimeData.formats() / urls(),不做反序列化、不写临时文件,
所以即便在 macOS 上也不会触发 application/x-qt-image → NSImage 的
native crash(那个风险只在 imageData()/loadFromData 时出现,见
_extract_clipboard_image)。给焦点在输入框时的 Ctrl/Cmd+V 路由用:
有图就走图片粘贴,否则放行给文本粘贴。
"""
clipboard = QGuiApplication.clipboard()
if clipboard is None:
return False
mime_data = clipboard.mimeData()
if mime_data is None:
return False
# 路径 A:文件 URL 指向图片文件
if mime_data.hasUrls():
for url in mime_data.urls():
if url.isLocalFile() and Path(url.toLocalFile()).suffix.lower() in _PASTE_VALID_EXT:
return True
# 路径 B/C:剪贴板里挂着图像 MIME(仅列 formats,不读字节)
image_mimes = {"image/png", "image/jpeg", "image/bmp", "image/tiff",
"image/gif", "image/webp", "application/x-qt-image"}
return any(fmt in image_mimes for fmt in mime_data.formats())
@Slot(result="QVariantList")
def pasteFromClipboard(self) -> list:
"""从系统剪贴板拿图片,返回本地路径列表(正斜杠风格)。失败返回空列表。
......
......@@ -122,8 +122,9 @@ Item {
}
}
// 全局 Ctrl+V 粘贴图片(仅在图片生成 tab 激活时生效;
// 焦点在 TextArea/TextField 里 Ctrl+V 优先走文本粘贴,不会触发这个 Shortcut)
// 全局 Ctrl/Cmd+V 粘贴图片:覆盖焦点不在输入框的情况(按钮/下拉/空白处)。
// 焦点在 promptArea 里时编辑控件会吞掉 Ctrl/Cmd+V,这个 Shortcut 拿不到,
// 那种情况由 promptArea 的 Keys.onPressed 按剪贴板内容分流(见下方 TextArea)。
Shortcut {
sequences: [StandardKey.Paste]
enabled: appState.currentTab === 0
......@@ -635,6 +636,17 @@ Item {
wrapMode: TextArea.Wrap
selectionColor: App.Theme.accent
selectedTextColor: App.Theme.textOnAccent
// 焦点在输入框时,编辑控件会吞掉 Ctrl/Cmd+V 走内置文本粘贴,
// 顶层那个 StandardKey.Paste Shortcut 拿不到 = 粘贴图片失效。
// 这里按"剪贴板内容"分流:有图就粘图(吃掉事件),
// 没图就放行,让 TextArea 自己做文本粘贴。
Keys.onPressed: function(event) {
if (event.matches(StandardKey.Paste) && imageGen.clipboardHasImage()) {
tab.pasteFromClipboardAction()
event.accepted = true
}
}
background: Rectangle {
color: App.Theme.bgSubtle
radius: App.Theme.radiusMd
......