use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum AppsTarget {
#[default]
All,
Focused,
}
#[derive(Debug, Clone, Default, Deserialize, JsonSchema)]
pub struct ComputerApps {
pub target: Option<AppsTarget>,
pub timeout_ms: Option<u64>,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum SnapshotFormat {
#[default]
Tree,
Json,
}
#[derive(Debug, Clone, Default, Deserialize, JsonSchema)]
pub struct ComputerSnapshot {
pub name: Option<String>,
pub pid: Option<u32>,
pub selector: Option<String>,
pub nth: Option<usize>,
pub max_depth: Option<u32>,
pub format: Option<SnapshotFormat>,
pub timeout_ms: Option<u64>,
pub surface: Option<SurfaceKind>,
}
#[derive(Debug, Clone, Serialize, JsonSchema)]
pub struct AppInfo {
pub name: String,
pub pid: Option<u32>,
pub foreground: bool,
}
#[derive(Debug, Clone, Serialize, JsonSchema)]
pub struct AppsOutput {
pub apps: Vec<AppInfo>,
pub count: usize,
}
#[derive(Debug, Clone, Serialize, JsonSchema)]
pub struct FocusedElement {
pub role: String,
pub name: Option<String>,
pub value: Option<String>,
pub path: Vec<String>,
}
#[derive(Debug, Clone, Serialize, JsonSchema)]
pub struct FocusedOutput {
pub app: String,
pub pid: Option<u32>,
pub focused_element: Option<FocusedElement>,
}
#[derive(Debug, Clone, Default, Deserialize, JsonSchema)]
pub struct ComputerScreenshot {
pub region: Option<Vec<i32>>,
pub app: Option<String>,
pub pid: Option<u32>,
pub selector: Option<String>,
pub nth: Option<usize>,
#[serde(default)]
pub annotate: bool,
pub max_width: Option<u32>,
pub timeout_ms: Option<u64>,
pub surface: Option<SurfaceKind>,
}
#[derive(Debug, Clone, Serialize, JsonSchema)]
pub struct ScreenshotOutput {
pub width: u32,
pub height: u32,
pub desktop_origin: (i32, i32),
pub desktop_scale: (f64, f64),
pub bytes: usize,
pub legend: Vec<LegendEntryOutput>,
pub omitted: Vec<OmissionOutput>,
pub truncated: usize,
#[serde(skip)]
pub images: Vec<cosh_sdk::connector::ImageBlock>,
}
#[derive(Debug, Clone, Serialize, JsonSchema)]
pub struct LegendEntryOutput {
pub tag: String,
pub selector: String,
pub role: String,
pub name: Option<String>,
pub color: [u8; 3],
}
#[derive(Debug, Clone, Serialize, JsonSchema)]
pub struct OmissionOutput {
pub selector: String,
pub role: String,
pub name: Option<String>,
pub reason: String,
}
#[derive(Debug, Clone, Serialize, JsonSchema)]
pub struct SnapshotOutput {
pub app: String,
pub pid: Option<u32>,
pub snapshot: String,
pub elements: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum ToggleState {
Off,
On,
Mixed,
}
impl From<xa11y::Toggled> for ToggleState {
fn from(t: xa11y::Toggled) -> Self {
match t {
xa11y::Toggled::Off => Self::Off,
xa11y::Toggled::On => Self::On,
xa11y::Toggled::Mixed => Self::Mixed,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct ElementStates {
pub enabled: bool,
pub visible: bool,
pub focused: bool,
pub checked: Option<ToggleState>,
pub selected: bool,
pub expanded: Option<bool>,
pub editable: bool,
pub busy: bool,
}
impl Default for ElementStates {
fn default() -> Self {
Self {
enabled: true,
visible: true,
focused: false,
checked: None,
selected: false,
expanded: None,
editable: false,
busy: false,
}
}
}
impl ElementStates {
#[must_use]
pub fn from_state_set(states: &xa11y::StateSet) -> Self {
Self {
enabled: states.enabled,
visible: states.visible,
focused: states.focused,
checked: states.checked.map(ToggleState::from),
selected: states.selected,
expanded: states.expanded,
editable: states.editable,
busy: states.busy,
}
}
#[must_use]
pub fn is_default(&self) -> bool {
*self == Self::default()
}
#[must_use]
pub fn outline_tokens(&self) -> Vec<&'static str> {
let mut tokens = Vec::new();
if !self.enabled {
tokens.push("disabled");
}
if !self.visible {
tokens.push("hidden");
}
if self.focused {
tokens.push("focused");
}
match self.checked {
Some(ToggleState::On) => tokens.push("checked"),
Some(ToggleState::Off) => tokens.push("unchecked"),
Some(ToggleState::Mixed) => tokens.push("mixed"),
None => {}
}
if self.selected {
tokens.push("selected");
}
match self.expanded {
Some(true) => tokens.push("expanded"),
Some(false) => tokens.push("collapsed"),
None => {}
}
if self.editable {
tokens.push("editable");
}
if self.busy {
tokens.push("busy");
}
tokens
}
}
#[derive(Debug, Clone, Serialize)]
pub struct StateNode {
pub role: String,
pub name: Option<String>,
pub value: Option<String>,
pub states: ElementStates,
pub children: Vec<StateNode>,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ActAction {
#[default]
Press,
Focus,
Blur,
Toggle,
Select,
Expand,
Collapse,
ShowMenu,
Increment,
Decrement,
ScrollIntoView,
SetValue,
SetNumericValue,
SelectText,
TypeText,
PerformAction,
}
#[derive(Debug, Clone, Default, Deserialize, JsonSchema)]
pub struct ComputerAct {
pub name: Option<String>,
pub pid: Option<u32>,
pub selector: Option<String>,
pub nth: Option<usize>,
pub action: Option<ActAction>,
pub value: Option<String>,
pub numeric_value: Option<f64>,
pub range: Option<Vec<u32>>,
pub timeout_ms: Option<u64>,
pub surface: Option<SurfaceKind>,
pub key: Option<String>,
pub text: Option<String>,
pub held: Option<Vec<String>>,
pub wait: Option<u64>,
pub then: Option<Box<ComputerAct>>,
}
#[derive(Debug, Clone, Serialize, JsonSchema)]
pub struct ActOutput {
pub sent: String,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum WaitState {
Attached,
Detached,
#[default]
Visible,
Hidden,
Enabled,
Disabled,
Focused,
Unfocused,
}
#[derive(Debug, Clone, Default, Deserialize, JsonSchema)]
pub struct ComputerWait {
pub name: Option<String>,
pub pid: Option<u32>,
pub selector: Option<String>,
pub nth: Option<usize>,
pub state: Option<WaitState>,
pub timeout_ms: Option<u64>,
}
#[derive(Debug, Clone, Serialize, JsonSchema)]
pub struct WaitOutput {
pub met: bool,
pub elapsed_ms: u64,
pub observed: WaitObservation,
}
#[derive(Debug, Clone, Serialize, JsonSchema)]
pub struct WaitObservation {
pub attached: bool,
pub visible: Option<bool>,
pub enabled: Option<bool>,
pub focused: Option<bool>,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum SurfaceKind {
#[default]
MenuBar,
StatusItems,
Taskbar,
Panel,
Dock,
Desktop,
Flyout,
Unknown,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum PointerAction {
#[default]
Click,
DoubleClick,
RightClick,
Move,
Down,
Up,
Scroll,
Drag,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum PointerAnchor {
#[default]
Center,
TopLeft,
TopRight,
BottomLeft,
BottomRight,
}
#[derive(Debug, Clone, Default, Deserialize, JsonSchema)]
pub struct ComputerControl {
pub x: Option<i32>,
pub y: Option<i32>,
pub action: Option<PointerAction>,
pub button: Option<String>,
pub dx: Option<i32>,
pub dy: Option<i32>,
pub app: Option<String>,
pub pid: Option<u32>,
pub surface: Option<SurfaceKind>,
pub selector: Option<String>,
pub nth: Option<usize>,
pub anchor: Option<PointerAnchor>,
pub count: Option<u32>,
pub held: Option<Vec<String>>,
pub x2: Option<i32>,
pub y2: Option<i32>,
pub to_selector: Option<String>,
pub duration_ms: Option<u64>,
pub key: Option<String>,
pub text: Option<String>,
pub wait: Option<u64>,
pub then: Option<Box<ComputerControl>>,
}
#[derive(Debug, Clone, Serialize, JsonSchema)]
pub struct ControlOutput {
pub sent: String,
}