forked from intitni/CopilotForXcode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAXNotificationStream.swift
More file actions
76 lines (68 loc) · 2.27 KB
/
AXNotificationStream.swift
File metadata and controls
76 lines (68 loc) · 2.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import AppKit
import ApplicationServices
import Foundation
public final class AXNotificationStream: AsyncSequence {
public typealias Stream = AsyncStream<Element>
public typealias Continuation = Stream.Continuation
public typealias AsyncIterator = Stream.AsyncIterator
public typealias Element = (name: String, info: CFDictionary)
private var continuation: Continuation
private let stream: Stream
public func makeAsyncIterator() -> Stream.AsyncIterator {
stream.makeAsyncIterator()
}
deinit {
continuation.finish()
}
public init(
app: NSRunningApplication,
element: AXUIElement? = nil,
notificationNames: String...
) {
var cont: Continuation!
stream = Stream { continuation in
cont = continuation
}
continuation = cont
var observer: AXObserver?
func callback(
observer: AXObserver,
element: AXUIElement,
notificationName: CFString,
userInfo: CFDictionary,
pointer: UnsafeMutableRawPointer?
) {
guard let pointer = pointer?.assumingMemoryBound(to: Continuation.self)
else { return }
pointer.pointee.yield((notificationName as String, userInfo))
}
_ = AXObserverCreateWithInfoCallback(
app.processIdentifier,
callback,
&observer
)
guard let observer else {
continuation.finish()
return
}
let observingElement = element ?? AXUIElementCreateApplication(app.processIdentifier)
continuation.onTermination = { @Sendable _ in
for name in notificationNames {
AXObserverRemoveNotification(observer, observingElement, name as CFString)
}
CFRunLoopRemoveSource(
CFRunLoopGetMain(),
AXObserverGetRunLoopSource(observer),
.commonModes
)
}
for name in notificationNames {
AXObserverAddNotification(observer, observingElement, name as CFString, &continuation)
}
CFRunLoopAddSource(
CFRunLoopGetMain(),
AXObserverGetRunLoopSource(observer),
.commonModes
)
}
}