From the previous article, we believe that you should use AXUIElement of the Accessibility API. Today we will continue the article for the second time. This time we will introduce AXObserver, which can be monitored by specific Key values. For example, the size and position of the window change.
AXObserver
As you can see from apple’s official documentation, there are two ways to create an AXObserver:
1.public func AXObserverCreate(_ application: pid_t, _ callback: AXObserverCallback, _ outObserver: UnsafeMutablePointer<AXObserver? >) -> AXError 2.public func AXObserverCreateWithInfoCallback(_ application: pid_t, _ callback: AXObserverCallbackWithInfo, _ outObserver: UnsafeMutablePointer<AXObserver? >) -> AXErrorCopy the code
From this point of view, the following elements are required to successfully create an AXObserver
- Pid: indicates the ID of a program process
- Callback: Callback used to receive listening. Is a closure type. There are two types of callback
AXObserverCallback
The other isAXObserverCallbackWithInfo
- OutObserver: Object of type inout, used for receiving
AXObserver
- AXError: This is the return value used to determine your
AXObserver
Whether it was successfully created.
So for callback AXObserverCallback callback types and AXObserverCallbackWithInfo what difference does it make? Let’s start with the definition in the official documentation
1. public typealias AXObserverCallback = @convention(c) (AXObserver, AXUIElement, CFString, UnsafeMutableRawPointer?) -> Void
2. public typealias AXObserverCallbackWithInfo = @convention(c) (AXObserver, AXUIElement, CFString, CFDictionary, UnsafeMutableRawPointer?) -> Void
Copy the code
From the official document, we can find the closure is no return, but almost the same parameters, than just AXObserverCallbackWithInfo AXObserverCallback CFDictionary item to a dictionary
- AXObserver: This is the AXObserver object that you are listening to
- AXUIElement: This is the AXUIElement object being listened on
- CFString: This is the key of the listening object, in fact, the key of the behavior of the object you want to listen to
- UnsafeMutableRawPointer? : This is the caller and can be nil
- CFDictionary: only AXObserverCallbackWithInfo this has, in fact is the same and the userInfo in our NSNotification.
That’s it. Let’s go to the code
Define the CallBack
AXObserverCallback
let _observerCallback:AXObserverCallback = { (observer, element, notification, refcon) in
print("AXObserverCallback did called")
}
Copy the code
AXObserverCallbackWithInfo
let _observerCallbackWithInfo: AXObserverCallbackWithInfo = { (observer, element, notification, userInfo, refcon)
print("it will called when element did modify")
}
Copy the code
createAXObserver
object
AXObserver created through AXObserverCallback
var observer : AXObserver?
let error:AXError = AXObserverCreate(pid, _observerCallback, &observer)
Copy the code
Created by AXObserverCallbackWithInfo AXObserver
var observer : AXObserver?
let error:AXError = AXObserverCreateWithInfoCallback(pid, _observerCallbackWithInfo, &observer)
Copy the code
Add notification
let selfPtr = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())
let error : AXError = AXObserverAddNotification(observer, element, kAXWindowMovedNotification, selfPtr)
Copy the code
This is key the Observer kAXWindowMovedNotification. Specific can consult AXNotificationConstants. H
After adding the notification, we need to add it to the RunLoop:
CFRunLoopAddSource(CFRunLoopGetCurrent(), observer.runLoopSource(), CFRunLoopMode.defaultMode)
Copy the code
Remove the notification
First we remove the RunLoop
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), observer.runLoopSource(), CFRunLoopMode.defaultMode)
Copy the code
Then remove the notification for Key
let error : AXError = AXObserverRemoveNotification(observer, element, kAXWindowMovedNotification)
Copy the code
Notifications and callbacksrefcon: UnsafeMutableRawPointer?
The Get&Set
Refcon: UnsafeMutableRawPointer?
1. public func AXObserverAddNotification(_ observer: AXObserver, _ element: AXUIElement, _ notification: CFString,_ refcon: UnsafeMutableRawPointer?) -> AXError
2. public typealias AXObserverCallback = @convention(c) (AXObserver, AXUIElement, CFString, UnsafeMutableRawPointer?) -> Void
Copy the code
So how do we pass in values and values?
When a function needs to pass a value, it needs to convert:
//self is the object you want to pass, SelfPtr = UnsafeMutableRawPointer(unmanaged.passunretained (self).toopaque ()) let error : AXError = AXObserverAddNotification(observer, element, kAXWindowMovedNotification, selfPtr)Copy the code
So how do you value it in a callback? It also needs a switch:
let _observerCallbackWithInfo: AXObserverCallbackWithInfo = {(observer, element, notification, the userInfo, refcon) in the if let ref = refcon {/ / because at the time of transfer value, I passed in self(which is actually the ViewController object), so when I converted it would be ViewController let obj: ViewController = Unmanaged<ViewController>.fromOpaque(ref).takeUnretainedValue() obj.observerLogView.string += log } }Copy the code