diff --git a/Cargo.toml b/Cargo.toml index 0a5cd01..984dd6a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,4 +47,6 @@ windows = { version = "0.52.0", features = [ "Win32_Foundation", "Win32_Media_Audio", "Win32_Media_Audio_Endpoints", + "Win32_System_Console", + "Win32_UI_WindowsAndMessaging", ] } diff --git a/src/main.rs b/src/main.rs index b670346..23ee175 100644 --- a/src/main.rs +++ b/src/main.rs @@ -54,6 +54,8 @@ use timers::AudibleTimers; mod options; #[cfg(target_os = "windows")] mod windows_volume; +#[cfg(target_os = "windows")] +mod windows_focus; use tracing::{debug, error, info, instrument, warn}; use tracing_appender::rolling::{RollingFileAppender, Rotation}; @@ -611,6 +613,18 @@ fn call_fn( Some(format!("Current voice is {}", name)) } + "focus_terminal" => { + #[cfg(target_os = "windows")] + { + windows_focus::bring_terminal_to_front(); + None + } + #[cfg(not(target_os = "windows"))] + { + Some("focus_terminal is only supported on Windows".to_string()) + } + } + "list_output_devices" => { let default = get_default_output_device().unwrap_or_else(|| "Unknown".to_string()); let mut devices = list_audio_output_devices(); @@ -1576,6 +1590,16 @@ async fn main() -> Result<(), Box> { })) .build().unwrap(), + ChatCompletionFunctionsArgs::default() + .name("focus_terminal") + .description("Brings the console window to the foreground on Windows.") + .parameters(json!({ + "type": "object", + "properties": {}, + "required": [], + })) + .build().unwrap(), + ChatCompletionFunctionsArgs::default() .name("get_location") .description("Returns an approximate location based on the machine's IP address.") diff --git a/src/windows_focus.rs b/src/windows_focus.rs new file mode 100644 index 0000000..655a9ea --- /dev/null +++ b/src/windows_focus.rs @@ -0,0 +1,43 @@ +#[cfg(target_os = "windows")] +use windows::Win32::Foundation::HWND; +#[cfg(target_os = "windows")] +use windows::Win32::System::Console::GetConsoleWindow; +#[cfg(target_os = "windows")] +use windows::Win32::UI::WindowsAndMessaging::{SetForegroundWindow, ShowWindow, SW_RESTORE}; + +#[cfg(target_os = "windows")] +/// Brings the console window to the foreground on Windows. +pub fn bring_terminal_to_front() { + // Skip if running inside VS Code's integrated terminal to avoid spawning a new window + if let Ok(term) = std::env::var("TERM_PROGRAM") { + if term.to_lowercase().contains("vscode") { + return; + } + } + + unsafe { + let hwnd: HWND = GetConsoleWindow(); + if hwnd.0 != 0 { + // Restore the window in case it is minimized + ShowWindow(hwnd, SW_RESTORE); + // Attempt to bring the window to the foreground + let _ = SetForegroundWindow(hwnd); + } + } +} + +#[cfg(not(target_os = "windows"))] +/// Stub for non-Windows platforms. +pub fn bring_terminal_to_front() {} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn call_bring_terminal_to_front() { + // The function should simply run without panicking on all platforms. + bring_terminal_to_front(); + } +} +