Skip to content

Commit

Permalink
fix: send a11y tree after actions
Browse files Browse the repository at this point in the history
this ensures focus is updated correctly
  • Loading branch information
wash2 committed Nov 22, 2024
1 parent 1b9116a commit 49d90ae
Showing 1 changed file with 99 additions and 93 deletions.
192 changes: 99 additions & 93 deletions winit/src/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,7 @@ async fn run_instance<'a, P, C>(
let Some(event) = event else {
break;
};
let mut rebuild_a11y_tree = false;

Check warning on line 805 in winit/src/program.rs

View workflow job for this annotation

GitHub Actions / web

variable `rebuild_a11y_tree` is assigned to, but never used

Check warning on line 805 in winit/src/program.rs

View workflow job for this annotation

GitHub Actions / web

variable `rebuild_a11y_tree` is assigned to, but never used

Check warning on line 805 in winit/src/program.rs

View workflow job for this annotation

GitHub Actions / wasm

variable `rebuild_a11y_tree` is assigned to, but never used

Check warning on line 805 in winit/src/program.rs

View workflow job for this annotation

GitHub Actions / wasm

variable `rebuild_a11y_tree` is assigned to, but never used

match event {
Event::StartDnd => {
Expand Down Expand Up @@ -1097,6 +1098,7 @@ async fn run_instance<'a, P, C>(
is_window_opening = false;
}
Event::UserEvent(action) => {
rebuild_a11y_tree = true;

Check warning on line 1101 in winit/src/program.rs

View workflow job for this annotation

GitHub Actions / web

value assigned to `rebuild_a11y_tree` is never read

Check warning on line 1101 in winit/src/program.rs

View workflow job for this annotation

GitHub Actions / web

value assigned to `rebuild_a11y_tree` is never read
let exited = run_action(
action,
&program,
Expand Down Expand Up @@ -1130,6 +1132,18 @@ async fn run_instance<'a, P, C>(
}
}
Event::Winit(window_id, event) => {
#[cfg(feature = "a11y")]
{
if let Some((id, window)) =
window_manager.get_mut_alias(window_id)
{
if let Some(Some((_, adapter))) =
a11y_enabled.then(|| adapters.get_mut(&id))
{
adapter.process_event(window.raw.as_ref(), &event);
};
}
}
match event {
event::WindowEvent::RedrawRequested => {
let Some((id, window)) =
Expand Down Expand Up @@ -1240,99 +1254,6 @@ async fn run_instance<'a, P, C>(
.expect("Remove user interface")
.relayout(logical_size, &mut window.renderer);

#[cfg(feature = "a11y")]
{
use iced_accessibility::{
accesskit::{
NodeBuilder, NodeId, Role, Tree,
TreeUpdate,
},
A11yId, A11yNode, A11yTree,
};
if let Some(Some((a11y_id, adapter))) =
a11y_enabled.then(|| adapters.get_mut(&id))
{
// TODO cleanup duplication
let child_tree =
ui.a11y_nodes(window.state.cursor());
let mut root =
NodeBuilder::new(Role::Window);
root.set_name(
window.state.title.to_string(),
);
let window_tree =
A11yTree::node_with_child_tree(
A11yNode::new(root, *a11y_id),
child_tree,
);
let tree = Tree::new(NodeId(*a11y_id));

let focus =
Arc::new(std::sync::Mutex::new(None));
let focus_clone = focus.clone();
let operation: Box<dyn Operation<()>> =
Box::new(operation::map(
Box::new(
operation::focusable::find_focused(
),
),
move |id| {
let mut guard = focus.lock().unwrap();
_ = guard.replace(id);
},
));
let mut current_operation = Some(operation);

while let Some(mut operation) =
current_operation.take()
{
ui.operate(
&window.renderer,
operation.as_mut(),
);

match operation.finish() {
operation::Outcome::None => {}
operation::Outcome::Some(()) => {
break;
}
operation::Outcome::Chain(next) => {
current_operation = Some(next);
}
}
}
let mut guard = focus_clone.lock().unwrap();
let focus = guard
.take()
.map(|id| A11yId::Widget(id));
tracing::debug!(
"focus: {:?}\ntree root: {:?}\n children: {:?}",
&focus,
window_tree
.root()
.iter()
.map(|n| (n.node().role(), n.id()))
.collect::<Vec<_>>(),
window_tree
.children()
.iter()
.map(|n| (n.node().role(), n.id()))
.collect::<Vec<_>>()
);
let focus = focus
.filter(|f_id| {
window_tree.contains(f_id)
})
.map(|id| id.into())
.unwrap_or_else(|| tree.root);
adapter.update_if_active(|| TreeUpdate {
nodes: window_tree.into(),
tree: Some(tree),
focus,
});
}
}

let _ = user_interfaces.insert(id, ui);
debug.layout_finished();

Expand Down Expand Up @@ -1658,6 +1579,7 @@ async fn run_instance<'a, P, C>(

window.request_redraw();
}
rebuild_a11y_tree = true;

Check warning on line 1582 in winit/src/program.rs

View workflow job for this annotation

GitHub Actions / web

value assigned to `rebuild_a11y_tree` is never read

Check warning on line 1582 in winit/src/program.rs

View workflow job for this annotation

GitHub Actions / web

value assigned to `rebuild_a11y_tree` is never read

user_interfaces = ManuallyDrop::new(build_user_interfaces(
&program,
Expand Down Expand Up @@ -1807,6 +1729,7 @@ async fn run_instance<'a, P, C>(
}
#[cfg(feature = "a11y")]
Event::Accessibility(id, e) => {
rebuild_a11y_tree = true;
match e.action {
iced_accessibility::accesskit::Action::Focus => {
// TODO send a command for this
Expand Down Expand Up @@ -1838,6 +1761,89 @@ async fn run_instance<'a, P, C>(
// log ignored events?
}
}
#[cfg(feature = "a11y")]
{
use iced_accessibility::{
accesskit::{NodeBuilder, NodeId, Role, Tree, TreeUpdate},
A11yId, A11yNode, A11yTree,
};
if !a11y_enabled || !rebuild_a11y_tree {
continue;
}

for id in window_manager.ids() {
let Some((a11y_id, adapter)) = adapters.get_mut(&id) else {
continue;
};
let Some(window) = window_manager.get(id) else {
continue;
};
let interface =
user_interfaces.get_mut(&id).expect("Get user interface");

// TODO cleanup duplication
let child_tree = interface.a11y_nodes(window.state.cursor());
let mut root = NodeBuilder::new(Role::Window);
root.set_name(window.state.title.to_string());
let window_tree = A11yTree::node_with_child_tree(
A11yNode::new(root, *a11y_id),
child_tree,
);
let tree = Tree::new(NodeId(*a11y_id));

let focus = Arc::new(std::sync::Mutex::new(None));
let focus_clone = focus.clone();
let operation: Box<dyn Operation<()>> =
Box::new(operation::map(
Box::new(operation::focusable::find_focused()),
move |id| {
let mut guard = focus.lock().unwrap();
_ = guard.replace(id);
},
));
let mut current_operation = Some(operation);

while let Some(mut operation) = current_operation.take() {
interface.operate(&window.renderer, operation.as_mut());

match operation.finish() {
operation::Outcome::None => {}
operation::Outcome::Some(()) => {
break;
}
operation::Outcome::Chain(next) => {
current_operation = Some(next);
}
}
}
let mut guard = focus_clone.lock().unwrap();
let focus = guard
.take()
.map(|id| A11yId::Widget(id))
.filter(|f_id| window_tree.contains(f_id));
tracing::debug!(
"tree root: {:?}\nchildren: {:?}\nfocus: {:?}\n",
window_tree
.root()
.iter()
.map(|n| (n.node(), n.id()))
.collect::<Vec<_>>(),
window_tree
.children()
.iter()
.map(|n| (n.node(), n.id()))
.collect::<Vec<_>>(),
&focus,
);
let focus =
focus.map(|id| id.into()).unwrap_or_else(|| tree.root);
adapter.update_if_active(|| TreeUpdate {
nodes: window_tree.into(),
tree: Some(tree),
focus,
});
}
}
}

let _ = ManuallyDrop::into_inner(user_interfaces);
Expand Down

0 comments on commit 49d90ae

Please sign in to comment.