1use std::sync::{Arc, OnceLock};
22
23pub use xa11y_core::{
25 App, Element, ElementData, ElementState, Error, Event, EventKind, Locator, RawPlatformData,
26 Rect, Result, Role, StateFlag, StateSet, Subscription, SubscriptionIter, Toggled, TreeNode,
27};
28
29pub use xa11y_core::input;
31pub use xa11y_core::{
32 anchor_point, point_for, Anchor, ClickOptions, ClickTarget, DragOptions, InputProvider,
33 InputSim, IntoPoint, Key, Keyboard, Mouse, MouseButton, Point, ScrollDelta,
34};
35
36pub use xa11y_core::screenshot;
38pub use xa11y_core::{Screenshot, ScreenshotProvider};
39
40pub use xa11y_core::{is_bidi_control, strip_bidi, strip_bidi_opt};
44
45#[doc(hidden)]
47pub use xa11y_core::{CancelHandle, EventReceiver, Provider, RecvStatus, Selector, SelectorGroup};
48
49#[cfg(feature = "test-support")]
53#[doc(hidden)]
54pub use xa11y_core::mock;
55
56#[doc(hidden)]
57pub mod cli;
58
59pub use app_ext::AppExt;
61
62static PROVIDER: OnceLock<std::result::Result<&'static dyn Provider, String>> = OnceLock::new();
65
66fn get_provider_ref() -> Result<&'static dyn Provider> {
67 PROVIDER
68 .get_or_init(|| {
69 create_provider_boxed()
70 .map(|b| &*Box::leak(b))
71 .map_err(|e| format!("{e}"))
72 })
73 .as_ref()
74 .copied()
75 .map_err(|msg| Error::Platform {
76 code: -1,
77 message: msg.clone(),
78 })
79}
80
81#[doc(hidden)]
82pub fn provider() -> Result<Arc<dyn Provider>> {
83 Ok(Arc::new(get_provider_ref()?))
84}
85
86#[doc(hidden)]
89#[cfg(feature = "testing")]
90pub fn create_provider() -> Result<Arc<dyn Provider>> {
91 create_provider_boxed().map(Arc::from)
92}
93
94pub fn input_sim() -> Result<InputSim> {
101 #[cfg(target_os = "macos")]
102 {
103 let backend = xa11y_macos::MacOSInputProvider::new()?;
104 Ok(InputSim::new(Arc::new(backend)))
105 }
106 #[cfg(target_os = "windows")]
107 {
108 let backend = xa11y_windows::WindowsInputProvider::new()?;
109 Ok(InputSim::new(Arc::new(backend)))
110 }
111 #[cfg(target_os = "linux")]
112 {
113 let backend = xa11y_linux::LinuxInputProvider::new()?;
114 Ok(InputSim::new(Arc::new(backend)))
115 }
116 #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))]
117 {
118 Err(Error::Platform {
119 code: -1,
120 message: format!(
121 "Input simulation not available on platform: {}",
122 std::env::consts::OS
123 ),
124 })
125 }
126}
127
128static SCREENSHOT_BACKEND: OnceLock<std::result::Result<Arc<dyn ScreenshotProvider>, String>> =
143 OnceLock::new();
144
145fn screenshot_backend() -> Result<Arc<dyn ScreenshotProvider>> {
146 SCREENSHOT_BACKEND
147 .get_or_init(create_screenshot_backend)
148 .as_ref()
149 .cloned()
150 .map_err(|msg| Error::Platform {
151 code: -1,
152 message: msg.clone(),
153 })
154}
155
156fn create_screenshot_backend() -> std::result::Result<Arc<dyn ScreenshotProvider>, String> {
157 #[cfg(target_os = "macos")]
158 {
159 xa11y_macos::MacOSScreenshot::new()
160 .map(|b| Arc::new(b) as Arc<dyn ScreenshotProvider>)
161 .map_err(|e| format!("{e}"))
162 }
163 #[cfg(target_os = "windows")]
164 {
165 xa11y_windows::WindowsScreenshot::new()
166 .map(|b| Arc::new(b) as Arc<dyn ScreenshotProvider>)
167 .map_err(|e| format!("{e}"))
168 }
169 #[cfg(target_os = "linux")]
170 {
171 xa11y_linux::LinuxScreenshot::new()
172 .map(|b| Arc::new(b) as Arc<dyn ScreenshotProvider>)
173 .map_err(|e| format!("{e}"))
174 }
175 #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))]
176 {
177 Err(format!(
178 "Screenshot not available on platform: {}",
179 std::env::consts::OS
180 ))
181 }
182}
183
184pub fn screenshot() -> Result<Screenshot> {
186 screenshot_backend()?.capture_full()
187}
188
189pub fn screenshot_region(rect: Rect) -> Result<Screenshot> {
191 screenshot_backend()?.capture_region(rect)
192}
193
194pub fn screenshot_element(element: &Element) -> Result<Screenshot> {
199 let rect = element.bounds.ok_or(Error::NoElementBounds)?;
200 screenshot_backend()?.capture_region(rect)
201}
202
203fn create_provider_boxed() -> Result<Box<dyn Provider>> {
204 #[cfg(target_os = "macos")]
205 {
206 Ok(Box::new(xa11y_macos::MacOSProvider::new()?))
207 }
208 #[cfg(target_os = "windows")]
209 {
210 Ok(Box::new(xa11y_windows::WindowsProvider::new()?))
211 }
212 #[cfg(target_os = "linux")]
213 {
214 Ok(Box::new(xa11y_linux::LinuxProvider::new()?))
215 }
216 #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))]
217 {
218 Err(Error::Platform {
219 code: -1,
220 message: format!("Unsupported platform: {}", std::env::consts::OS),
221 })
222 }
223}
224
225mod app_ext {
228 use std::time::Duration;
229
230 use super::{provider, App, Result};
231
232 pub trait AppExt: Sized {
245 fn by_name(name: &str, timeout: Duration) -> Result<Self>;
250 fn by_pid(pid: u32, timeout: Duration) -> Result<Self>;
254 fn list() -> Result<Vec<Self>>;
256 }
257
258 impl AppExt for App {
259 fn by_name(name: &str, timeout: Duration) -> Result<Self> {
260 App::by_name_with(provider()?, name, timeout)
261 }
262
263 fn by_pid(pid: u32, timeout: Duration) -> Result<Self> {
264 App::by_pid_with(provider()?, pid, timeout)
265 }
266
267 fn list() -> Result<Vec<Self>> {
268 App::list_with(provider()?)
269 }
270 }
271}