11import AppKit
22import ApplicationServices
33import Foundation
4+ import Logger
45
56public final class AXNotificationStream : AsyncSequence {
67 public typealias Stream = AsyncStream < Element >
@@ -18,7 +19,7 @@ public final class AXNotificationStream: AsyncSequence {
1819 deinit {
1920 continuation. finish ( )
2021 }
21-
22+
2223 public convenience init (
2324 app: NSRunningApplication ,
2425 element: AXUIElement ? = nil ,
@@ -72,24 +73,56 @@ public final class AXNotificationStream: AsyncSequence {
7273 . commonModes
7374 )
7475 }
75-
76- Task {
77- for name in notificationNames {
78- var error = AXError . cannotComplete
79- var retryCount = 0
80- while error == AXError . cannotComplete, retryCount < 5 {
81- error = AXObserverAddNotification ( observer, observingElement, name as CFString , & continuation)
82- if error == . cannotComplete {
83- try await Task . sleep ( nanoseconds: 1_000_000_000 )
84- }
85- retryCount += 1
86- }
87- }
76+
77+ Task { [ weak self] in
8878 CFRunLoopAddSource (
8979 CFRunLoopGetMain ( ) ,
9080 AXObserverGetRunLoopSource ( observer) ,
9181 . commonModes
9282 )
83+ var pendingRegistrationNames = Set ( notificationNames)
84+ var retry = 0
85+ while !pendingRegistrationNames. isEmpty, retry < 100 {
86+ guard let self else { return }
87+ retry += 1
88+ for name in notificationNames {
89+ let e = AXObserverAddNotification (
90+ observer,
91+ observingElement,
92+ name as CFString ,
93+ & self . continuation
94+ )
95+ switch e {
96+ case . success:
97+ pendingRegistrationNames. remove ( name)
98+ case . actionUnsupported:
99+ Logger . service. error ( " AXObserver: Action unsupported: \( name) " )
100+ pendingRegistrationNames. remove ( name)
101+ case . apiDisabled:
102+ Logger . service. error ( " AXObserver: Accessibility API disabled, will try again later " )
103+ retry -= 1
104+ case . invalidUIElement:
105+ Logger . service. error ( " AXObserver: Invalid UI element " )
106+ pendingRegistrationNames. remove ( name)
107+ case . invalidUIElementObserver:
108+ Logger . service. error ( " AXObserver: Invalid UI element observer " )
109+ pendingRegistrationNames. remove ( name)
110+ case . cannotComplete:
111+ Logger . service
112+ . error ( " AXObserver: Failed to observe \( name) , will try again later " )
113+ case . notificationUnsupported:
114+ Logger . service. error ( " AXObserver: Notification unsupported: \( name) " )
115+ pendingRegistrationNames. remove ( name)
116+ case . notificationAlreadyRegistered:
117+ pendingRegistrationNames. remove ( name)
118+ default :
119+ Logger . service
120+ . error ( " AXObserver: Unrecognized error \( e) when registering \( name) , will try again later " )
121+ }
122+ }
123+ try await Task . sleep ( nanoseconds: 1_500_000_000 )
124+ }
93125 }
94126 }
95127}
128+
0 commit comments