atspi_client/
accessible_ext.rs1use crate::convertable::{Convertable, ConvertableBlocking};
2use async_trait::async_trait;
3use atspi_common::{AtspiError as Error, MatcherArgs, ObjectPair, RelationType, Role};
4use atspi_proxies::{
5 accessible::{Accessible, AccessibleBlocking, AccessibleProxy, AccessibleProxyBlocking},
6 hyperlink::Hyperlink,
7 text::{Text, TextBlocking},
8};
9use std::collections::HashMap;
10
11#[async_trait]
12pub trait AccessibleExt {
13 type Error: std::error::Error;
14 async fn get_application_ext<'a>(&self) -> Result<Self, Self::Error>
15 where
16 Self: Sized;
17 async fn get_parent_ext<'a>(&self) -> Result<Self, Self::Error>
18 where
19 Self: Sized;
20 async fn get_children_ext<'a>(&self) -> Result<Vec<Self>, Self::Error>
21 where
22 Self: Sized;
23 async fn get_siblings<'a>(&self) -> Result<Vec<Self>, Self::Error>
24 where
25 Self: Sized;
26 async fn get_children_indexes<'a>(&self) -> Result<Vec<i32>, Self::Error>;
27 async fn get_siblings_before<'a>(&self) -> Result<Vec<Self>, Self::Error>
28 where
29 Self: Sized;
30 async fn get_siblings_after<'a>(&self) -> Result<Vec<Self>, Self::Error>
31 where
32 Self: Sized;
33 async fn get_children_caret<'a>(&self, after: bool) -> Result<Vec<Self>, Self::Error>
34 where
35 Self: Sized;
36 async fn get_next<'a>(
39 &self,
40 matcher_args: &MatcherArgs,
41 backward: bool,
42 already_visited: &'a mut Vec<ObjectPair>,
43 ) -> Result<Option<Self>, Self::Error>
44 where
45 Self: Sized;
46 async fn edges<'a>(&self, backward: Option<bool>) -> Result<Vec<Self>, Self::Error>
51 where
52 Self: Sized;
53 async fn get_relation_set_ext<'a>(
54 &self,
55 ) -> Result<HashMap<RelationType, Vec<Self>>, Self::Error>
56 where
57 Self: Sized;
58 async fn match_(
59 &self,
60 matcher_args: &MatcherArgs,
61 ) -> Result<bool, <Self as AccessibleExt>::Error>;
62}
63pub trait AccessibleBlockingExt {}
65
66#[allow(clippy::module_name_repetitions)]
67pub trait AccessibleExtError: Accessible + Convertable {
68 type Error: std::error::Error
69 + From<<Self as Accessible>::Error>
70 + From<<Self as Convertable>::Error>
71 + From<<<Self as Convertable>::Text as Text>::Error>
73 + From<std::num::TryFromIntError>
74 + Send;
75}
76impl AccessibleExtError for AccessibleProxy<'_> {
77 type Error = Error;
78}
79
80#[allow(clippy::module_name_repetitions)]
81pub trait AccessibleBlockingExtError: AccessibleBlocking + ConvertableBlocking {
82 type Error: std::error::Error
83 + From<<Self as AccessibleBlocking>::Error>
84 + From<<Self as ConvertableBlocking>::Error>
85 + From<<<Self as ConvertableBlocking>::Text as TextBlocking>::Error>
87 + From<std::num::TryFromIntError>;
88}
89impl AccessibleBlockingExtError for AccessibleProxyBlocking<'_> {
90 type Error = Error;
91}
92
93#[async_trait]
94impl<T: Accessible + Convertable + AccessibleExtError + Send + Sync + Clone> AccessibleExt for T
95where
96 ObjectPair: for<'c> TryFrom<&'c T>,
97{
98 type Error = <T as AccessibleExtError>::Error;
99 async fn get_application_ext<'a>(&self) -> Result<Self, Self::Error>
100 where
101 Self: Sized,
102 {
103 Ok(self.get_application().await?)
104 }
105 async fn get_parent_ext<'a>(&self) -> Result<Self, Self::Error>
106 where
107 Self: Sized,
108 {
109 Ok(self.parent().await?)
110 }
111 async fn get_children_indexes<'a>(&self) -> Result<Vec<i32>, Self::Error> {
112 let mut indexes = Vec::new();
113 for child in self.get_children_ext().await? {
114 indexes.push(child.get_index_in_parent().await?);
115 }
116 Ok(indexes)
117 }
118 async fn get_children_ext<'a>(&self) -> Result<Vec<Self>, Self::Error>
119 where
120 Self: Sized,
121 {
122 Ok(self.get_children().await?)
123 }
138 async fn get_siblings<'a>(&self) -> Result<Vec<Self>, Self::Error>
139 where
140 Self: Sized,
141 {
142 let parent = self.parent().await?;
143 let pin = self.get_index_in_parent().await?;
144 let index = pin.try_into()?;
145 #[allow(clippy::if_not_else)]
147 let children: Vec<Self> = parent
148 .get_children()
149 .await?
150 .into_iter()
151 .enumerate()
152 .filter_map(|(i, a)| if i != index { Some(a) } else { None })
153 .collect();
154 Ok(children)
155 }
156 async fn get_siblings_before<'a>(&self) -> Result<Vec<Self>, Self::Error>
157 where
158 Self: Sized,
159 {
160 let parent = self.parent().await?;
161 let index = self.get_index_in_parent().await?.try_into()?;
162 let children: Vec<Self> = parent
163 .get_children_ext()
164 .await?
165 .into_iter()
166 .enumerate()
167 .filter_map(|(i, a)| if i < index { Some(a) } else { None })
168 .collect();
169 Ok(children)
170 }
171 async fn get_siblings_after<'a>(&self) -> Result<Vec<Self>, Self::Error>
172 where
173 Self: Sized,
174 {
175 let parent = self.parent().await?;
176 let index = self.get_index_in_parent().await?.try_into()?;
177 let children: Vec<Self> = parent
178 .get_children_ext()
179 .await?
180 .into_iter()
181 .enumerate()
182 .filter_map(|(i, a)| if i > index { Some(a) } else { None })
183 .collect();
184 Ok(children)
185 }
186 async fn get_children_caret<'a>(&self, backward: bool) -> Result<Vec<Self>, Self::Error>
187 where
188 Self: Sized,
189 {
190 let mut children_after_before = Vec::new();
191 let text_iface = self.to_text().await?;
192 let caret_pos = text_iface.caret_offset().await?;
193 let children_hyperlink = self.get_children_ext().await?;
194 for child in children_hyperlink {
195 let hyperlink = child.to_hyperlink().await?;
196 if let Ok(start_index) = hyperlink.start_index().await {
197 if (start_index <= caret_pos && backward) || (start_index >= caret_pos && !backward)
198 {
199 children_after_before.push(child);
200 }
201 } else {
203 children_after_before.push(child);
204 }
205 }
206 Ok(children_after_before)
207 }
208 async fn edges<'a>(&self, backward: Option<bool>) -> Result<Vec<Self>, Self::Error>
209 where
210 Self: Sized,
211 {
212 let mut edge_elements = Vec::new();
213 let children = match backward {
214 Some(backward) => {
215 if let Ok(caret_children) = self.get_children_caret(backward).await {
216 caret_children
217 } else {
218 self.get_children().await?
219 }
220 }
221 None => self.get_children().await?,
222 };
223 children.into_iter().for_each(|child| edge_elements.push(child));
224 let siblings = match backward {
225 Some(false) => self.get_siblings_before().await?,
226 Some(true) => self.get_siblings_after().await?,
227 None => self.get_siblings().await?,
228 };
229 siblings.into_iter().for_each(|sibling| edge_elements.push(sibling));
230 let parent = self.get_parent_ext().await?;
231 edge_elements.push(parent);
232 Ok(edge_elements)
233 }
234 async fn get_next<'a>(
235 &self,
236 matcher_args: &MatcherArgs,
237 backward: bool,
238 visited: &'a mut Vec<ObjectPair>,
239 ) -> Result<Option<Self>, Self::Error>
240 where
241 Self: Sized,
242 {
243 let mut stack: Vec<T> = Vec::new();
244 let edges = self.edges(Some(backward)).await?;
245 edges.into_iter().for_each(|edge| stack.push(edge));
246 while let Some(item) = stack.pop() {
247 let Ok(identifier) = ObjectPair::try_from(&item) else {
249 return Ok(None);
250 };
251 if visited.contains(&identifier) {
253 continue;
254 }
255 visited.push(identifier);
256 if item.get_role().await? == Role::InternalFrame {
257 return Ok(None);
258 }
259 if item.match_(matcher_args).await? {
261 return Ok(Some(item));
262 }
263 self.edges(Some(backward))
265 .await?
266 .into_iter()
267 .for_each(|edge| stack.push(edge));
268 }
269 return Ok(None);
270 }
271 async fn get_relation_set_ext<'a>(
272 &self,
273 ) -> Result<HashMap<RelationType, Vec<Self>>, Self::Error>
274 where
275 Self: Sized,
276 {
277 let raw_relations = self.get_relation_set().await?;
278 let mut relations = HashMap::new();
279 for relation in raw_relations {
280 let mut related_vec = Vec::new();
281 for related in relation.1 {
282 related_vec.push(related);
283 }
284 relations.insert(relation.0, related_vec);
285 }
286 Ok(relations)
287 }
288 async fn match_(
290 &self,
291 matcher_args: &MatcherArgs,
292 ) -> Result<bool, <Self as AccessibleExt>::Error> {
293 let roles = &matcher_args.0;
294 if roles.len() != 1 {
295 return Ok(false);
296 }
297 Ok(self.get_role().await? == *roles.get(0).unwrap())
299 }
300}
301
302impl<T: AccessibleBlocking + ConvertableBlocking + AccessibleBlockingExtError> AccessibleBlockingExt
303 for T
304{
305}
306
307assert_impl_all!(AccessibleProxy: Accessible, AccessibleExt);
308assert_impl_all!(AccessibleProxyBlocking: AccessibleBlocking, AccessibleBlockingExt);