Commit Graph
1084 Commits
Author SHA1 Message Date
吕柏青andClaude Opus 4.8 8211dea3d7 feat(coding-agent): 拆分两功能 — 选中润色(快取用键)+ Cloud Agent(语音键,占位);热键移到通用设置
- 快取用键 = 选中文本润色:选中→Claude 润色→回插替换;全程胶囊反馈
  (没选中提示"请先选中文本";润色中/完成/出错都显示),纯文本 plan 只读、无 guard、便宜可靠。
- 面板键 = Cloud Agent(语音→ASR→Claude→结果弹窗),完整流程开发中,先给可见提示。
- 两个热键从「高级」移到「通用→快捷键」,停用按钮置于录制器左边、常驻行。
- CodingAgentSection 精简为开关/后端/模型/权限/工作目录 + 热键位置提示;5 语言 i18n。

cargo check + tsc + vite 均绿。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 09:21:35 +08:00
吕柏青andClaude Opus 4.8 0463c30282 feat(coding-agent): 接线快取用执行链路(热键 → 选中 → 无头 Claude → 回插)
- 新增 coding_agent_hotkey.rs:双绑定全局热键监听器(面板键 + 快取用键),
  镜像 qa_hotkey,3 单测。
- coordinator 接线:Inner 加 coding_agent_hotkey;新增 supervisor(仅
  coding_agent_enabled 时注册)+ bridge loop + handler;lib.rs 启动调用。
- handler:capture_selection → 护栏化 run_claude_agent(sonnet 默认、deny 清单、
  git 快照、成本封顶)→ TextInserter 回插光标。本版面板键暂同走快取用,
  语音 + 面板随后续版本。

cargo check 绿;coding_agent 全模块 22 单测通过。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 08:34:04 +08:00
吕柏青andClaude Opus 4.8 d8dc54695d feat(coding-agent): 语音 Agent 设置 UI(开关 + Claude/OpenCode 选择 + 双热键 + 模型/权限/工作目录)
- UserPreferences 新增 7 字段(coding_agent_*):启用开关、后端 provider、模型、
  权限模式、工作目录、面板热键、快取用热键;贯穿 struct/Wire/双向转换/默认。
- 前端 types.ts/ipc.ts 同步类型与 mock;CodingAgentPermissionMode 收敛到 types.ts 单一来源。
- 新增 CodingAgentSection(设置→高级):启用开关、Claude/OpenCode 选择、两个
  ShortcutRecorder(可启用/停用)、权限模式、模型、工作目录。
- i18n 全 5 语言新增 settings.codingAgent.*。

热键实时注册与触发执行链路(coordinator 接线)随后续提交。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 08:20:56 +08:00
吕柏青 d5756db8a6 Merge remote-tracking branch 'origin/beta' into feat/fast-agent 2026-06-05 08:08:50 +08:00
Chris233 0d94364e65 Merge pull request #591 from Open-Less/feat/issue-582-openrouter-asr
feat(asr): 支持 OpenRouter 作为 ASR 提供商 (#582)
2026-06-04 22:19:12 +08:00
Chris233 6c17ffe35c Merge pull request #590 from Open-Less/fix/issue-573-overview-credentials-refresh
fix(overview): 凭据保存后状态不刷新仍显示「未配置」 (#573)
2026-06-04 21:57:46 +08:00
Chris233 a86af40194 Merge pull request #593 from Open-Less/chore/issue-470-capsule-diagnostics-v2
chore(capsule): #470 诊断 v2 — 暗点一次性日志(零行为改动)
2026-06-04 21:56:39 +08:00
Chris233 984169d837 Merge pull request #592 from Open-Less/feat/issue-576-global-hotkey-disable
feat(hotkey): 全局快捷键可停用/清空开关 (#576)
2026-06-04 21:55:44 +08:00
吕柏青 83e4135175 chore(capsule): #470 诊断 v2 —— 给胶囊不显示的暗点补一次性日志(零行为改动)
#470「Windows 语音输入看不到录音胶囊」根因仍未定(PR #471 已明说只加诊断、需真机
日志;byte92 报 macOS 也复现,疑跨平台)。本 PR 不改任何 show/hide/position 行为,
仅在几个静默路径补日志,把根因收敛到 A/B/C 单一分支,帮助拿日志定位:

- coordinator.rs show_capsule_window_no_activate(Windows):两处 window_handle() /
  RawWindowHandle::Win32 取不到时此前静默 return false,补 warn(Win32 show 失败最可能的暗点)。
- coordinator.rs emit_capsule:get_webview_window("capsule") 取不到时此前静默 return,
  补一次性 warn(暗点 A0:窗口压根没创建/已销毁)。沿用 AtomicBool 一次性门,避免 ~30Hz 刷屏。
- lib.rs position_capsule_bottom_center(Windows):定位只夹了上边(.max(mon.top)),
  多显示器/负坐标/异常 DPI 下可能算到屏幕外却无观测,补显示器几何 + 最终落点 debug log。
- Capsule.tsx:webview 收到第一个 capsule:state 事件时打一次 console.info,区分
  「后端没 emit」与「emit 了但窗口没显示/没渲染」。

注:Windows-cfg 部分本机无法交叉编译验证(ring 的 C 代码需 MSVC),依赖 Windows CI。
2026-06-04 20:45:47 +08:00
吕柏青 d8ec007fcd feat(hotkey): 全局快捷键可停用/清空开关 (#576)
0602 版本默认注册的「切换风格 / 唤起 App」全局快捷键无法关闭,与其他软件冲突
且会拦截软件内快捷键。本 PR 复用 QA 快捷键已有的 `Option<ShortcutBinding>=None`
停用模式,给这两个 action 键加上「可清空停用」能力。

默认仍开启(Some 默认键),对老用户零行为变化,仅新增可关。

后端:
- types.rs: 内层 AppPrefs switch_style_hotkey/open_app_hotkey 改 Option;default fn
  返回 Some(默认键);Wire::default 改携带 Some(缺字段=启用);from-wire 去掉
  unwrap_or_else 直传 Option(None=停用不再被塌缩成默认键——这正是「无法关闭」的根因)。
- coordinator.rs: action_hotkey_binding 返回 Option;supervisor / update 加 None 反注册
  分支;reset-latch 对 Option 解包。
- commands.rs: set_switch_style_hotkey/set_open_app_hotkey 接受 Option(None=停用,跳过
  validate/overlap);所有 reject_*_overlap 读取处对 Option 解包(停用项不参与冲突检测)。

前端:
- types.ts/ipc.ts: switchStyleHotkey/openAppHotkey 与 setter 改 nullable。
- ShortcutsSection: 有值→录制器+「停用」按钮;停用→「启用」按钮恢复默认(仿 QA 行)。
- lib/hotkey.ts: defaultSwitchStyleShortcut/defaultOpenAppShortcut helper。
- 5 份 i18n 加 settings.shortcuts.enable/disable。

测试:默认启用、缺字段启用、None 往返为 null、显式绑定往返、overlap 拒绝(含停用项跳过)。
2026-06-04 20:38:40 +08:00
吕柏青 1d4a3adaad feat(asr): 支持 OpenRouter 作为 ASR 提供商 (#582)
OpenRouter 的 /audio/transcriptions 与 OpenAI 路径相同、也走 Bearer,但请求体是
application/json:{model, input_audio:{data:<base64 wav>, format:"wav"}},而非 OpenAI
官方的 multipart/form-data。直接当 whisper 兼容 provider 会被 OpenRouter 拒绝。

- whisper.rs: 新增 AsrRequestFormat{Multipart,OpenRouterJson},transcribe_chunk 按格式
  分发;OpenRouterJson 走 JSON+标准 base64(带 padding),不带 multipart 专属的
  prompt/response_format 字段。用 with_request_format builder 避免改 new() 签名(不动
  既有 4 处构造点)。
- coordinator.rs: is_whisper_compatible_provider 注册 openrouter;新增
  whisper_request_format;verbose_json 对 openrouter 保持关闭;base64 膨胀 ~33%,长
  录音按 30s 切分(同 zhipu)。
- 前端: ASR_PRESETS / AsrPresetId / Overview 名称映射 + 5 份 i18n 加 openrouter。
- 测试: OpenRouterJson 发 JSON body 单测 + 注册/格式断言;既有 transcribe 测试不变。

默认 model 用报告人已验证的 openai/whisper-large-v3-turbo。
新增直接依赖 base64=0.22(此前已是传递依赖,未引入新 crate)。
2026-06-04 20:19:40 +08:00
吕柏青 14c3874eb8 fix(overview): port 凭据保存后状态不刷新修复到 beta (#573)
issue #532/#573:在 Settings 填写/更新凭据但不切换提供商时,Overview 页
原有的 useEffect 不会重跑,asrConfigured 仍停留在「未配置」。

该修复曾随 #538 合入 main,但被 beta→main 合并覆盖,beta(开发主分支)上缺失,
导致用户(如 Ubuntu 24.04)配好火山引擎 ASR 后界面仍显示「未配置」。

- commands.rs: set_credential 保存/删除成功后 emit "credentials:changed"
- Overview.tsx: 监听该事件调用 refreshCredentials()(复用 credentialsRequestSeq 防竞态,
  比 #538 原版裸 getCredentials() 更稳)
2026-06-04 20:07:56 +08:00
吕柏青andClaude Opus 4.8 333ba3dd1c feat(coding-agent): 快速 Agent 引擎 + Claude 控制台(无头 Claude Code)
issue #579 骨架的首个垂直切片(UCW 版):只接 Claude Code、放行 + 护栏。

后端 coding_agent/ 模块(19 单测全绿,已对真实 claude v2.1.161 验证链路):
- args: claude -p 无头流式 argv 构造
- stream: stream-json 逐行解析为 CodingAgentEvent
- guard: 高风险命令分类 + acceptEdits + deny 清单护栏 settings
- detect: 解析 claude --version / mcp list(computer use 检测口径)
- mod: tokio 异步运行器(超时 / 取消 / stderr 排空)+ git stash create 快照
- commands: detect / run_test(护栏流式)/ cancel / command_risk,注册入 lib.rs

前端 Claude 控制台(设置 → 高级):
- 检测面板 + 终端观感流式输出 + 用量;权限模式 / 工作目录 / 可执行路径
- ipc 封装 + 类型 + 5 语言 i18n;控制台测试默认 sonnet 控成本

未含(后续阶段):语音双热键 + coordinator 接线 + 面板 + prefs 持久化。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 19:52:43 +08:00
TRIP 30cf33e2b1 Merge pull request #589 from Open-Less/docs/readme-real-example
docs(readme): 实际效果示例换成客户回邮件用例(中英双语)
2026-06-04 19:33:36 +08:00
吕柏青 5cf015de17 docs(readme): 实际效果示例换成客户回邮件用例(中英双语)
把「一个实际例子 / A concrete example」从未充分测试的 SQL→ChatGPT 演示
换成经过测试的客户回邮件用例:口语输入 → 结构化清理稿,更贴合
OpenLess「只清理你的话、不替你作答」的定位,宣传与实际相符。
收束句由「回车发送」改为「粘贴给 ChatGPT/Claude 续写」,标语保持不变。
2026-06-04 19:31:15 +08:00
TRIP 2067367d83 Merge pull request #588 from ig505gi/fix-beta-reset
fix(macos): Beta 更新重启前重置 TCC 权限记录
2026-06-04 19:29:46 +08:00
TRIP 61f5416c73 Merge pull request #587 from Open-Less/docs/discord-community-link
docs(readme): 顶部加入 Discord 社区入口
2026-06-04 19:00:47 +08:00
Ian Gao f482ac21ee fix(macos): Beta 更新重启前重置 TCC 权限记录 2026-06-04 16:04:54 +08:00
吕柏青 ace7fe47ab docs(readme): 顶部加入 Discord 社区入口(badge + 社区行,中英双语) 2026-06-04 13:20:32 +08:00
吕柏青 bd435b9e5e chore(release): bump version to 1.3.6-2 (Beta) — 翻译会话参与对话感知润色(#583) + 快速录音提示音丢失修复(#584) + 正式发版自动更新 Homebrew cask(#586) 2026-06-04 13:17:17 +08:00
TRIP 7cc8175d98 Merge pull request #586 from Open-Less/ci/auto-update-homebrew-cask
ci(release): 正式发版自动更新 Homebrew cask(+ 补 cask 到 1.3.5)
2026-06-04 13:08:27 +08:00
TRIP 13a0a03ab3 Merge pull request #584 from Open-Less/fix/audio-cue-missing
fix(audioCue): 修复快速录音时录音提示音偶尔丢失
2026-06-04 13:08:19 +08:00
TRIP 85d6ed851f Merge pull request #583 from Open-Less/fix/polish-context-isolation
fix(polish): 对话感知上下文——按风格包隔离 + 翻译会话参与润色(不串味)
2026-06-04 13:08:09 +08:00
吕柏青 4c31448cb9 test(polish): 补 Case 4 单测——普通历史在翻译轮喂 final_text (@claude review) 2026-06-04 12:59:08 +08:00
吕柏青 18ffbb0e48 fix(ci): cask intel sed 锚定 sha256 行,避免误改 arch 指令 (@claude review)
裸 s/intel: "..."/ 会同时命中 cask 第2行 arch arm: "aarch64", intel: "x64",把 arch 的 intel 改成哈希 → Intel Mac 用户 brew 安装 404。改用 ^[[:space:]]*intel: 锚定 sha256 块行(捕获组保留缩进),并加防呆:arch 指令被破坏或 sha256 没写进去就让 job 失败。本地模拟新旧 sed 对比已验证。
2026-06-04 12:57:31 +08:00
吕柏青 6b28d42ea1 chore(cask): openless 补到当前正式版 1.3.5
cask 此前停在 1.3.4(自动更新一直没生效),Homebrew 用户拿不到 1.3.5。用 v1.3.5-tauri release 资产 sha256 一次性补齐。
2026-06-04 11:50:32 +08:00
吕柏青 0d35c811fe ci(release): 正式发版后在流水线内自动更新 Homebrew cask
原 update-cask.yml 监听 release: published,但 Release 由 release-tauri.yml 用默认 GITHUB_TOKEN 创建,不会触发该事件(GitHub 防递归)——所以 cask 从不自动更新,需手动;且其条件 endsWith('-tauri') 连 beta 也匹配。

改为在 release-tauri.yml 内新增 needs:build 的 update-homebrew-cask job:仅正式版 tag(v*-tauri 且非 -beta-tauri),构建+建 Release 后下载 DMG 算 sha256、sed 更新 Casks/openless.rb、提交回默认分支([skip ci])。删除失效且会错配 beta 的 update-cask.yml。
2026-06-04 11:50:32 +08:00
吕柏青 bff4bd727f feat(polish): 翻译会话参与对话感知润色(润色+翻译单次调用 + 按轮剔除译文)
接续上一条「按风格包隔离」,把「翻译会话直接排除出上下文」改成「保留但按需剔除」:翻译会话也参与对话连续性,又不让外语译文污染普通润色。

- 翻译改为单次 LLM 调用同时润色源文 + 翻译:polish_and_translate_or_passthrough 用合成系统提示词(翻译规则 + 追加输出润色后源文 + 两段哨兵)走现成 polish() 通道,复用对话上下文;解析失败 / 译文为空则退回专用 translate_text 拿干净译文(不丢字)。
- DictationSession 加 polish_source(serde default 兼容旧历史),存润色后的源语言文本。
- eligible_polish_context_turns 加 current_translation_active 分流:翻译历史在普通轮喂 polish_source(无则跳过=剔除译文),翻译轮喂 final_text;普通历史始终喂 final_text。
- 前后端类型同步(polishSource);补解析器 + 上下文分流单测,cargo test --lib 371 全过。
2026-06-04 11:36:35 +08:00
吕柏青 52e2e45bb2 fix(audioCue): 修复快速录音时提示音偶尔丢失
suspended 的 AudioContext 播放前需异步 resume。原实现用单个 playGeneration:快速点一下录音时 resume 还没完成、录音已结束(stopAudioCue 自增代号),挂起的播放被作废 → 提示音「有时没有」。

A 治本:新增 primeAudioCue(),胶囊挂载时预热 resume,让常见路径同步播放、绕开竞态。
B 兜底:拆 playSeq(新播放接管)/ stopSeq(发生过 stop)双序号 + 400ms 迟到阈值,抽出纯函数 shouldPlayDeferredCue 决策——被新播放接管→不播;停了且真迟到→不播;停了但 resume 很快(快速录音)→仍补响一声。

补 shouldPlayDeferredCue 单测(含边界);tsc --noEmit 通过。
2026-06-04 09:23:15 +08:00
吕柏青 8bc1583c98 fix(polish): 对话感知上下文按风格包隔离 + 排除翻译会话
对话感知 polish 回看最近历史作为 LLM 上下文时,之前复用所有成功会话,导致两类串味:

1. 切换风格包后,旧风格包的历史仍被带进新提示词,把当前风格带偏;
2. 翻译会话的译文/指令污染下一段普通润色(如中文输入被带成英文)。

给 DictationSession 增加 style_pack_id / translation_active 两字段(serde default 向后兼容旧历史),抽出 eligible_polish_context_turns 过滤:仅复用同一 active 风格包、且非翻译的成功会话;旧历史无 style_pack_id 时保守排除。前后端类型同步,补两条单测。
2026-06-04 09:12:33 +08:00
jmr 898c6911c6 Update fmt.Println message from 'Hello' to 'Goodbye' 2026-06-03 22:28:57 +08:00
jmr b0fe9ccb52 Revise README for improved clarity and structure
Updated README.md to enhance clarity and formatting.
2026-06-03 22:20:54 +08:00
Chris233 63d3e16757 Merge pull request #577 from aeoform/chore/suppress-linux-build-warnings
chore: suppress all Linux build warnings (192 → 0)
2026-06-03 21:53:23 +08:00
aeoformandClaude Opus 4.7 8d386815f2 fix(ci): restore macOS/Windows imports removed by cargo fix
Restore std::path::Path, std::sync::Arc, parking_lot::Mutex, anyhow::Result,
std::time::{Duration, Instant} imports in cache.rs, PhysicalPosition/PhysicalSize
in lib.rs, and std::time::Duration in selection.rs. These were removed by
cargo fix --broken-code because they appear unused on Linux but are needed
on macOS and Windows.

Add unused_imports to cfg_attr allow lists so future cargo fix runs on
Linux won't strip cross-platform imports again.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 23:29:41 +08:00
aeoformandClaude Opus 4.7 b4d0f1e36e fix(ci): restore variables broken by cargo fix --broken-code
Restore handle_pressed/handle_released imports and window/show_capsule/
visible/audio_timeout/duration_ms variable names that cargo fix renamed
with _ prefix. These are used on macOS/Windows but the _ prefix broke
the builds. Add platform-gated import for model_dir in test_run.rs.

Expand cfg_attr allow lists to cover unused_imports and unused_variables
where needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 23:19:07 +08:00
aeoformandClaude Opus 4.7 72b53520f2 chore: suppress all Linux build warnings (192 → 0)
Add #[cfg_attr(target_os = "linux", allow(dead_code, unused_variables))]
to 20+ source files where Linux builds see platform-specific dead code
(Windows IME, macOS permissions, Sherpa ASR, clipboard restore, etc.).
Also manually fix 3 real warnings: unused imports in coordinator.rs,
unreachable expression in insertion.rs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 23:01:31 +08:00
吕柏青 08ad6b7979 docs(readme): 突出风格市场 + 流式输出,状态更新到 v1.3.6 2026-06-01 18:00:22 +08:00
Chris233 ad629367d7 Merge pull request #572 from katanumahotori/fix/whisper-hallucination-verbose-json
fix(asr): 用 verbose_json 元数据丢弃 Whisper 幻听段落(仅 OpenAI/Groq)
2026-06-01 16:52:41 +08:00
吕柏青 d1a5b75c2b chore(release): bump version to 1.3.6-1 (Beta) — MediaPlayPause 线控录音 + Toggle 冷却(#545) + 多屏胶囊跟随(#569) + 本地模型管理(#559) + Linux 磨砂回退(#553) 2026-06-01 15:08:50 +08:00
片沼ほとりandClaude Opus 4.8 48713ed6d5 fix(asr): drop Whisper hallucination segments via verbose_json (OpenAI/Groq only)
Whisper fabricates plausible-but-unspoken text on silence/noise (the
classic hallucination defect): leading/trailing silence or mic hiss turns
into unrelated words. When the provider returns verbose_json, each segment
carries no_speech_prob / avg_logprob / compression_ratio — use them to
drop segments that clearly aren't speech (conservative thresholds so real
speech is never trimmed). No segments in the response → fall back to text.

Provider-gated to avoid breaking non-Whisper backends:
- whisper (OpenAI) / groq: native Whisper, verbose_json fully supported
  with the metrics above — filter is effective. Verified against both
  providers' current docs.
- siliconflow: SenseVoice / TeleSpeech, response_format is undocumented;
  sending verbose_json risks a 4xx, so it stays on the existing json path.
- zhipu (GLM-ASR): accepts verbose_json but does not emit those metrics
  (filter would be a no-op), so it also stays on json to minimize behavior
  change. Only whisper/groq opt in.

whisper_supports_verbose_json(provider_id) decides the flag; WhisperBatchASR
gains a verbose_json bool. Missing metric fields are treated as "keep" so
the filter is harmless for any provider that returns segments without them.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 14:21:54 +09:00
Chris233 137c175ccb Merge pull request #569 from katanumahotori/fix/capsule-follow-input-monitor
fix(windows): 多显示器下胶囊跟随正在输入的屏幕
2026-06-01 12:42:26 +08:00
Chris233 c87bab4dc3 Merge pull request #571 from H-Chris233/fix/545-toggle-cooldown
fix: add 600ms activation cooldown after end_session for Toggle mode (#545)
2026-06-01 12:27:46 +08:00
H-Chris233 1788da4667 fix: add 600ms activation cooldown after end_session for Toggle mode (#545)
在 coordinator 层增加 timer-based busy gate:end_session / cancel_session
将 phase 设为 Idle 时记录冷却时间戳;handle_pressed 的 (Toggle, Idle)
分支在 begin_session 前检查该冷却,未过期则忽略本次按键。

冷却时长 600ms(覆盖胶囊 EXIT_ANIM_MS 360ms + 余量),既拦截
三连按的第 3 次误触,也不影响用户主动重新激活。

- coordinator.rs: 新增 POST_SESSION_COOLDOWN_MS 常量 + Inner 字段
- dictation.rs: handle_pressed 增加冷却检查
- dictation.rs: end_session / cancel_session 成功收尾时设置冷却
2026-06-01 12:08:55 +08:00
Chris233 9b05ed0c71 Merge pull request #570 from H-Chris233/fix/linux-frosted-glass-553
fix(linux): fallback from backdrop-filter when WEBKIT_DISABLE_COMPOSITING_MODE=1
2026-06-01 10:36:46 +08:00
H-Chris233 c45b6c0179 fix(linux): fallback from backdrop-filter when WEBKIT_DISABLE_COMPOSITING_MODE=1
Issue #553: Linux 上 WEBKIT_DISABLE_COMPOSITING_MODE=1 时 WebKitGTK backdrop-filter
在 DOM 重排后失效(hover 历史词汇表 / 选择条目刷新面板)。

方案:
- Rust 端新增 is_no_compositing_mode command 暴露环境变量状态
- App.tsx 初始化时调用,写入 data-ol-no-compositing 到 <html>
- CSS 用 [data-ol-no-compositing] 选择器覆盖 inline style,切换到
  渐变+噪点纹理假磨砂方案(复用 tokens.css --ol-frost-grain)
- WindowChrome/FloatingShell 加 className 钩子

受影响的三处 backdrop-filter:WindowChrome 底板、主面板、
Linux 标题栏。ProviderPrompt/HotkeyModePrompt 弹窗遮罩
(瞬态 UI)跳过。提交签署:Reasonix Code
2026-06-01 09:35:07 +08:00
片沼ほとりandClaude Opus 4.8 2c47ef65b8 fix(windows): 多显示器下胶囊跟随「正在输入的屏幕」
问题:多显示器环境下,无论在哪块屏输入,录音胶囊总是固定出现在主屏
(或胶囊窗口自己所在那块屏)。在 A 屏取消后到 B 屏输入,胶囊仍停在 A 屏。

根因:`position_capsule_bottom_center` 用 `window.current_monitor()` 决定
位置,拿到的是胶囊窗口自身所在显示器,而非用户正在输入的显示器。并且
`maybe_position_capsule_bottom_center` 的去重缓存 key 也基于同一个
current_monitor,于是「输入焦点已切到另一块屏、但胶囊还在原屏」会被误判为
「没变化」→ 跳过重新定位,胶囊被钉死在原屏。

修复:
- 新增 `foreground_window_monitor()`(Win32 GetForegroundWindow →
  MonitorFromWindow → GetMonitorInfoW + GetDpiForMonitor),定位「正在输入的
  App」所在显示器;`position_capsule_bottom_center` 在 Windows 上优先按它
  (physical px + 该屏 DPI)摆放,取不到时回退 current_monitor。
- `capsule_layout_snapshot()` 让去重缓存 key 与实际定位用的显示器一致,
  消除「输入切屏但不重定位」的误判。
- Cargo.toml 增加 `Win32_UI_HiDpi` feature(GetDpiForMonitor 所需)。

仅 Windows 路径改动;macOS / Linux 行为不变(仍走 current_monitor)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 09:56:54 +09:00
Chris233 4d2a35d2d3 Merge pull request #568 from H-Chris233/feat/media-play-pause-trigger
feat: 新增 MediaPlayPause HotkeyTrigger 支持有线耳机线控录音 (#477)
2026-06-01 08:39:32 +08:00
H-Chris233 dc846f60e6 feat: 新增 MediaPlayPause HotkeyTrigger 支持有线耳机线控录音
- 枚举新增 MediaPlayPause 变体,与 RightControl 等并列
- Windows WH_KEYBOARD_LL 钩子捕获 VK_MEDIA_PLAY_PAUSE (0xB3)
- macOS/Linux 标记为 unreachable (Windows-only)
- 前端类型、i18n 翻译支持
- 配置迁移保护:Linux fcitx 函数添加 MediaPlayPause 守卫

Closes #477
2026-05-31 23:14:48 +08:00
Chris233 854d0aacd1 Merge pull request #566 from H-Chris233/fix/issue-562-qa-active-asr
fix(qa): use active ASR provider in floating panel
2026-05-31 21:34:22 +08:00
Chris233 0b615a9a3e 更新 pr-agent.yml 2026-05-31 21:32:21 +08:00