33// the LICENSE-APACHE file) or the MIT license (found in
44// the LICENSE-MIT file), at your option.
55
6- use accesskit:: NodeId ;
6+ use accesskit:: { Live , NodeId } ;
77use accesskit_consumer:: { DetachedNode , FilterResult , Node , TreeChangeHandler , TreeState } ;
8- use objc2:: foundation:: NSString ;
8+ use objc2:: {
9+ foundation:: { NSInteger , NSMutableDictionary , NSNumber , NSObject , NSString } ,
10+ msg_send, Message ,
11+ } ;
912use std:: rc:: Rc ;
1013
1114use crate :: {
1215 appkit:: * ,
1316 context:: Context ,
14- node:: { filter, NodeWrapper } ,
17+ node:: { filter, filter_detached , NodeWrapper } ,
1518} ;
1619
20+ // Workaround for https://github.com/madsmtm/objc2/issues/306
21+ fn set_object_for_key < K : Message , V : Message > (
22+ dictionary : & mut NSMutableDictionary < K , V > ,
23+ value : & V ,
24+ key : & K ,
25+ ) {
26+ let _: ( ) = unsafe { msg_send ! [ dictionary, setObject: value, forKey: key] } ;
27+ }
28+
1729// This type is designed to be safe to create on a non-main thread
1830// and send to the main thread. This ability isn't yet used though.
1931pub ( crate ) enum QueuedEvent {
@@ -22,9 +34,24 @@ pub(crate) enum QueuedEvent {
2234 notification : & ' static NSString ,
2335 } ,
2436 NodeDestroyed ( NodeId ) ,
37+ Announcement {
38+ text : String ,
39+ priority : NSInteger ,
40+ } ,
2541}
2642
2743impl QueuedEvent {
44+ fn live_region_announcement ( node : & Node ) -> Self {
45+ Self :: Announcement {
46+ text : node. name ( ) . unwrap ( ) ,
47+ priority : if node. live ( ) == Live :: Assertive {
48+ NSAccessibilityPriorityHigh
49+ } else {
50+ NSAccessibilityPriorityMedium
51+ } ,
52+ }
53+ }
54+
2855 fn raise ( self , context : & Rc < Context > ) {
2956 match self {
3057 Self :: Generic {
@@ -44,6 +71,39 @@ impl QueuedEvent {
4471 } ;
4572 }
4673 }
74+ Self :: Announcement { text, priority } => {
75+ let view = match context. view . load ( ) {
76+ Some ( view) => view,
77+ None => {
78+ return ;
79+ }
80+ } ;
81+
82+ let window = match view. window ( ) {
83+ Some ( window) => window,
84+ None => {
85+ return ;
86+ }
87+ } ;
88+
89+ let mut user_info = NSMutableDictionary :: < _ , NSObject > :: new ( ) ;
90+ let text = NSString :: from_str ( & text) ;
91+ set_object_for_key ( & mut user_info, & * text, unsafe {
92+ NSAccessibilityAnnouncementKey
93+ } ) ;
94+ let priority = NSNumber :: new_isize ( priority) ;
95+ set_object_for_key ( & mut user_info, & * priority, unsafe {
96+ NSAccessibilityPriorityKey
97+ } ) ;
98+
99+ unsafe {
100+ NSAccessibilityPostNotificationWithUserInfo (
101+ & window,
102+ NSAccessibilityAnnouncementRequestedNotification ,
103+ & user_info,
104+ )
105+ } ;
106+ }
47107 }
48108 }
49109}
@@ -91,8 +151,14 @@ impl EventGenerator {
91151}
92152
93153impl TreeChangeHandler for EventGenerator {
94- fn node_added ( & mut self , _node : & Node ) {
95- // TODO: text changes, live regions
154+ fn node_added ( & mut self , node : & Node ) {
155+ if filter ( node) != FilterResult :: Include {
156+ return ;
157+ }
158+ if node. name ( ) . is_some ( ) && node. live ( ) != Live :: Off {
159+ self . events
160+ . push ( QueuedEvent :: live_region_announcement ( node) ) ;
161+ }
96162 }
97163
98164 fn node_updated ( & mut self , old_node : & DetachedNode , new_node : & Node ) {
@@ -124,6 +190,15 @@ impl TreeChangeHandler for EventGenerator {
124190 notification : unsafe { NSAccessibilitySelectedTextChangedNotification } ,
125191 } ) ;
126192 }
193+ if new_node. name ( ) . is_some ( )
194+ && new_node. live ( ) != Live :: Off
195+ && ( new_node. name ( ) != old_node. name ( )
196+ || new_node. live ( ) != old_node. live ( )
197+ || filter_detached ( old_node) != FilterResult :: Include )
198+ {
199+ self . events
200+ . push ( QueuedEvent :: live_region_announcement ( new_node) ) ;
201+ }
127202 }
128203
129204 fn focus_moved ( & mut self , _old_node : Option < & DetachedNode > , new_node : Option < & Node > ) {
@@ -139,7 +214,6 @@ impl TreeChangeHandler for EventGenerator {
139214 }
140215
141216 fn node_removed ( & mut self , node : & DetachedNode , _current_state : & TreeState ) {
142- // TODO: text changes
143217 self . events . push ( QueuedEvent :: NodeDestroyed ( node. id ( ) ) ) ;
144218 }
145219}
0 commit comments