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

  1. Pid: indicates the ID of a program process
  2. Callback: Callback used to receive listening. Is a closure type. There are two types of callbackAXObserverCallbackThe other isAXObserverCallbackWithInfo
  3. OutObserver: Object of type inout, used for receivingAXObserver
  4. AXError: This is the return value used to determine yourAXObserverWhether 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

  1. AXObserver: This is the AXObserver object that you are listening to
  2. AXUIElement: This is the AXUIElement object being listened on
  3. CFString: This is the key of the listening object, in fact, the key of the behavior of the object you want to listen to
  4. UnsafeMutableRawPointer? : This is the caller and can be nil
  5. 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

createAXObserverobject

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