AXElements/AXElements

View on GitHub
experiments/notifications.rb

Summary

Maintainability
A
0 mins
Test Coverage
framework 'Cocoa'

# make sure the fixture app is running first

workspace   = NSWorkspace.sharedWorkspace
running_app = workspace.runningApplications.find { |app| app.localizedName == 'AXElementsTester' }

app = AXUIElementCreateApplication(running_app.processIdentifier)

def attribute_for element, attr
  ptr = Pointer.new :id
  AXUIElementCopyAttributeValue(element, attr, ptr)
  ptr[0]
end

def children_for element
  attribute_for element, KAXChildrenAttribute
end

window = children_for(app).find do |item|
  attribute_for(item, KAXRoleAttribute) == KAXWindowRole
end

button = children_for(window).find do |item|
  attribute_for(item, KAXRoleAttribute) == KAXButtonRole &&
    attribute_for(item, KAXTitleAttribute) == 'Yes'
end

def make_observer_for pid
  ptr  = Pointer.new '^{__AXObserver}'
  code = AXObserverCreate(pid, Proc.new, ptr)
  ptr[0]
end


button_observer = make_observer_for running_app.processIdentifier do |observer, element, notif, _|
  puts 'button callback'
end
CFShow(button_observer)

app_observer = make_observer_for running_app.processIdentifier do |observer, element, notif, _|
  puts 'app callback'
end
CFShow(app_observer)


CHEEZ = 'Cheezburger'

# technically, we could reuse the same observer
AXObserverAddNotification(app_observer, app, CHEEZ, nil)
# AXObserverAddNotification(button_observer, button, CHEEZ, nil)

puts 'starting'
# have to add the fucking source
run_loop = CFRunLoopGetCurrent()
source   = AXObserverGetRunLoopSource(app_observer)
CFRunLoopAddSource(run_loop, source, KCFRunLoopDefaultMode)
CFRunLoopRunInMode(KCFRunLoopDefaultMode, 10.0, false)

# unregister
# problem?

# try with app
# try with specific element
# do I get the notification once, or is registration forever