Implement support for Windows

This commit is contained in:
felixm 2024-07-10 19:54:38 -04:00
parent 288ef6a9c4
commit 0d50da7ceb
5 changed files with 131 additions and 81 deletions

View File

@ -1,9 +1,12 @@
[package]
name = "antidrift"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = "1.0.86"
ratatui = "0.27.0"
regex = "1.10.5"
[package]
name = "antidrift"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = "1.0.86"
ratatui = "0.27.0"
regex = "1.10.5"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["winuser", "processthreadsapi"] }

View File

@ -9,5 +9,5 @@ window was and calculates a session score from that.
To use AntiDrift, run `cargo run --release` directly, or `cargo build --release`
and copy the binary into your `PATH`.
Uses `xdotool` to get window titles and minimize windows. Currently Linux with
X11 is the only supported platform.
Under Linux, we use `xdotool` to get window titles and minimize windows. Under
Windows, we use the package `winapi` for the same functionality.

View File

@ -1,70 +1,70 @@
use regex::Regex;
use std::{process::Command, process::Output, str};
pub fn get_title_clean() -> String {
let title = get_window_info().title;
let re = Regex::new(r"-?\d+([:.]\d+)+%?").unwrap();
re.replace_all(&title, "").to_string()
}
pub fn minimize_other(title: &str) {
let window_info = get_window_info();
if &window_info.title != title {
run(&format!("xdotool windowminimize {}", window_info.wid));
}
}
struct WindowInfo {
title: String,
_class: String,
wid: String,
}
fn run(cmd: &str) -> Option<String> {
let output = Command::new("sh").arg("-c").arg(cmd).output();
let Ok(Output {
status,
stdout,
stderr: _,
}) = output
else {
return None;
};
if status.code() != Some(0) {
return None;
}
let Ok(output_str) = str::from_utf8(&stdout) else {
return None;
};
Some(output_str.trim().to_string())
}
fn get_window_info() -> WindowInfo {
let none = WindowInfo {
title: "none".to_string(),
_class: "none".to_string(),
wid: "".to_string(),
};
let Some(wid) = run("xdotool getactivewindow") else {
return none;
};
let Some(class) = run(&format!("xdotool getwindowclassname {wid}")) else {
return none;
};
let Some(title) = run(&format!("xdotool getwindowname {wid}")) else {
return none;
};
WindowInfo {
title,
_class: class,
wid,
}
}
use regex::Regex;
use std::{process::Command, process::Output, str};
pub fn get_title_clean() -> String {
let title = get_window_info().title;
let re = Regex::new(r"-?\d+([:.]\d+)+%?").unwrap();
re.replace_all(&title, "").to_string()
}
pub fn minimize_other(title: &str) {
let window_info = get_window_info();
if &window_info.title != title {
run(&format!("xdotool windowminimize {}", window_info.wid));
}
}
struct WindowInfo {
title: String,
_class: String,
wid: String,
}
fn run(cmd: &str) -> Option<String> {
let output = Command::new("sh").arg("-c").arg(cmd).output();
let Ok(Output {
status,
stdout,
stderr: _,
}) = output
else {
return None;
};
if status.code() != Some(0) {
return None;
}
let Ok(output_str) = str::from_utf8(&stdout) else {
return None;
};
Some(output_str.trim().to_string())
}
fn get_window_info() -> WindowInfo {
let none = WindowInfo {
title: "none".to_string(),
_class: "none".to_string(),
wid: "".to_string(),
};
let Some(wid) = run("xdotool getactivewindow") else {
return none;
};
let Some(class) = run(&format!("xdotool getwindowclassname {wid}")) else {
return none;
};
let Some(title) = run(&format!("xdotool getwindowname {wid}")) else {
return none;
};
WindowInfo {
title,
_class: class,
wid,
}
}

9
src/window/mod.rs Normal file
View File

@ -0,0 +1,9 @@
#[cfg(target_os = "windows")]
mod windows;
#[cfg(target_os = "windows")]
pub use windows::*;
#[cfg(target_os = "linux")]
mod linux;
#[cfg(target_os = "linux")]
pub use linux::*;

38
src/window/windows.rs Normal file
View File

@ -0,0 +1,38 @@
use regex::Regex;
use std::{ffi::OsString, os::windows::ffi::OsStringExt};
use winapi::shared::windef::HWND;
use winapi::um::winuser::{ShowWindow, SW_MINIMIZE, GetForegroundWindow, GetWindowTextW};
pub fn get_title_clean() -> String {
let title = get_window_info().title;
let re = Regex::new(r"-?\d+([:.]\d+)+%?").unwrap();
re.replace_all(&title, "").to_string()
}
pub fn minimize_other(title: &str) {
let window_info = get_window_info();
if window_info.title != title {
unsafe {
ShowWindow(window_info.hwnd, SW_MINIMIZE);
}
}
}
struct WindowInfo {
title: String,
hwnd: HWND,
}
fn get_window_info() -> WindowInfo {
unsafe {
let hwnd = GetForegroundWindow();
let mut text: [u16; 512] = [0; 512];
let len = GetWindowTextW(hwnd, text.as_mut_ptr(), text.len() as i32) as usize;
let title = OsString::from_wide(&text[..len]).to_string_lossy().into_owned();
WindowInfo {
title,
hwnd,
}
}
}