1#![doc = include_str!("../README.md")]
2
3use accesskit::{NodeClassSet, NodeId, Tree, TreeUpdate};
4use fltk::{enums::*, prelude::*, *};
5use std::num::NonZeroU128;
6
7pub mod accessible;
8mod fltk_adapter;
9mod platform_adapter;
10
11pub use accessible::Accessible;
12pub use fltk_adapter::{ActionRequestEvent, Adapter};
13
14pub struct AccessibilityContext {
15 adapter: Adapter,
16 root: window::Window,
17 widgets: Vec<Box<dyn Accessible>>,
18 nc: NodeClassSet,
19}
20
21impl AccessibilityContext {
22 pub fn new(root: window::Window, mut widgets: Vec<Box<dyn Accessible>>) -> Self {
23 let mut nc = NodeClassSet::new();
24 let mut wids = vec![];
25 for w in &widgets {
26 let n = w.make_node(&mut nc, &[]);
27 wids.push(n);
28 }
29 let (win_id, win_node) =
30 root.make_node(&mut nc, &wids.iter().map(|x| x.0).collect::<Vec<_>>());
31 wids.push((win_id, win_node));
32 let adapter = {
33 Adapter::new(&root, move || TreeUpdate {
34 nodes: wids,
35 tree: Some(Tree::new(win_id)),
36 focus: if let Some(focused) = app::focus() {
37 let focused = focused.as_widget_ptr() as usize as u128;
38 Some(NodeId(unsafe { NonZeroU128::new_unchecked(focused) }))
39 } else {
40 None
41 },
42 })
43 };
44 widgets.push(Box::new(root.clone()));
45 Self {
46 adapter,
47 root,
48 widgets,
49 nc,
50 }
51 }
52}
53
54pub trait AccessibleApp {
55 fn run_with_accessibility(&self, ac: AccessibilityContext) -> Result<(), FltkError>;
56}
57
58impl AccessibleApp for app::App {
59 fn run_with_accessibility(&self, mut ac: AccessibilityContext) -> Result<(), FltkError> {
60 ac.root.handle({
61 let adapter = ac.adapter.clone();
62 move |w, ev| {
63 let adapter = adapter.clone();
64 match ev {
65 Event::KeyUp => {
66 let mut wids = vec![];
68 for w in &ac.widgets {
69 let n = w.make_node(&mut ac.nc, &[]);
70 wids.push(n);
71 }
72 let (win_id, win_node) =
73 w.make_node(&mut ac.nc, &wids.iter().map(|x| x.0).collect::<Vec<_>>());
74 wids.push((win_id, win_node));
75 if let Some(focused) = app::focus() {
76 let focused = focused.as_widget_ptr() as usize as u128;
77 let node_id = NodeId(unsafe { NonZeroU128::new_unchecked(focused) });
78 adapter.update_if_active(|| TreeUpdate {
79 nodes: wids,
80 tree: None,
81 focus: Some(node_id),
82 });
83 }
84 false
86 }
87 _ => false,
88 }
89 }
90 });
91 self.run()
92 }
93}