use serde::{Deserialize, Serialize};
use super::AccessibilitySurface;
use super::bridge::run_ax;
use super::target::{Target, WindowIdentity, now_seconds};
use crate::MacosError;
use crate::screenshot::{WindowScope, list_windows};
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ActionStatus {
Confirmed,
SentUnverified,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct WindowActionResult {
pub action: String,
pub window_id: u32,
pub surface: AccessibilitySurface,
pub r#ref: String,
pub status: ActionStatus,
pub frontmost_pid_before: i32,
pub frontmost_pid_after: i32,
pub foreground_changed: bool,
}
fn act(token: &str, action: &str, value: Option<&str>) -> Result<WindowActionResult, MacosError> {
let target = Target::decode(token, now_seconds()?)?;
let windows = list_windows(WindowScope::AllSpaces)?;
let current = windows
.iter()
.find(|window| window.window_id == target.window.window_id)
.ok_or_else(|| MacosError::NotFound("window disappeared; inspect again".into()))?;
if WindowIdentity::from(current) != target.window {
return Err(MacosError::Other(
"window identity changed; inspect again".into(),
));
}
run_ax(
&target.window,
include_str!("ax_action.swift"),
&[],
&serde_json::json!({
"ref": target.r#ref,
"surface": target.surface,
"fingerprint": target.fingerprint,
"issued_at": target.issued_at,
"action": action,
"value": value,
}),
)
}
pub fn press(token: &str) -> Result<WindowActionResult, MacosError> {
act(token, "press", None)
}
pub fn set_value(token: &str, value: &str) -> Result<WindowActionResult, MacosError> {
if value.len() > 65_536 {
return Err(MacosError::Other(
"window text value must be at most 65536 bytes".into(),
));
}
act(token, "set_value", Some(value))
}