现象
Windows 上划词追问浮窗的多轮提问场景:
- 选段文字 → Cmd+Shift+; 弹浮窗(OK,选区被抓到)
- 按 Option 录音 → 说话 → 按 Option 提交 → LLM 答案出来(OK)
- 再按 Option 第二次提问 → 选区抓不到,LLM 收到的 "选区原文" 段是空的,或是 OpenLess 浮窗内容
macOS 不复现(macOS 走 `orderFrontRegardless` 不抢前台焦点)。Linux 受同样影响。
复现
- 在备忘录 / 浏览器选段 200 字
- Cmd+Shift+; → Option → 说"什么意思" → Option → 第一轮答案 OK
- 不动选区,按 Option 开始第二轮 → 说"用大白话" → Option
- 观察:LLM 答 "您没提供选中内容...",或者基于浮窗自身的 markdown 答的(可笑)
根因
lib.rs:517 的 `show_qa_window` 在 macOS 用 `orderFrontRegardless`(不抢 key window),但 Win/Linux 走的是普通 `window.show()`:
```rust
#[cfg(target_os = "macos")]
{
// ... orderFrontRegardless 不抢焦点
}
#[cfg(not(target_os = "macos"))]
if let Err(e) = window.show() {
log::warn!("[qa] show failed: {e}");
}
```
Windows 上 `window.show()` 调 `ShowWindow(SW_SHOW)`,OpenLess 浮窗成为前台。后续 `capture_selection` 在浮窗 Cmd+C fallback 路径上跑——拿到的是浮窗自己的 webview 内容(空 / 浮窗里能选中的字)。第一轮能拿到是因为浮窗刚 show 还在过渡(焦点切换有延迟),第二轮浮窗已稳定为前台 → 必然失败。
参考 `show_capsule_window_no_activate`(coordinator.rs:2415)的实现,用 `SetWindowPos` + `SWP_NOACTIVATE` 是 Windows 上"显示但不抢焦点"的标准手法。
影响
- 平台:Windows + Linux(Linux 也走 `window.show()` 分支)
- 频率:每次多轮提问的第二轮+ 必现
- 用户损失:划词追问 v2 在 Win/Linux 的多轮场景实质不可用
建议 fix
把 macOS 的 `orderFrontRegardless` 思路在 Windows 上对应到 `SetWindowPos + SWP_NOACTIVATE + HWND_TOPMOST`,跟 `show_capsule_window_no_activate` 一样:
```rust
#[cfg(target_os = "windows")]
fn show_qa_window_no_activate<R: Runtime>(window: &tauri::WebviewWindow) -> bool {
use raw_window_handle::{HasWindowHandle, RawWindowHandle};
use windows::Win32::Foundation::HWND;
use windows::Win32::UI::WindowsAndMessaging::{
SetWindowPos, HWND_TOPMOST, SWP_NOACTIVATE, SWP_SHOWWINDOW, SWP_NOMOVE, SWP_NOSIZE,
};
let Ok(handle) = window.window_handle() else { return false; };
let RawWindowHandle::Win32(h) = handle.as_raw() else { return false; };
let hwnd = HWND(h.hwnd.get() as *mut _);
unsafe {
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE).is_ok()
}
}
```
然后 `show_qa_window` 在 Windows 分支调它代替 `window.show()`。Linux 暂保 `window.show()`(没等价 X11 API),但在 Linux 平台契约 issue 里另议。
现象
Windows 上划词追问浮窗的多轮提问场景:
macOS 不复现(macOS 走 `orderFrontRegardless` 不抢前台焦点)。Linux 受同样影响。
复现
根因
lib.rs:517的 `show_qa_window` 在 macOS 用 `orderFrontRegardless`(不抢 key window),但 Win/Linux 走的是普通 `window.show()`:```rust
#[cfg(target_os = "macos")]
{
// ... orderFrontRegardless 不抢焦点
}
#[cfg(not(target_os = "macos"))]
if let Err(e) = window.show() {
log::warn!("[qa] show failed: {e}");
}
```
Windows 上 `window.show()` 调 `ShowWindow(SW_SHOW)`,OpenLess 浮窗成为前台。后续 `capture_selection` 在浮窗 Cmd+C fallback 路径上跑——拿到的是浮窗自己的 webview 内容(空 / 浮窗里能选中的字)。第一轮能拿到是因为浮窗刚 show 还在过渡(焦点切换有延迟),第二轮浮窗已稳定为前台 → 必然失败。
参考 `show_capsule_window_no_activate`(
coordinator.rs:2415)的实现,用 `SetWindowPos` + `SWP_NOACTIVATE` 是 Windows 上"显示但不抢焦点"的标准手法。影响
建议 fix
把 macOS 的 `orderFrontRegardless` 思路在 Windows 上对应到 `SetWindowPos + SWP_NOACTIVATE + HWND_TOPMOST`,跟 `show_capsule_window_no_activate` 一样:
```rust
#[cfg(target_os = "windows")]
fn show_qa_window_no_activate<R: Runtime>(window: &tauri::WebviewWindow) -> bool {
use raw_window_handle::{HasWindowHandle, RawWindowHandle};
use windows::Win32::Foundation::HWND;
use windows::Win32::UI::WindowsAndMessaging::{
SetWindowPos, HWND_TOPMOST, SWP_NOACTIVATE, SWP_SHOWWINDOW, SWP_NOMOVE, SWP_NOSIZE,
};
let Ok(handle) = window.window_handle() else { return false; };
let RawWindowHandle::Win32(h) = handle.as_raw() else { return false; };
let hwnd = HWND(h.hwnd.get() as *mut _);
unsafe {
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE).is_ok()
}
}
```
然后 `show_qa_window` 在 Windows 分支调它代替 `window.show()`。Linux 暂保 `window.show()`(没等价 X11 API),但在 Linux 平台契约 issue 里另议。