fix(windows): guard paste by restored target

This commit is contained in:
Cooper-X-Oak committed 2026-05-01 14:09:00 +08:00
1 parent 5650a9a1bc
commit 6232c491fd
3 files changed
+46 -10

No files matched your search

@@ -388,8 +388,8 @@ try {
if ([string]::IsNullOrWhiteSpace($latest.rawTranscript) -or [string]::IsNullOrWhiteSpace($latest.finalText)) {
throw "Latest history item is missing rawTranscript or finalText."
}
if (@("copiedFallback", "pasteSent") -notcontains $latest.insertStatus) {
throw "Expected Windows insertStatus copiedFallback or pasteSent, got '$($latest.insertStatus)'."
if ($latest.insertStatus -ne "pasteSent") {
throw "Expected Windows insertStatus pasteSent after guarded foreground restore, got '$($latest.insertStatus)'."
}
Focus-Window $inputTarget.Process | Out-Null
@@ -403,6 +403,9 @@ try {
if ([string]::IsNullOrWhiteSpace($targetText)) {
throw "$Target clipboard readback is empty after Ctrl+A/C."
}
if (-not $targetText.Contains($latest.finalText)) {
throw "$Target readback does not contain latest finalText; insertion was not proven at the target caret."
}
Write-Host "[ok] History updated. raw='$($latest.rawTranscript)'"
Write-Host "[ok] Final text length=$($latest.finalText.Length), insertStatus=$($latest.insertStatus)"
+28 -8
View File
@@ -943,9 +943,16 @@ async fn end_session(inner: &Arc<Inner>) -> Result<(), String> {
}
let focus_target = inner.state.lock().focus_target;
restore_focus_target_if_possible(focus_target);
let focus_ready_for_paste = restore_focus_target_if_possible(focus_target);
let restore_clipboard = inner.prefs.get().restore_clipboard_after_paste;
let status = inner.inserter.insert(&polished, restore_clipboard);
let status = if focus_ready_for_paste {
inner.inserter.insert(&polished, restore_clipboard)
} else {
log::warn!(
"[coord] original insertion target is not foreground; copied output without paste"
);
inner.inserter.copy_fallback(&polished)
};
let inserted_chars = polished.chars().count() as u32;
// 累计每条 enabled 词条在最终文本中的命中次数。
@@ -1561,7 +1568,7 @@ fn capture_frontmost_app() -> Option<String> {
}
#[cfg(target_os = "windows")]
fn restore_focus_target_if_possible(target: Option<usize>) {
fn restore_focus_target_if_possible(target: Option<usize>) -> bool {
use std::ffi::c_void;
use std::time::Duration;
use windows::Win32::Foundation::HWND;
@@ -1569,18 +1576,22 @@ fn restore_focus_target_if_possible(target: Option<usize>) {
GetForegroundWindow, IsIconic, IsWindow, SetForegroundWindow, ShowWindow, SW_RESTORE,
};
let Some(raw_target) = target else { return };
let Some(raw_target) = target else {
log::warn!("[coord] no original Windows insertion target captured");
return false;
};
let hwnd = HWND(raw_target as *mut c_void);
if hwnd.0.is_null() {
return;
return false;
}
if !unsafe { IsWindow(hwnd).as_bool() } {
return;
log::warn!("[coord] original Windows insertion target is no longer a valid window");
return false;
}
let foreground = unsafe { GetForegroundWindow() };
if foreground == hwnd {
return;
return true;
}
if unsafe { IsIconic(hwnd).as_bool() } {
@@ -1588,10 +1599,19 @@ fn restore_focus_target_if_possible(target: Option<usize>) {
}
let _ = unsafe { SetForegroundWindow(hwnd) };
std::thread::sleep(Duration::from_millis(60));
let foreground = unsafe { GetForegroundWindow() };
if foreground != hwnd {
log::warn!("[coord] failed to restore original Windows insertion target before paste");
return false;
}
true
}
#[cfg(not(target_os = "windows"))]
fn restore_focus_target_if_possible(_target: Option<usize>) {}
fn restore_focus_target_if_possible(_target: Option<usize>) -> bool {
true
}
#[cfg(target_os = "windows")]
fn show_capsule_window_no_activate() -> bool {
@@ -50,6 +50,19 @@ impl TextInserter {
}
insertion_success_status()
}
/// Copy text without attempting a synthetic paste. Used when the platform cannot
/// prove the original input target is active enough to safely receive Ctrl/Cmd+V.
pub fn copy_fallback(&self, text: &str) -> InsertStatus {
if text.is_empty() {
return InsertStatus::CopiedFallback;
}
if copy_to_clipboard(text) {
InsertStatus::CopiedFallback
} else {
InsertStatus::Failed
}
}
}
impl Default for TextInserter {