Skip to main content

Computer

Struct Computer 

Source
pub struct Computer<B: Backend> { /* private fields */ }
Expand description

A computer-use session over a Backend.

Observe an app with get_app_state, then act on it by element index or by screenshot pixel. It remembers the latest state per app so indexes stay valid until the next capture of that app.

use computer_use::{CaptureOptions, ClickOptions, ClickTarget, Computer};

let mut computer = Computer::new()?;
let state = computer.get_app_state("TextEdit", &CaptureOptions::default())?;
println!("{}", state.render());

computer.click("TextEdit", ClickTarget::Element(3), ClickOptions::default())?;
computer.type_text("TextEdit", "Hello from Rust")?;
computer.press_key("TextEdit", "super+s")?;

Implementations§

Source§

impl Computer<NativeBackend>

Source

pub fn new() -> Result<Self>

Available on Linux or macOS or Windows only.

Creates a session over this platform’s native backend.

§Errors

Fails if the platform’s accessibility stack cannot be initialized.

Examples found in repository?
examples/list_apps.rs (line 7)
6fn main() -> computer_use::Result<()> {
7    let computer = computer_use::Computer::new()?;
8    for app in computer.list_apps()? {
9        let status = match (app.is_running, app.is_active, app.needs_restart) {
10            (true, _, true) => "restart",
11            (true, true, _) => "active",
12            (true, false, _) => "running",
13            _ => "installed",
14        };
15        let pid = app.pid.map(|p| format!(" pid {p}")).unwrap_or_default();
16        println!("{:<9} {} [{}]{pid}", status, app.name, app.reference());
17    }
18    Ok(())
19}
More examples
Hide additional examples
examples/inspect.rs (line 24)
13fn main() -> ExitCode {
14    use computer_use::{CaptureOptions, Computer};
15
16    let mut args = std::env::args().skip(1);
17    let Some(app) = args.next() else {
18        eprintln!("usage: inspect <app name | bundle id | pid:N> [screenshot.png]");
19        return ExitCode::FAILURE;
20    };
21    let output = args.next();
22
23    let run = || -> computer_use::Result<()> {
24        let mut computer = Computer::new()?;
25        let permissions = computer.permissions();
26        if !permissions.all_granted() {
27            eprintln!("warning: missing permissions: {permissions:?}");
28        }
29        let started = std::time::Instant::now();
30        let state = computer.get_app_state(&app, &CaptureOptions::default())?;
31        println!("{state}");
32        eprintln!("\ncaptured {} elements in {:?}", state.elements.len(), started.elapsed());
33        if let (Some(path), Some(shot)) = (output, &state.screenshot) {
34            std::fs::write(&path, shot.png())?;
35            eprintln!("saved {}x{} screenshot to {path}", shot.width(), shot.height());
36        }
37        Ok(())
38    };
39    match run() {
40        Ok(()) => ExitCode::SUCCESS,
41        Err(e) => {
42            eprintln!("error: {e}");
43            ExitCode::FAILURE
44        }
45    }
46}
examples/textedit.rs (line 19)
11fn main() -> computer_use::Result<()> {
12    use std::time::Duration;
13
14    use computer_use::{
15        CaptureOptions, ClickMethod, ClickOptions, ClickTarget, Computer, ElementQuery, Error, TextSelection,
16    };
17
18    const APP: &str = "TextEdit";
19    let mut computer = Computer::new()?.settle_delay(Duration::from_millis(300));
20    let tree_only = CaptureOptions::default().include_screenshot(false);
21
22    let state = computer.get_app_state(APP, &tree_only)?;
23    let new_doc = state.find(&ElementQuery::text("New Document").with_role("button").exact(true)).next();
24    if let Some(button) = new_doc.map(|e| e.index) {
25        println!(
26            "click New Document: {:?}",
27            computer.click(APP, ClickTarget::Element(button), ClickOptions::default())?
28        );
29    }
30
31    let state = computer.get_app_state(APP, &tree_only)?;
32    let text_area = state
33        .find(&ElementQuery::role("AXTextArea"))
34        .next()
35        .map(|e| e.index)
36        .ok_or_else(|| Error::StateUnavailable("no text area".into()))?;
37    println!(
38        "click text area {text_area}: {:?}",
39        computer.click(APP, ClickTarget::Element(text_area), ClickOptions::default())?
40    );
41    computer.set_value(APP, text_area, "")?;
42    computer.type_text(APP, "Hello from computer-use-rs!\nSecond line.")?;
43
44    let state = computer.get_app_state(APP, &tree_only)?;
45    let value = state.find(&ElementQuery::role("AXTextArea")).next().and_then(|e| e.value.clone());
46    println!("text area now contains: {value:?}");
47
48    computer.select_text(APP, text_area, &TextSelection::new("computer-use-rs"))?;
49    let state = computer.get_app_state(APP, &tree_only)?;
50    println!("selected text: {:?}", state.selected_text);
51
52    computer.press_key(APP, "BackSpace")?;
53    let state = computer.get_app_state(APP, &tree_only)?;
54    let value = state.find(&ElementQuery::role("AXTextArea")).next().and_then(|e| e.value.clone());
55    println!("after BackSpace: {value:?}");
56
57    computer.press_key(APP, "super+a")?;
58    let state = computer.get_app_state(APP, &tree_only)?;
59    println!("after super+a, selected: {:?}", state.selected_text);
60
61    let focused = ClickOptions::default().method(ClickMethod::FocusedBackground);
62    println!("focused click: {:?}", computer.click(APP, ClickTarget::Element(text_area), focused)?);
63    computer.type_text(APP, " The end.")?;
64    let state = computer.get_app_state(APP, &tree_only)?;
65    let value = state.find(&ElementQuery::role("AXTextArea")).next().and_then(|e| e.value.clone());
66    println!("final text: {value:?}");
67
68    Ok(())
69}
Source§

impl<B: Backend> Computer<B>

Source

pub fn with_backend(backend: B) -> Self

Creates a session over a custom backend.

Source

pub const fn delivery(self, delivery: Delivery) -> Self

Sets the default input delivery for synthesized events.

Source

pub const fn settle_delay(self, delay: Duration) -> Self

Sleeps this long after every action so the UI can settle before the next capture.

Examples found in repository?
examples/textedit.rs (line 19)
11fn main() -> computer_use::Result<()> {
12    use std::time::Duration;
13
14    use computer_use::{
15        CaptureOptions, ClickMethod, ClickOptions, ClickTarget, Computer, ElementQuery, Error, TextSelection,
16    };
17
18    const APP: &str = "TextEdit";
19    let mut computer = Computer::new()?.settle_delay(Duration::from_millis(300));
20    let tree_only = CaptureOptions::default().include_screenshot(false);
21
22    let state = computer.get_app_state(APP, &tree_only)?;
23    let new_doc = state.find(&ElementQuery::text("New Document").with_role("button").exact(true)).next();
24    if let Some(button) = new_doc.map(|e| e.index) {
25        println!(
26            "click New Document: {:?}",
27            computer.click(APP, ClickTarget::Element(button), ClickOptions::default())?
28        );
29    }
30
31    let state = computer.get_app_state(APP, &tree_only)?;
32    let text_area = state
33        .find(&ElementQuery::role("AXTextArea"))
34        .next()
35        .map(|e| e.index)
36        .ok_or_else(|| Error::StateUnavailable("no text area".into()))?;
37    println!(
38        "click text area {text_area}: {:?}",
39        computer.click(APP, ClickTarget::Element(text_area), ClickOptions::default())?
40    );
41    computer.set_value(APP, text_area, "")?;
42    computer.type_text(APP, "Hello from computer-use-rs!\nSecond line.")?;
43
44    let state = computer.get_app_state(APP, &tree_only)?;
45    let value = state.find(&ElementQuery::role("AXTextArea")).next().and_then(|e| e.value.clone());
46    println!("text area now contains: {value:?}");
47
48    computer.select_text(APP, text_area, &TextSelection::new("computer-use-rs"))?;
49    let state = computer.get_app_state(APP, &tree_only)?;
50    println!("selected text: {:?}", state.selected_text);
51
52    computer.press_key(APP, "BackSpace")?;
53    let state = computer.get_app_state(APP, &tree_only)?;
54    let value = state.find(&ElementQuery::role("AXTextArea")).next().and_then(|e| e.value.clone());
55    println!("after BackSpace: {value:?}");
56
57    computer.press_key(APP, "super+a")?;
58    let state = computer.get_app_state(APP, &tree_only)?;
59    println!("after super+a, selected: {:?}", state.selected_text);
60
61    let focused = ClickOptions::default().method(ClickMethod::FocusedBackground);
62    println!("focused click: {:?}", computer.click(APP, ClickTarget::Element(text_area), focused)?);
63    computer.type_text(APP, " The end.")?;
64    let state = computer.get_app_state(APP, &tree_only)?;
65    let value = state.find(&ElementQuery::role("AXTextArea")).next().and_then(|e| e.value.clone());
66    println!("final text: {value:?}");
67
68    Ok(())
69}
Source

pub const fn backend(&self) -> &B

The underlying backend, for platform-specific calls.

Source

pub fn permissions(&self) -> Permissions

Permissions currently held by this process.

Examples found in repository?
examples/inspect.rs (line 25)
13fn main() -> ExitCode {
14    use computer_use::{CaptureOptions, Computer};
15
16    let mut args = std::env::args().skip(1);
17    let Some(app) = args.next() else {
18        eprintln!("usage: inspect <app name | bundle id | pid:N> [screenshot.png]");
19        return ExitCode::FAILURE;
20    };
21    let output = args.next();
22
23    let run = || -> computer_use::Result<()> {
24        let mut computer = Computer::new()?;
25        let permissions = computer.permissions();
26        if !permissions.all_granted() {
27            eprintln!("warning: missing permissions: {permissions:?}");
28        }
29        let started = std::time::Instant::now();
30        let state = computer.get_app_state(&app, &CaptureOptions::default())?;
31        println!("{state}");
32        eprintln!("\ncaptured {} elements in {:?}", state.elements.len(), started.elapsed());
33        if let (Some(path), Some(shot)) = (output, &state.screenshot) {
34            std::fs::write(&path, shot.png())?;
35            eprintln!("saved {}x{} screenshot to {path}", shot.width(), shot.height());
36        }
37        Ok(())
38    };
39    match run() {
40        Ok(()) => ExitCode::SUCCESS,
41        Err(e) => {
42            eprintln!("error: {e}");
43            ExitCode::FAILURE
44        }
45    }
46}
Source

pub fn request_permissions(&self) -> Permissions

Prompts for missing permissions where the OS supports it.

Source

pub fn list_apps(&self) -> Result<Vec<AppInfo>>

Lists running apps first (frontmost first), then installed apps, by name.

§Errors

Fails if the platform cannot enumerate apps.

Examples found in repository?
examples/list_apps.rs (line 8)
6fn main() -> computer_use::Result<()> {
7    let computer = computer_use::Computer::new()?;
8    for app in computer.list_apps()? {
9        let status = match (app.is_running, app.is_active, app.needs_restart) {
10            (true, _, true) => "restart",
11            (true, true, _) => "active",
12            (true, false, _) => "running",
13            _ => "installed",
14        };
15        let pid = app.pid.map(|p| format!(" pid {p}")).unwrap_or_default();
16        println!("{:<9} {} [{}]{pid}", status, app.name, app.reference());
17    }
18    Ok(())
19}
Source

pub fn resolve_app(&self, query: &str) -> Result<AppInfo>

Resolves an app query (name, bundle ID, path, or pid:<n>), preferring running apps.

§Errors

Returns Error::AppNotFound when nothing matches, or Error::AmbiguousApp when several running apps match equally well.

Source

pub fn get_app_state( &mut self, app: &str, options: &CaptureOptions, ) -> Result<&AppState>

Captures the app’s current window, replacing any earlier state (and element indexes) for that app.

§Errors

Fails if the app cannot be found or launched, has no window, or permissions are missing.

Examples found in repository?
examples/inspect.rs (line 30)
13fn main() -> ExitCode {
14    use computer_use::{CaptureOptions, Computer};
15
16    let mut args = std::env::args().skip(1);
17    let Some(app) = args.next() else {
18        eprintln!("usage: inspect <app name | bundle id | pid:N> [screenshot.png]");
19        return ExitCode::FAILURE;
20    };
21    let output = args.next();
22
23    let run = || -> computer_use::Result<()> {
24        let mut computer = Computer::new()?;
25        let permissions = computer.permissions();
26        if !permissions.all_granted() {
27            eprintln!("warning: missing permissions: {permissions:?}");
28        }
29        let started = std::time::Instant::now();
30        let state = computer.get_app_state(&app, &CaptureOptions::default())?;
31        println!("{state}");
32        eprintln!("\ncaptured {} elements in {:?}", state.elements.len(), started.elapsed());
33        if let (Some(path), Some(shot)) = (output, &state.screenshot) {
34            std::fs::write(&path, shot.png())?;
35            eprintln!("saved {}x{} screenshot to {path}", shot.width(), shot.height());
36        }
37        Ok(())
38    };
39    match run() {
40        Ok(()) => ExitCode::SUCCESS,
41        Err(e) => {
42            eprintln!("error: {e}");
43            ExitCode::FAILURE
44        }
45    }
46}
More examples
Hide additional examples
examples/textedit.rs (line 22)
11fn main() -> computer_use::Result<()> {
12    use std::time::Duration;
13
14    use computer_use::{
15        CaptureOptions, ClickMethod, ClickOptions, ClickTarget, Computer, ElementQuery, Error, TextSelection,
16    };
17
18    const APP: &str = "TextEdit";
19    let mut computer = Computer::new()?.settle_delay(Duration::from_millis(300));
20    let tree_only = CaptureOptions::default().include_screenshot(false);
21
22    let state = computer.get_app_state(APP, &tree_only)?;
23    let new_doc = state.find(&ElementQuery::text("New Document").with_role("button").exact(true)).next();
24    if let Some(button) = new_doc.map(|e| e.index) {
25        println!(
26            "click New Document: {:?}",
27            computer.click(APP, ClickTarget::Element(button), ClickOptions::default())?
28        );
29    }
30
31    let state = computer.get_app_state(APP, &tree_only)?;
32    let text_area = state
33        .find(&ElementQuery::role("AXTextArea"))
34        .next()
35        .map(|e| e.index)
36        .ok_or_else(|| Error::StateUnavailable("no text area".into()))?;
37    println!(
38        "click text area {text_area}: {:?}",
39        computer.click(APP, ClickTarget::Element(text_area), ClickOptions::default())?
40    );
41    computer.set_value(APP, text_area, "")?;
42    computer.type_text(APP, "Hello from computer-use-rs!\nSecond line.")?;
43
44    let state = computer.get_app_state(APP, &tree_only)?;
45    let value = state.find(&ElementQuery::role("AXTextArea")).next().and_then(|e| e.value.clone());
46    println!("text area now contains: {value:?}");
47
48    computer.select_text(APP, text_area, &TextSelection::new("computer-use-rs"))?;
49    let state = computer.get_app_state(APP, &tree_only)?;
50    println!("selected text: {:?}", state.selected_text);
51
52    computer.press_key(APP, "BackSpace")?;
53    let state = computer.get_app_state(APP, &tree_only)?;
54    let value = state.find(&ElementQuery::role("AXTextArea")).next().and_then(|e| e.value.clone());
55    println!("after BackSpace: {value:?}");
56
57    computer.press_key(APP, "super+a")?;
58    let state = computer.get_app_state(APP, &tree_only)?;
59    println!("after super+a, selected: {:?}", state.selected_text);
60
61    let focused = ClickOptions::default().method(ClickMethod::FocusedBackground);
62    println!("focused click: {:?}", computer.click(APP, ClickTarget::Element(text_area), focused)?);
63    computer.type_text(APP, " The end.")?;
64    let state = computer.get_app_state(APP, &tree_only)?;
65    let value = state.find(&ElementQuery::role("AXTextArea")).next().and_then(|e| e.value.clone());
66    println!("final text: {value:?}");
67
68    Ok(())
69}
Source

pub fn list_windows(&self, app: &str) -> Result<Vec<WindowInfo>>

The app’s windows, front to back where the platform knows the order. Pass one to CaptureOptions::window to capture it instead of the focused or main window.

§Errors

Fails if the app is not running or the backend cannot list windows.

Source

pub fn state(&self, app: &str) -> Option<&AppState>

The latest captured state of an app, if any.

Source

pub fn forget(&mut self, app: &str)

Discards the remembered state of one app.

Source

pub fn clear(&mut self)

Discards all remembered state.

Source

pub fn query( &mut self, app: &str, query: &ElementQuery, max_nodes: usize, ) -> Result<Vec<Element>>

Finds elements in the app’s current window without taking a screenshot.

The fresh tree replaces the app’s remembered state, so the returned indexes can be used with element actions. A previous screenshot is kept when the window has not moved.

§Errors

Fails like get_app_state or if the query is empty.

Source

pub fn click( &mut self, app: &str, target: ClickTarget, options: ClickOptions, ) -> Result<ClickOutcome>

Clicks an element, a screenshot pixel, or a screen point.

§Errors

Fails if there is no state for the app, the target is invalid, or delivery fails.

Examples found in repository?
examples/textedit.rs (line 27)
11fn main() -> computer_use::Result<()> {
12    use std::time::Duration;
13
14    use computer_use::{
15        CaptureOptions, ClickMethod, ClickOptions, ClickTarget, Computer, ElementQuery, Error, TextSelection,
16    };
17
18    const APP: &str = "TextEdit";
19    let mut computer = Computer::new()?.settle_delay(Duration::from_millis(300));
20    let tree_only = CaptureOptions::default().include_screenshot(false);
21
22    let state = computer.get_app_state(APP, &tree_only)?;
23    let new_doc = state.find(&ElementQuery::text("New Document").with_role("button").exact(true)).next();
24    if let Some(button) = new_doc.map(|e| e.index) {
25        println!(
26            "click New Document: {:?}",
27            computer.click(APP, ClickTarget::Element(button), ClickOptions::default())?
28        );
29    }
30
31    let state = computer.get_app_state(APP, &tree_only)?;
32    let text_area = state
33        .find(&ElementQuery::role("AXTextArea"))
34        .next()
35        .map(|e| e.index)
36        .ok_or_else(|| Error::StateUnavailable("no text area".into()))?;
37    println!(
38        "click text area {text_area}: {:?}",
39        computer.click(APP, ClickTarget::Element(text_area), ClickOptions::default())?
40    );
41    computer.set_value(APP, text_area, "")?;
42    computer.type_text(APP, "Hello from computer-use-rs!\nSecond line.")?;
43
44    let state = computer.get_app_state(APP, &tree_only)?;
45    let value = state.find(&ElementQuery::role("AXTextArea")).next().and_then(|e| e.value.clone());
46    println!("text area now contains: {value:?}");
47
48    computer.select_text(APP, text_area, &TextSelection::new("computer-use-rs"))?;
49    let state = computer.get_app_state(APP, &tree_only)?;
50    println!("selected text: {:?}", state.selected_text);
51
52    computer.press_key(APP, "BackSpace")?;
53    let state = computer.get_app_state(APP, &tree_only)?;
54    let value = state.find(&ElementQuery::role("AXTextArea")).next().and_then(|e| e.value.clone());
55    println!("after BackSpace: {value:?}");
56
57    computer.press_key(APP, "super+a")?;
58    let state = computer.get_app_state(APP, &tree_only)?;
59    println!("after super+a, selected: {:?}", state.selected_text);
60
61    let focused = ClickOptions::default().method(ClickMethod::FocusedBackground);
62    println!("focused click: {:?}", computer.click(APP, ClickTarget::Element(text_area), focused)?);
63    computer.type_text(APP, " The end.")?;
64    let state = computer.get_app_state(APP, &tree_only)?;
65    let value = state.find(&ElementQuery::role("AXTextArea")).next().and_then(|e| e.value.clone());
66    println!("final text: {value:?}");
67
68    Ok(())
69}
Source

pub fn perform_secondary_action( &mut self, app: &str, index: usize, action: &str, ) -> Result<()>

Invokes a named accessibility action on an element (e.g. Show Menu, AXRaise).

§Errors

Fails if the element does not expose the action.

Source

pub fn scroll( &mut self, app: &str, index: usize, direction: ScrollDirection, pages: f64, ) -> Result<()>

Scrolls an element by a number of pages (fractions allowed).

Whole pages use the element’s own scroll-by-page action when it has one; otherwise wheel events are posted at the element’s center.

§Errors

Fails if pages is not positive or the element has no frame.

Source

pub fn scroll_at( &mut self, app: &str, target: ClickTarget, direction: ScrollDirection, pages: f64, ) -> Result<()>

Scrolls at an element, a screenshot pixel, or a screen point, by a number of pages (fractions allowed).

An element target behaves like scroll. For a point, wheel events are posted there; a page is 80% of the scroll area under the point when the latest state has one, else of the captured window, else 400 points.

§Errors

Fails if pages is not positive, a pixel lies outside the screenshot, or delivery fails.

Source

pub fn drag( &mut self, app: &str, from: (f64, f64), to: (f64, f64), ) -> Result<()>

Drags between two screenshot pixels.

§Errors

Fails if there is no screenshot or a point lies outside it.

Source

pub fn drag_screen(&mut self, app: &str, from: Point, to: Point) -> Result<()>

Drags between two screen points. Needs no earlier capture.

§Errors

Fails if the app is not running or delivery fails.

Source

pub fn type_text(&mut self, app: &str, text: &str) -> Result<()>

Types literal text into the app’s focused element.

With background delivery, text is inserted through accessibility when the focused element supports it, and synthesized as keystrokes otherwise.

§Errors

Fails if the app is not running or delivery fails.

Examples found in repository?
examples/textedit.rs (line 42)
11fn main() -> computer_use::Result<()> {
12    use std::time::Duration;
13
14    use computer_use::{
15        CaptureOptions, ClickMethod, ClickOptions, ClickTarget, Computer, ElementQuery, Error, TextSelection,
16    };
17
18    const APP: &str = "TextEdit";
19    let mut computer = Computer::new()?.settle_delay(Duration::from_millis(300));
20    let tree_only = CaptureOptions::default().include_screenshot(false);
21
22    let state = computer.get_app_state(APP, &tree_only)?;
23    let new_doc = state.find(&ElementQuery::text("New Document").with_role("button").exact(true)).next();
24    if let Some(button) = new_doc.map(|e| e.index) {
25        println!(
26            "click New Document: {:?}",
27            computer.click(APP, ClickTarget::Element(button), ClickOptions::default())?
28        );
29    }
30
31    let state = computer.get_app_state(APP, &tree_only)?;
32    let text_area = state
33        .find(&ElementQuery::role("AXTextArea"))
34        .next()
35        .map(|e| e.index)
36        .ok_or_else(|| Error::StateUnavailable("no text area".into()))?;
37    println!(
38        "click text area {text_area}: {:?}",
39        computer.click(APP, ClickTarget::Element(text_area), ClickOptions::default())?
40    );
41    computer.set_value(APP, text_area, "")?;
42    computer.type_text(APP, "Hello from computer-use-rs!\nSecond line.")?;
43
44    let state = computer.get_app_state(APP, &tree_only)?;
45    let value = state.find(&ElementQuery::role("AXTextArea")).next().and_then(|e| e.value.clone());
46    println!("text area now contains: {value:?}");
47
48    computer.select_text(APP, text_area, &TextSelection::new("computer-use-rs"))?;
49    let state = computer.get_app_state(APP, &tree_only)?;
50    println!("selected text: {:?}", state.selected_text);
51
52    computer.press_key(APP, "BackSpace")?;
53    let state = computer.get_app_state(APP, &tree_only)?;
54    let value = state.find(&ElementQuery::role("AXTextArea")).next().and_then(|e| e.value.clone());
55    println!("after BackSpace: {value:?}");
56
57    computer.press_key(APP, "super+a")?;
58    let state = computer.get_app_state(APP, &tree_only)?;
59    println!("after super+a, selected: {:?}", state.selected_text);
60
61    let focused = ClickOptions::default().method(ClickMethod::FocusedBackground);
62    println!("focused click: {:?}", computer.click(APP, ClickTarget::Element(text_area), focused)?);
63    computer.type_text(APP, " The end.")?;
64    let state = computer.get_app_state(APP, &tree_only)?;
65    let value = state.find(&ElementQuery::role("AXTextArea")).next().and_then(|e| e.value.clone());
66    println!("final text: {value:?}");
67
68    Ok(())
69}
Source

pub fn press_key(&mut self, app: &str, key: &str) -> Result<()>

Presses a key chord in xdotool syntax, e.g. Return, super+c, KP_0.

§Errors

Fails if the chord cannot be parsed or delivered.

Examples found in repository?
examples/textedit.rs (line 52)
11fn main() -> computer_use::Result<()> {
12    use std::time::Duration;
13
14    use computer_use::{
15        CaptureOptions, ClickMethod, ClickOptions, ClickTarget, Computer, ElementQuery, Error, TextSelection,
16    };
17
18    const APP: &str = "TextEdit";
19    let mut computer = Computer::new()?.settle_delay(Duration::from_millis(300));
20    let tree_only = CaptureOptions::default().include_screenshot(false);
21
22    let state = computer.get_app_state(APP, &tree_only)?;
23    let new_doc = state.find(&ElementQuery::text("New Document").with_role("button").exact(true)).next();
24    if let Some(button) = new_doc.map(|e| e.index) {
25        println!(
26            "click New Document: {:?}",
27            computer.click(APP, ClickTarget::Element(button), ClickOptions::default())?
28        );
29    }
30
31    let state = computer.get_app_state(APP, &tree_only)?;
32    let text_area = state
33        .find(&ElementQuery::role("AXTextArea"))
34        .next()
35        .map(|e| e.index)
36        .ok_or_else(|| Error::StateUnavailable("no text area".into()))?;
37    println!(
38        "click text area {text_area}: {:?}",
39        computer.click(APP, ClickTarget::Element(text_area), ClickOptions::default())?
40    );
41    computer.set_value(APP, text_area, "")?;
42    computer.type_text(APP, "Hello from computer-use-rs!\nSecond line.")?;
43
44    let state = computer.get_app_state(APP, &tree_only)?;
45    let value = state.find(&ElementQuery::role("AXTextArea")).next().and_then(|e| e.value.clone());
46    println!("text area now contains: {value:?}");
47
48    computer.select_text(APP, text_area, &TextSelection::new("computer-use-rs"))?;
49    let state = computer.get_app_state(APP, &tree_only)?;
50    println!("selected text: {:?}", state.selected_text);
51
52    computer.press_key(APP, "BackSpace")?;
53    let state = computer.get_app_state(APP, &tree_only)?;
54    let value = state.find(&ElementQuery::role("AXTextArea")).next().and_then(|e| e.value.clone());
55    println!("after BackSpace: {value:?}");
56
57    computer.press_key(APP, "super+a")?;
58    let state = computer.get_app_state(APP, &tree_only)?;
59    println!("after super+a, selected: {:?}", state.selected_text);
60
61    let focused = ClickOptions::default().method(ClickMethod::FocusedBackground);
62    println!("focused click: {:?}", computer.click(APP, ClickTarget::Element(text_area), focused)?);
63    computer.type_text(APP, " The end.")?;
64    let state = computer.get_app_state(APP, &tree_only)?;
65    let value = state.find(&ElementQuery::role("AXTextArea")).next().and_then(|e| e.value.clone());
66    println!("final text: {value:?}");
67
68    Ok(())
69}
Source

pub fn set_value(&mut self, app: &str, index: usize, value: &str) -> Result<()>

Sets the value of a settable element.

§Errors

Fails if the element’s value is read-only.

Examples found in repository?
examples/textedit.rs (line 41)
11fn main() -> computer_use::Result<()> {
12    use std::time::Duration;
13
14    use computer_use::{
15        CaptureOptions, ClickMethod, ClickOptions, ClickTarget, Computer, ElementQuery, Error, TextSelection,
16    };
17
18    const APP: &str = "TextEdit";
19    let mut computer = Computer::new()?.settle_delay(Duration::from_millis(300));
20    let tree_only = CaptureOptions::default().include_screenshot(false);
21
22    let state = computer.get_app_state(APP, &tree_only)?;
23    let new_doc = state.find(&ElementQuery::text("New Document").with_role("button").exact(true)).next();
24    if let Some(button) = new_doc.map(|e| e.index) {
25        println!(
26            "click New Document: {:?}",
27            computer.click(APP, ClickTarget::Element(button), ClickOptions::default())?
28        );
29    }
30
31    let state = computer.get_app_state(APP, &tree_only)?;
32    let text_area = state
33        .find(&ElementQuery::role("AXTextArea"))
34        .next()
35        .map(|e| e.index)
36        .ok_or_else(|| Error::StateUnavailable("no text area".into()))?;
37    println!(
38        "click text area {text_area}: {:?}",
39        computer.click(APP, ClickTarget::Element(text_area), ClickOptions::default())?
40    );
41    computer.set_value(APP, text_area, "")?;
42    computer.type_text(APP, "Hello from computer-use-rs!\nSecond line.")?;
43
44    let state = computer.get_app_state(APP, &tree_only)?;
45    let value = state.find(&ElementQuery::role("AXTextArea")).next().and_then(|e| e.value.clone());
46    println!("text area now contains: {value:?}");
47
48    computer.select_text(APP, text_area, &TextSelection::new("computer-use-rs"))?;
49    let state = computer.get_app_state(APP, &tree_only)?;
50    println!("selected text: {:?}", state.selected_text);
51
52    computer.press_key(APP, "BackSpace")?;
53    let state = computer.get_app_state(APP, &tree_only)?;
54    let value = state.find(&ElementQuery::role("AXTextArea")).next().and_then(|e| e.value.clone());
55    println!("after BackSpace: {value:?}");
56
57    computer.press_key(APP, "super+a")?;
58    let state = computer.get_app_state(APP, &tree_only)?;
59    println!("after super+a, selected: {:?}", state.selected_text);
60
61    let focused = ClickOptions::default().method(ClickMethod::FocusedBackground);
62    println!("focused click: {:?}", computer.click(APP, ClickTarget::Element(text_area), focused)?);
63    computer.type_text(APP, " The end.")?;
64    let state = computer.get_app_state(APP, &tree_only)?;
65    let value = state.find(&ElementQuery::role("AXTextArea")).next().and_then(|e| e.value.clone());
66    println!("final text: {value:?}");
67
68    Ok(())
69}
Source

pub fn select_text( &mut self, app: &str, index: usize, selection: &TextSelection, ) -> Result<()>

Selects text inside a text element, or places the caret before or after it.

§Errors

Fails if the text is missing or ambiguous, or the element does not support selection.

Examples found in repository?
examples/textedit.rs (line 48)
11fn main() -> computer_use::Result<()> {
12    use std::time::Duration;
13
14    use computer_use::{
15        CaptureOptions, ClickMethod, ClickOptions, ClickTarget, Computer, ElementQuery, Error, TextSelection,
16    };
17
18    const APP: &str = "TextEdit";
19    let mut computer = Computer::new()?.settle_delay(Duration::from_millis(300));
20    let tree_only = CaptureOptions::default().include_screenshot(false);
21
22    let state = computer.get_app_state(APP, &tree_only)?;
23    let new_doc = state.find(&ElementQuery::text("New Document").with_role("button").exact(true)).next();
24    if let Some(button) = new_doc.map(|e| e.index) {
25        println!(
26            "click New Document: {:?}",
27            computer.click(APP, ClickTarget::Element(button), ClickOptions::default())?
28        );
29    }
30
31    let state = computer.get_app_state(APP, &tree_only)?;
32    let text_area = state
33        .find(&ElementQuery::role("AXTextArea"))
34        .next()
35        .map(|e| e.index)
36        .ok_or_else(|| Error::StateUnavailable("no text area".into()))?;
37    println!(
38        "click text area {text_area}: {:?}",
39        computer.click(APP, ClickTarget::Element(text_area), ClickOptions::default())?
40    );
41    computer.set_value(APP, text_area, "")?;
42    computer.type_text(APP, "Hello from computer-use-rs!\nSecond line.")?;
43
44    let state = computer.get_app_state(APP, &tree_only)?;
45    let value = state.find(&ElementQuery::role("AXTextArea")).next().and_then(|e| e.value.clone());
46    println!("text area now contains: {value:?}");
47
48    computer.select_text(APP, text_area, &TextSelection::new("computer-use-rs"))?;
49    let state = computer.get_app_state(APP, &tree_only)?;
50    println!("selected text: {:?}", state.selected_text);
51
52    computer.press_key(APP, "BackSpace")?;
53    let state = computer.get_app_state(APP, &tree_only)?;
54    let value = state.find(&ElementQuery::role("AXTextArea")).next().and_then(|e| e.value.clone());
55    println!("after BackSpace: {value:?}");
56
57    computer.press_key(APP, "super+a")?;
58    let state = computer.get_app_state(APP, &tree_only)?;
59    println!("after super+a, selected: {:?}", state.selected_text);
60
61    let focused = ClickOptions::default().method(ClickMethod::FocusedBackground);
62    println!("focused click: {:?}", computer.click(APP, ClickTarget::Element(text_area), focused)?);
63    computer.type_text(APP, " The end.")?;
64    let state = computer.get_app_state(APP, &tree_only)?;
65    let value = state.find(&ElementQuery::role("AXTextArea")).next().and_then(|e| e.value.clone());
66    println!("final text: {value:?}");
67
68    Ok(())
69}

Trait Implementations§

Source§

impl<B: Backend> Debug for Computer<B>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<B> Forget for Computer<B>

§

impl<B> Freeze for Computer<B>
where B: Freeze, HashMap<String, Session<<B as Backend>::Handle>>: Freeze,

§

impl<B> RefUnwindSafe for Computer<B>
where B: RefUnwindSafe, HashMap<String, Session<<B as Backend>::Handle>>: RefUnwindSafe,

§

impl<B> Send for Computer<B>
where B: Send, HashMap<String, Session<<B as Backend>::Handle>>: Send,

§

impl<B> Sync for Computer<B>
where B: Sync, HashMap<String, Session<<B as Backend>::Handle>>: Sync,

§

impl<B> Unpin for Computer<B>
where B: Unpin, HashMap<String, Session<<B as Backend>::Handle>>: Unpin,

§

impl<B> UnsafeUnpin for Computer<B>
where B: UnsafeUnpin, HashMap<String, Session<<B as Backend>::Handle>>: UnsafeUnpin,

§

impl<B> UnwindSafe for Computer<B>
where B: UnwindSafe, HashMap<String, Session<<B as Backend>::Handle>>: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> AutoreleaseSafe for T
where T: ?Sized,

Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.