1 unstable release
Uses new Rust 2024
| 0.1.0 | Jan 23, 2026 |
|---|
#35 in Accessibility
25KB
306 lines
accesskit_xplat
Cross-platform AccessKit adapter similar to accesskit_winit, but without depending on Winit. This allows this crate to be used with any version of Winit without needing a version of crate that matches the version of Winit that you are using (this is particularly helpful for beta or git versions of Winit that don't usually get an accesskit_winit release).
WARNING: The AccessKit developers have noted that the approaches used by both this crates and accesskit_winit may not be the optimal way to implement AccessKit, so use this crate at your own risk. But if you would otherwise be using accesskit_winit then this crate has no additional caveats (except that it requires little bit of extra boilerplate code.)
Example usage
Based on Winit 0.31.0-beta.2's Window and WindowEvent types but could be adapted for other versions of Winit.
use accesskit::Rect;
use accesskit_xplat::{Adapter, EventHandler, WindowEvent as AccessKitEvent};
use raw_window_handle::HasWindowHandle;
use std::sync::Arc;
use winit_core::{
event::WindowEvent,
window::{Window, WindowId},
};
/// State of the accessibility node tree and platform adapter.
pub struct AccessibilityState {
adapter: Adapter,
}
struct Handler {
window_id: WindowId,
// Whatever else you like here. Perhaps EventLoopProxy and/or a channel sender.
}
impl EventHandler for Handler {
fn handle_accesskit_event(&self, event: AccessKitEvent) {
// Your own custom event handling code
}
}
impl AccessibilityState {
pub fn new(window: &dyn Window) -> Self {
let window_id = window.id();
Self {
adapter: Adapter::with_combined_handler(
// On Android, pass `&android_activity::AndroidApp` when creating the `Adapter`
#[cfg(target_os = "android")]
&crate::current_android_app(),
// On all other platforms, pass `RawWindowHandle` when creating the `Adapter`
#[cfg(not(target_os = "android"))]
window.window_handle().unwrap().as_raw(),
Arc::new(Handler { window_id }),
),
}
}
/// Allows reacting to window events.
///
/// This must be called whenever a new window event is received
/// and before it is handled by the application.
pub fn process_window_event(&mut self, window: &dyn Window, event: &WindowEvent) {
match event {
WindowEvent::Focused(is_focused) => {
self.adapter.set_focus(*is_focused);
}
WindowEvent::Moved(_) | WindowEvent::SurfaceResized(_) => {
let outer_position: (_, _) = window
.outer_position()
.unwrap_or_default()
.cast::<f64>()
.into();
let outer_size: (_, _) = window.outer_size().cast::<f64>().into();
let inner_position: (_, _) = window.surface_position().cast::<f64>().into();
let inner_size: (_, _) = window.surface_size().cast::<f64>().into();
self.adapter.set_window_bounds(
Rect::from_origin_size(outer_position, outer_size),
Rect::from_origin_size(inner_position, inner_size),
)
}
_ => (),
}
}
}
Compatibility with async runtimes
The following only applies on Linux/Unix:
While this crate's API is purely blocking, it internally spawns asynchronous tasks on an executor.
- If you use tokio, make sure to enable the
tokiofeature of this crate. - If you use another async runtime or if you don't use one at all, the default feature will suit your needs.
License
This project is licensed under the Apache 2.0 license.
Dependencies
~0.4–35MB
~494K SLoC