computeruse-rs 2.0.0

A Playwright-style SDK for automating desktop GUI applications
use std::time::Duration;
/// Example demonstrating element OCR functionality
///
/// This example shows how to:
/// 1. Open an application (Notepad)
/// 2. Find UI elements
/// 3. Capture screenshots of specific elements and perform OCR
/// 4. Compare different text extraction methods
use computeruse::{AutomationError, Desktop};

#[tokio::main]
async fn main() -> Result<(), AutomationError> {
    println!("๐Ÿ” Element OCR Demo");
    println!("==================");

    // Initialize desktop automation
    let desktop = Desktop::new(false, false)?;

    // Open Notepad for a reliable text-based application
    println!("\n๐Ÿ“ฑ Opening Notepad...");
    let notepad = desktop.open_application("notepad")?;
    std::thread::sleep(Duration::from_millis(2000));

    // Type some text to have content for OCR
    println!("โŒจ๏ธ  Typing sample text...");
    let locator = desktop.locator("role:Document");
    let text_area = locator.first(None).await?;
    text_area.type_text(
        "Hello World!\nThis is a test for OCR functionality.\nLine 3: Special characters @#$%",
        false,
    )?;

    // Wait for text to be rendered
    std::thread::sleep(Duration::from_millis(1000));

    println!("\n๐Ÿ” Testing OCR on different elements:");

    // Test 1: OCR on the text document area
    println!("\n1. OCR on document text area:");
    match text_area.ocr().await {
        Ok(ocr_text) => {
            println!("   โœ… OCR Success!");
            println!("   ๐Ÿ“„ Extracted text: \"{}\"", ocr_text.trim());
            println!("   ๐Ÿ“ Length: {} characters", ocr_text.len());
        }
        Err(e) => {
            println!("   โŒ OCR failed: {e}");
        }
    }

    // Test 2: Compare with native text() method
    println!("\n2. Comparison with native text() method:");
    match text_area.text(3) {
        Ok(native_text) => {
            println!("   โœ… Native text: \"{}\"", native_text.trim());
            println!("   ๐Ÿ“ Length: {} characters", native_text.len());
        }
        Err(e) => {
            println!("   โŒ Native text failed: {e}");
        }
    }

    // Test 3: OCR on the window title bar (should contain "Notepad")
    println!("\n3. OCR on window title bar:");
    let title_locator = desktop.locator("role:TitleBar");
    match title_locator.first(None).await {
        Ok(title_bar) => match title_bar.ocr().await {
            Ok(title_text) => {
                println!("   โœ… Title OCR Success!");
                println!("   ๐Ÿ“„ Title text: \"{}\"", title_text.trim());

                if title_text.to_lowercase().contains("notepad") {
                    println!("   ๐ŸŽฏ Correctly detected 'Notepad' in title!");
                }
            }
            Err(e) => {
                println!("   โŒ Title OCR failed: {e}");
            }
        },
        Err(e) => {
            println!("   โŒ Could not find title bar: {e}");
        }
    }

    // Test 4: OCR on menu items (File, Edit, etc.)
    println!("\n4. OCR on menu items:");
    let menu_locator = desktop.locator("role:MenuBar");
    match menu_locator.first(None).await {
        Ok(menu_bar) => {
            println!("   ๐Ÿ“‹ Found menu bar, testing OCR...");
            match menu_bar.ocr().await {
                Ok(menu_text) => {
                    println!("   โœ… Menu OCR Success!");
                    println!("   ๐Ÿ“„ Menu text: \"{}\"", menu_text.trim());

                    // Check for common menu items
                    let menu_lower = menu_text.to_lowercase();
                    let found_items: Vec<&str> = ["file", "edit", "format", "view", "help"]
                        .iter()
                        .filter(|&&item| menu_lower.contains(item))
                        .copied()
                        .collect();

                    if !found_items.is_empty() {
                        println!("   ๐ŸŽฏ Detected menu items: {found_items:?}");
                    }
                }
                Err(e) => {
                    println!("   โŒ Menu OCR failed: {e}");
                }
            }
        }
        Err(e) => {
            println!("   โŒ Could not find menu bar: {e}");
        }
    }

    // Test 5: Performance comparison
    println!("\n5. Performance comparison:");

    // Time the OCR method
    let start = std::time::Instant::now();
    let _ocr_result = text_area.ocr().await;
    let ocr_duration = start.elapsed();

    // Time just the capture method
    let start = std::time::Instant::now();
    let _capture_result = text_area.capture();
    let capture_duration = start.elapsed();

    println!("   โฑ๏ธ  Capture only: {capture_duration:?}");
    println!("   โฑ๏ธ  OCR (capture + recognition): {ocr_duration:?}");
    println!("   ๐Ÿ“Š OCR overhead: {:?}", ocr_duration - capture_duration);

    // Clean up
    println!("\n๐Ÿงน Cleaning up...");
    notepad.close()?;

    println!("\nโœ… Element OCR demo completed!");
    println!("\n๐Ÿ’ก Key takeaways:");
    println!("   โ€ข Use element.ocr() for extracting text from visual elements");
    println!("   โ€ข OCR works best on clear, well-rendered text");
    println!("   โ€ข Compare with native text() methods when available");
    println!("   โ€ข OCR is particularly useful for elements that don't expose text via accessibility APIs");

    Ok(())
}