From 86983dcd069bc88a83fbc2d3c422b9c4f5565337 Mon Sep 17 00:00:00 2001 From: Rishav Mishra <168016790+tokito-99@users.noreply.github.com> Date: Sun, 26 Jul 2026 11:11:24 -0400 Subject: [PATCH] fix: avoid Windows delay in voice settings --- surfaces/gui/src-tauri/Cargo.lock | 1 + surfaces/gui/src-tauri/Cargo.toml | 3 ++ surfaces/gui/src-tauri/src/lib.rs | 73 ++++++++++++++++++++++++------- 3 files changed, 62 insertions(+), 15 deletions(-) diff --git a/surfaces/gui/src-tauri/Cargo.lock b/surfaces/gui/src-tauri/Cargo.lock index e1d34864..27c42659 100644 --- a/surfaces/gui/src-tauri/Cargo.lock +++ b/surfaces/gui/src-tauri/Cargo.lock @@ -2684,6 +2684,7 @@ dependencies = [ "tauri-plugin-single-instance", "tauri-plugin-updater", "uuid", + "windows-version", ] [[package]] diff --git a/surfaces/gui/src-tauri/Cargo.toml b/surfaces/gui/src-tauri/Cargo.toml index e8e721ab..877baf81 100644 --- a/surfaces/gui/src-tauri/Cargo.toml +++ b/surfaces/gui/src-tauri/Cargo.toml @@ -23,3 +23,6 @@ serde_json = "1" uuid = { version = "1", features = ["v4"] } # Kept outside the Tauri shell so another product can depend on the same local STT engine. ocw-stt = { path = "../../../stt" } + +[target.'cfg(target_os = "windows")'.dependencies] +windows-version = "0.1" diff --git a/surfaces/gui/src-tauri/src/lib.rs b/surfaces/gui/src-tauri/src/lib.rs index 460021b4..cb755fd3 100644 --- a/surfaces/gui/src-tauri/src/lib.rs +++ b/surfaces/gui/src-tauri/src/lib.rs @@ -345,19 +345,22 @@ fn voice_input_compatibility() -> (bool, String, Option) { #[cfg(target_os = "windows")] fn voice_input_compatibility() -> (bool, String, Option) { - let version = Command::new("cmd") - .args(["/C", "ver"]) - .output() - .ok() - .map(|output| String::from_utf8_lossy(&output.stdout).trim().to_owned()) - .unwrap_or_else(|| "Windows (unknown version)".to_owned()); - let build = version - .split(|character: char| !character.is_ascii_digit() && character != '.') - .find(|part| part.matches('.').count() >= 2) - .and_then(|part| part.split('.').nth(2)) - .and_then(|part| part.parse::().ok()) - .unwrap_or(0); - let x64 = std::env::consts::ARCH == "x86_64"; + // Do not spawn `cmd /C ver` here. This function runs in the synchronous + // `get_dictation_status` Tauri command, and process startup can stall the Windows + // webview event loop for several seconds while the user navigates away from Voice Input. + windows_voice_input_compatibility( + windows_version::OsVersion::current(), + std::env::consts::ARCH, + ) +} + +#[cfg(target_os = "windows")] +fn windows_voice_input_compatibility( + version: windows_version::OsVersion, + architecture: &str, +) -> (bool, String, Option) { + let x64 = architecture == "x86_64"; + let build = version.build; let supported = x64 && build >= 19_045; let reason = if !x64 { Some("Voice Input currently requires a 64-bit x64 Windows PC.".to_owned()) @@ -366,7 +369,43 @@ fn voice_input_compatibility() -> (bool, String, Option) { } else { None }; - (supported, format!("{version} · x64"), reason) + let architecture = if x64 { "x64" } else { architecture }; + ( + supported, + format!( + "Windows {}.{}.{} · {architecture}", + version.major, version.minor, version.build + ), + reason, + ) +} + +#[cfg(all(test, target_os = "windows"))] +mod voice_input_compatibility_tests { + use super::windows_voice_input_compatibility; + use windows_version::OsVersion; + + #[test] + fn windows_10_22h2_x64_is_supported_without_spawning_a_process() { + let (supported, summary, reason) = + windows_voice_input_compatibility(OsVersion::new(10, 0, 0, 19_045), "x86_64"); + + assert!(supported); + assert_eq!(summary, "Windows 10.0.19045 · x64"); + assert_eq!(reason, None); + } + + #[test] + fn older_windows_builds_remain_unsupported() { + let (supported, _, reason) = + windows_voice_input_compatibility(OsVersion::new(10, 0, 0, 19_044), "x86_64"); + + assert!(!supported); + assert_eq!( + reason.as_deref(), + Some("Voice Input requires Windows 10 22H2 or Windows 11.") + ); + } } #[cfg(not(any(target_os = "macos", target_os = "windows")))] @@ -525,7 +564,11 @@ async fn download_update( // (Guard scope stays sync: a std MutexGuard must not live across an await.) { let slot = pending.0.lock().unwrap(); - if slot.as_ref().map(|(v, _)| v == &update.version).unwrap_or(false) { + if slot + .as_ref() + .map(|(v, _)| v == &update.version) + .unwrap_or(false) + { return Ok(()); } }