Skip to content

fix(insertion): macOS 让「恢复剪贴板」开关真正生效,修复被回退的 #525#683

Open
appergb wants to merge 1 commit into
betafrom
fix/issue-525-macos-clipboard-restore-toggle
Open

fix(insertion): macOS 让「恢复剪贴板」开关真正生效,修复被回退的 #525#683
appergb wants to merge 1 commit into
betafrom
fix/issue-525-macos-clipboard-restore-toggle

Conversation

@appergb

@appergb appergb commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

User description

关联 issue

Closes #525(修复其在 macOS 上的回退)

问题

#525 的 macOS 剪贴板恢复(commit 4b4d219)被 Android 移植 commit 1ea467a 连同 cfg 门控一起回退:

  • 整套剪贴板恢复机制被重新 #[cfg(not(any(macos, android, ios)))] 排除出 macOS;
  • macOS insert() 退回「只写剪贴板 + Cmd+V」,参数 restore_clipboard_after_paste(即设置里的开关)被忽略。

结果:设置里的「恢复剪贴板」开关在 macOS 上完全无效——无论开还是关,听写/插入后剪贴板都被留成转写文字,覆盖用户手动复制的内容。(Windows/Linux 不受影响。)

改动(单一职责)

  • 共享的剪贴板恢复机制(ClipboardRestorePlan / PendingClipboardRestore / copy_to_clipboard_with_restore_plan / schedule_clipboard_restore / remember_pending_clipboard_restore / restore_clipboard_after_delay / is_latest_clipboard_restore / clear_pending_clipboard_restore / should_restore_clipboard / CLIPBOARD_RESTORE_DELAY + 相关 imports)的 cfg 从 not(any(macos,android,ios)) 放宽为 not(any(android,ios))重新纳入 macOS(移动端仍排除)。
  • macOS insert() 改为:保存原剪贴板 → 写转写文字 → Cmd+V → 仅当开关开启且粘贴成功时延迟恢复;粘贴失败保留文字供手动粘贴。开 = 恢复,关 = 保持现状。
  • 删除随之失效的 macos_insert_status_after_paste

未改动的 Windows/Linux 专用项(insert_with_clipboard_restore / paste_keys / simulate_paste(shortcut) 及其 insertion_success_status 变体)保持 macOS 排除——它们依赖 enigo / PasteShortcut,macOS 走固定 Cmd+V。

测试

cargo test --lib insertion   # 7 passed
  macos_paste_success_reports_inserted_and_guards_restore ... ok   (新增)
  restore_only_when_clipboard_still_holds_inserted_text ... ok      (现在 macOS 也跑)
  pending_clipboard_restore_keeps_first_original_until_latest_restore ... ok
  clipboard_restore_skips_when_clipboard_no_longer_matches_inserted_text ... ok

macOS 下 lib 干净编译(无重复定义/缺符号);restore_clipboard_after_paste 不再是 unused 警告。

需真机验证

macOS 出测试版号 dmg,验证「恢复剪贴板」开关两态:开 → 听写后剪贴板恢复为原内容;关 → 保持转写文字。

来源:2026-06-16 全仓多 Agent 审计,经 git 溯源确认回退提交为 1ea467a


PR Type

Bug fix


Description

  • Restore macOS clipboard restore toggle functionality (regression from 建议:插入语音转写文字后恢复用户剪贴板 #525)

  • Re-enable shared clipboard restore mechanism for macOS (relaxed cfg gates)

  • Modify macOS insert() to save original clipboard and conditionally restore based on toggle

  • Remove obsolete macos_insert_status_after_paste function


Diagram Walkthrough

flowchart LR
  A["Save original clipboard"] --> B["Write transcribed text"]
  B --> C["Cmd+V paste"]
  C --> D{"Restore toggle ON\?"}
  D -- Yes --> E["Schedule delayed restore"]
  D -- No --> F["Keep transcribed text"]
  E --> G["Restore original after delay"]
Loading

File Walkthrough

Relevant files
Bug fix
insertion.rs
Fix macOS clipboard restore toggle in insertion                   

openless-all/app/src-tauri/src/insertion.rs

  • Relaxed cfg from not(any(macos, android, ios)) to not(any(android,
    ios)) for clipboard restore mechanism
  • Rewrote macOS insert() to save original clipboard and conditionally
    restore after paste
  • Removed macos_insert_status_after_paste helper function
  • Updated test for macOS to verify restore guard logic
+52/-44 

#525 的 macOS 剪贴板恢复(commit 4b4d219)被 Android 移植 commit 1ea467a
连同 cfg 门控一起回退:整套恢复机制被重新 #[cfg] 排除出 macOS,macOS insert()
退回「只写剪贴板 + Cmd+V」,于是设置里的「恢复剪贴板」开关在 macOS 上完全无效
——无论开关开还是关,剪贴板都被留成转写文字。

- 把共享的剪贴板恢复机制(ClipboardRestorePlan / schedule_clipboard_restore /
  restore_clipboard_after_delay / should_restore_clipboard 等)的 cfg 从
  not(any(macos,android,ios)) 放宽为 not(any(android,ios)),重新纳入 macOS
  (移动端仍排除;Windows/Linux 不变)。
- macOS insert() 改为:保存原剪贴板 → 写转写文字 → Cmd+V → 仅当「恢复剪贴板」
  开关开启且粘贴成功时按 CLIPBOARD_RESTORE_DELAY 延迟恢复;粘贴失败则保留转写
  文字供手动粘贴、不恢复。开 = 恢复,关 = 保持现状,开关说了算。
- 删除随之失效的 macos_insert_status_after_paste;恢复相关单测在 macOS 也运行。

Windows/Linux 专用项(insert_with_clipboard_restore / paste_keys /
simulate_paste(shortcut) / 其 insertion_success_status 变体)的 macOS 排除保持不变。
@appergb

appergb commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator Author

@claude 请审核:让 macOS 的「恢复剪贴板」开关真正生效(#5251ea467a 回退后修复)。重点看 (1) 把恢复机制 cfg 从 not(any(macos,android,ios)) 放宽到 not(any(android,ios)) 是否准确——macOS/Windows/Linux 启用、Android/iOS 排除,没有把 enigo/PasteShortcut 相关 winlinux 专用项误带进 macOS(应无重复定义);(2) macOS insert 的开=恢复/关=保持/粘贴失败=保留 三态逻辑;(3) schedule_clipboard_restore 用 std::thread + arboard 在 macOS 是否妥当。

@claude

claude Bot commented Jun 16, 2026

Copy link
Copy Markdown

Claude finished @appergb's task in 2m 46s —— View job


审核结果

  • 读取变更文件(insertion.rs)
  • 分析 cfg 门控正确性
  • 分析 macOS insert 三态逻辑
  • 分析 std::thread + arboard 在 macOS 的适当性
  • 输出审核结论

1. cfg 门控正确性 ✅

放宽范围的函数/类型(全部改为 not(any(android, ios)),macOS 重新纳入):

符号 类型
AtomicU64/Ordering import use
Duration import use
once_cell::sync::Lazy import use
parking_lot::Mutex import use
CLIPBOARD_RESTORE_DELAY const
ClipboardRestorePlan struct
PendingClipboardRestore struct
NEXT_CLIPBOARD_RESTORE_ID static
PENDING_CLIPBOARD_RESTORE static
copy_to_clipboard_with_restore_plan fn
schedule_clipboard_restore fn
remember_pending_clipboard_restore fn
restore_clipboard_after_delay fn
is_latest_clipboard_restore fn
clear_pending_clipboard_restore fn
should_restore_clipboard fn

保持 not(any(macos, android, ios)) 排除 macOS 的项(enigo/PasteShortcut 相关):

符号 行号 说明
insert_with_clipboard_restore 262 仍为 not(any(macos,android,ios))
paste_keys 398 同上 ✓
simulate_paste(shortcut) 408 同上 ✓(与 macOS 的无参版本 simulate_paste() 签名不同,无冲突)
insert_via_clipboard_fallback 63 同上 ✓

结论:cfg 放宽精准,共享基础设施对 macOS 开放,enigo/PasteShortcut 专属逻辑保持排除,macOS 编译无重复定义,符合改动目标。


2. macOS insert 三态逻辑 ✅

// 开关开 (restore_clipboard_after_paste = true)
copy_to_clipboard_with_restore_plan(text)   // 保存原剪贴板 + 写转写文字
→ simulate_paste() 成功
→ schedule_clipboard_restore(restore_plan)   // 750ms 后恢复InsertStatus::Inserted

// 开关关 (restore_clipboard_after_paste = false)
copy_to_clipboard_with_restore_plan(text)simulate_paste() 成功
→ schedule_clipboard_restore 不调用           // 转写文字留在剪贴板InsertStatus::Inserted

// 粘贴失败
copy_to_clipboard_with_restore_plan(text)simulate_paste() 返回 Err
→ 不恢复(转写文字留剪贴板供手动粘贴)
→ InsertStatus::CopiedFallback

三态逻辑正确。should_restore_clipboard 在恢复前再次检查剪贴板内容是否仍为转写文字,若用户在 750ms 内手动复制了其他内容则跳过恢复——这个「双重保险」完好保留。

一处轻微效率问题(非阻塞):当 restore_clipboard_after_paste=false 时,copy_to_clipboard_with_restore_plan 仍会执行 clipboard.get_text() 读取原剪贴板,读到的值随后被丢弃。可通过下面方式优化,但会引入分支复杂度,权衡之后保持现状也完全可接受:

// 可选优化(非必须)
if restore_clipboard_after_paste {
    let plan = copy_to_clipboard_with_restore_plan(text)?;
    // ...
    schedule_clipboard_restore(plan);
} else {
    copy_to_clipboard(text);   // 不读原剪贴板
}

Fix this →


3. std::thread + arboard 在 macOS 是否妥当 ⚠️ 建议真机验证

schedule_clipboard_restore(line 287)在后台线程调用 arboard:

std::thread::spawn(move || {
    restore_clipboard_after_delay(plan, original_text, restore_id, CLIPBOARD_RESTORE_DELAY)
});

后台线程内 restore_clipboard_after_delay 会:

  1. std::thread::sleep(750ms)
  2. arboard::Clipboard::new() — macOS 实现使用 NSPasteboard
  3. clipboard.get_text() + clipboard.set_text()

分析

方面 评估
NSPasteboard 线程安全性 Apple 文档明确 NSPasteboard 可从任意线程访问,无需主线程 ✅
Autorelease Pool arboard 在 macOS 实现内部自行管理 @autoreleasepool,后台线程无需额外处理 ✅
JoinHandle 丢弃 spawn 返回的 handle 被丢弃 = detach,750ms 后台恢复正常完成,不会被提前终止 ✅
竞态防护 NEXT_CLIPBOARD_RESTORE_ID(SeqCst AtomicU64)+ PENDING_CLIPBOARD_RESTORE(parking_lot::Mutex)确保多次快速听写时只有最新一次恢复执行 ✅
沙盒限制 此应用依赖辅助功能权限,非 App Store 沙盒限制环境,跨线程剪贴板访问无额外限制 ✅

主要风险:arboard 在 macOS 后台线程调用的行为在极端条件下(如系统剪贴板被第三方剪贴板管理器大量监听时)可能有细微延迟差异。PR 描述中"需真机验证"是正确判断——建议在「恢复剪贴板」开关两态下各测试 ≥10 次,覆盖快速连续听写场景


测试覆盖评估

测试 cfg 说明
macos_paste_success_reports_inserted_and_guards_restore(新增) macOS 测试 insertion_success_status()should_restore_clipboard()——单元层面正确;因 CGEvent 需系统权限,insert() 集成路径需真机验证
restore_only_when_clipboard_still_holds_inserted_text 现在 macOS 也跑
pending_clipboard_restore_keeps_first_original_until_latest_restore 现在 macOS 也跑
clipboard_restore_skips_when_clipboard_no_longer_matches_inserted_text 现在 macOS 也跑

总结

可合并,无阻塞性问题。三处需关注:

  1. 可选优化(关闭状态下的多余剪贴板读取)——不影响正确性,可后续迭代
  2. 真机验证(arboard 后台线程在 macOS 的实际行为)——PR 描述中已有说明,合并前请完成
  3. 测试覆盖——insert() 端到端开关行为依赖真机测试,单元测试覆盖了核心辅助函数

cfg 边界清晰、三态逻辑正确、删除失效的 macos_insert_status_after_paste 属于正确清理。

@github-actions

Copy link
Copy Markdown
Contributor

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

🎫 Ticket compliance analysis ✅

525 - Fully compliant

Compliant requirements:

  • 在插入转写文字(完成粘贴操作)后,将用户此前复制的内容再次复制到系统剪贴板中,恢复用户的剪贴板状态(当开关开启且粘贴成功时)。
  • 在执行语音转写插入前,主动保存当前系统剪贴板内容(通过 copy_to_clipboard_with_restore_plan)。
  • 完成转写文字的粘贴后,将保存的内容写回系统剪贴板(通过 schedule_clipboard_restore)。
  • 设置中的「恢复剪贴板」开关在 macOS 上生效:打开则恢复,关闭则保持现状。
⏱️ Estimated effort to review: 1 🔵⚪⚪⚪⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ No major issues detected

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

建议:插入语音转写文字后恢复用户剪贴板

1 participant