use super::{CaptureRequest, Display, Launched, Shot, Window, xcap_common as common};
use crate::extensions::computer::input;
use core_graphics::{
event::CGEvent,
event_source::{CGEventSource, CGEventSourceStateID},
};
use std::process::Command;
pub fn available() -> bool {
true
}
pub fn describe() -> String {
"macos, capture: xcap (needs Screen Recording permission), input: enigo (CGEvent, needs Accessibility permission), windows: CoreGraphics".to_string()
}
pub fn displays() -> Result<Vec<Display>, String> {
common::displays()
}
pub fn windows() -> Result<Vec<Window>, String> {
common::windows()
}
pub fn focus_window(id: u64) -> Result<(), String> {
let window = super::window(id)?;
if window.app.is_empty() {
return Err(format!(
"window {id} reports no application name to activate"
));
}
let output = Command::new("open")
.args(["-a", &window.app])
.stdin(std::process::Stdio::null())
.output()
.map_err(|e| format!("could not run open -a {:?}: {e}", window.app))?;
if output.status.success() {
Ok(())
} else {
let err = String::from_utf8_lossy(&output.stderr).trim().to_string();
Err(format!(
"open -a {:?} failed ({}): {}; macOS may need the Accessibility permission",
window.app,
output.status,
if err.is_empty() { "no stderr" } else { &err }
))
}
}
pub fn window_action(id: u64, action: &str) -> Result<String, String> {
focus_window(id)?;
let chord = match action {
"close" => "cmd+w",
"minimize" => "cmd+m",
"maximize" | "restore" => "ctrl+cmd+f",
other => return Err(format!("unknown window action {other:?}")),
};
input::press_chord(chord, 1, 0.0)?;
Ok(format!("{action}: sent {chord} to window {id}"))
}
pub fn capture(req: &CaptureRequest) -> Result<Shot, String> {
common::capture(req)
}
pub fn cursor() -> Option<(i32, i32)> {
let source = CGEventSource::new(CGEventSourceStateID::HIDSystemState).ok()?;
let event = CGEvent::new(source).ok()?;
let point = event.location();
Some((point.x as i32, point.y as i32))
}
pub fn launch(target: &str, args: &[String], wait_ms: u64) -> Result<Launched, String> {
common::launch(target, args, wait_ms)
}