Skip to content

Simple example for atspi/unix? #633

@C-Loftus

Description

@C-Loftus

Thank you for the great work on accesskit

I was trying to investigate contributing a simple quickstart example for unix with atspi since I am reasonably familiar with atspi itself, but can't seem to figure out how to get the unix adapter working.

The code at the end of this issue compiles and prints fine to stdout but Orca does not speak the announcement and I do not see any accessibility info in the acceserciser GUI on Linux.

I am on Ubuntu 24.04 with Orca v49, I am running the example in X11 from a separate terminal and there shouldn't be any app armor / sandboxing stuff interfering. I am unclear if this is related perhaps to #328 in some way?

Apologies if I am missing something obvious but I feel I am a bit stuck. I assumed that I could just do no-ops for the ActionHandler since I just want it to initialize the tree and make the announcement.

use accesskit::{
    ActionHandler, ActionRequest, ActivationHandler, DeactivationHandler, Live, Node, NodeId, Role, Tree, TreeUpdate,
};
use accesskit_unix::Adapter;

const ROOT_ID: NodeId = NodeId(0);
const ANNOUNCEMENT_ID: NodeId = NodeId(1);

struct MyActivationHandler;
struct MyActionHandler;
struct MyDeactivationHandler;

fn build_announcement(text: &str) -> Node {
    let mut node = Node::new(Role::Label);
    node.set_value(text);
    node.set_live(Live::Assertive);
    node
}

impl ActivationHandler for MyActivationHandler {
    fn request_initial_tree(&mut self) -> Option<TreeUpdate> {

        let mut root = Node::new(Role::Label);
        root.set_children(vec![ANNOUNCEMENT_ID]);

        let tree = Tree::new(ROOT_ID);
        Some(TreeUpdate {
            nodes: vec![
                (ROOT_ID, root),
                (ANNOUNCEMENT_ID, build_announcement("Hello world")),
            ],
            tree: Some(tree),
            focus: ROOT_ID,
        })
    }
}

impl ActionHandler for MyActionHandler {
    fn do_action(&mut self, request: ActionRequest) {
        println!("Action: {:?}", request);
    }
}

impl DeactivationHandler for MyDeactivationHandler {
    fn deactivate_accessibility(&mut self) {
        println!("Accessibility deactivated");
    }
}

fn main() {
    let mut adapter = Adapter::new(
        MyActivationHandler,
        MyActionHandler,
        MyDeactivationHandler,
    );

    // Send initial tree unconditionally
    adapter.update_if_active(|| MyActivationHandler.request_initial_tree().unwrap());

    println!("Adapter initialized successfully!");

    // Simulate updating the live region later
    std::thread::sleep(std::time::Duration::from_secs(2));
    adapter.update_if_active(|| TreeUpdate {
        nodes: vec![(ANNOUNCEMENT_ID, build_announcement("Hello, world again!"))],
        tree: None,
        focus: ROOT_ID,
    });

    println!("Announcement updated!");
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions