Skip to content

Commit cba6a94

Browse files
authored
Merge pull request #25 from crowecawcaw/claude/update-xa11y-library-1zTfU
Update to xa11y 0.7: native screenshot, click, keyboard support
2 parents 83619a8 + b9c63d3 commit cba6a94

10 files changed

Lines changed: 296 additions & 918 deletions

File tree

Cargo.lock

Lines changed: 140 additions & 93 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,7 @@ serde = { version = "1", features = ["derive"] }
1212
serde_json = "1"
1313
dirs = "6"
1414
anyhow = "1"
15-
xa11y = "0.6"
16-
17-
# macOS platform helpers (screenshots, window bounds) — NOT for accessibility
18-
[target.'cfg(target_os = "macos")'.dependencies]
19-
core-foundation = "0.10.1"
15+
xa11y = "0.7"
2016

2117
[features]
2218
e2e = []

src/commands/screenshot.rs

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,37 @@
11
use anyhow::{Context, Result};
2-
3-
use crate::platform;
2+
use xa11y::{App, AppExt, Role};
43

54
pub fn run_screenshot(output_path: &str, scale: f64, app: Option<&str>, pid: Option<u32>) -> Result<()> {
6-
if app.is_some() || pid.is_some() {
7-
platform::take_screenshot_window(output_path, app, pid)?;
5+
let shot = if app.is_some() || pid.is_some() {
6+
let xa_app = match (pid, app) {
7+
(Some(p), _) => App::by_pid(p).map_err(|e| anyhow::anyhow!("{}", e))?,
8+
(None, Some(name)) => App::by_name(name).map_err(|e| anyhow::anyhow!("{}", e))?,
9+
_ => unreachable!(),
10+
};
11+
let window = xa_app
12+
.children()
13+
.map_err(|e| anyhow::anyhow!("{}", e))?
14+
.into_iter()
15+
.find(|e| matches!(e.data().role, Role::Window))
16+
.ok_or_else(|| anyhow::anyhow!("No window found for the specified app"))?;
17+
xa11y::screenshot_element(&window)
18+
.map_err(|e| anyhow::anyhow!("Screenshot failed: {}", e))?
819
} else {
9-
platform::take_screenshot(output_path)?;
10-
}
20+
xa11y::screenshot().map_err(|e| anyhow::anyhow!("Screenshot failed: {}", e))?
21+
};
1122

1223
if (scale - 1.0).abs() > 1e-9 {
13-
let img = image::open(output_path).context("Failed to open captured screenshot")?;
14-
let (w, h) = (img.width(), img.height());
15-
let new_w = (w as f64 * scale) as u32;
16-
let new_h = (h as f64 * scale) as u32;
17-
let resized = img.resize_exact(new_w, new_h, image::imageops::FilterType::Lanczos3);
18-
resized
24+
let rgba = image::RgbaImage::from_raw(shot.width, shot.height, shot.pixels)
25+
.ok_or_else(|| anyhow::anyhow!("Invalid screenshot pixel data"))?;
26+
let new_w = ((shot.width as f64) * scale) as u32;
27+
let new_h = ((shot.height as f64) * scale) as u32;
28+
image::DynamicImage::ImageRgba8(rgba)
29+
.resize_exact(new_w, new_h, image::imageops::FilterType::Lanczos3)
1930
.save(output_path)
2031
.context("Failed to save scaled screenshot")?;
32+
} else {
33+
shot.save_png(output_path)
34+
.map_err(|e| anyhow::anyhow!("Failed to save screenshot: {}", e))?;
2135
}
2236

2337
println!("Screenshot saved to {}", output_path);

src/commands/scroll.rs

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use anyhow::{Context, Result};
1+
use anyhow::Result;
22

33
use crate::platform;
44
use crate::state::AppState;
@@ -10,7 +10,6 @@ pub fn run_scroll(
1010
direction: &str,
1111
amount: Option<u32>,
1212
) -> Result<()> {
13-
// Validate direction
1413
match direction {
1514
"up" | "down" | "left" | "right" => {}
1615
_ => anyhow::bail!(
@@ -19,21 +18,17 @@ pub fn run_scroll(
1918
),
2019
}
2120

22-
// If element specified, move mouse to its center
23-
if let Some(eid) = element_id {
21+
// Resolve element center to use as the scroll target point.
22+
let at = if let Some(eid) = element_id {
2423
let state = AppState::load()?;
2524
let elem = state.get_element(eid)?;
26-
if let Some(ref bounds) = elem.bounds {
27-
let (x, y) = bounds.center();
28-
platform::move_mouse(x, y).context(format!(
29-
"Failed to move mouse to element {} at ({}, {})",
30-
eid, x, y
31-
))?;
32-
}
33-
}
25+
elem.bounds.as_ref().map(|b| b.center())
26+
} else {
27+
None
28+
};
3429

3530
let scroll_amount = amount.unwrap_or(DEFAULT_SCROLL_AMOUNT);
36-
platform::scroll(direction, scroll_amount)?;
31+
platform::scroll(direction, scroll_amount, at)?;
3732

3833
if let Some(eid) = element_id {
3934
println!("Scrolled {} {} clicks in element {}", direction, scroll_amount, eid);

src/platform/accessibility/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ fn map_xa11y_error(e: xa11y::Error) -> anyhow::Error {
430430
}
431431

432432
/// Detect screen resolution using platform-specific tools.
433-
fn get_screen_size() -> (u32, u32) {
433+
pub fn get_screen_size() -> (u32, u32) {
434434
#[cfg(target_os = "linux")]
435435
{
436436
if let Some(size) = get_screen_size_linux() {

0 commit comments

Comments
 (0)