use windows::Win32::{
Foundation::{CloseHandle, MAX_PATH},
System::Threading::{
OpenProcess, QueryFullProcessImageNameW, PROCESS_NAME_FORMAT,
PROCESS_QUERY_LIMITED_INFORMATION,
},
UI::WindowsAndMessaging::{GetForegroundWindow, GetWindowTextW, GetWindowThreadProcessId},
};
use crate::FocusedWindowInfo;
pub(crate) fn get_focused_window_info() -> Option<FocusedWindowInfo> {
unsafe {
let hwnd = GetForegroundWindow();
if hwnd.is_invalid() {
return None;
}
let mut title_buf = [0u16; 512];
let title_len = GetWindowTextW(hwnd, &mut title_buf);
let window_title = if title_len > 0 {
String::from_utf16_lossy(&title_buf[..title_len as usize])
} else {
String::new()
};
let mut process_id: u32 = 0;
GetWindowThreadProcessId(hwnd, Some(&mut process_id));
let app_name = get_process_name(process_id).unwrap_or_default();
Some(FocusedWindowInfo {
app_name,
window_title,
bundle_id: None,
pid: Some(process_id),
})
}
}
fn get_process_name(pid: u32) -> Option<String> {
unsafe {
let handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, pid).ok()?;
let mut buf = [0u16; MAX_PATH as usize];
let mut size = buf.len() as u32;
let result =
QueryFullProcessImageNameW(handle, PROCESS_NAME_FORMAT(0), &mut buf, &mut size);
let _ = CloseHandle(handle);
result.ok()?;
let full_path = String::from_utf16_lossy(&buf[..size as usize]);
let file_name = full_path
.rsplit('\\')
.next()
.unwrap_or(&full_path)
.to_string();
Some(file_name)
}
}