Skip to content

Instantly share code, notes, and snippets.

@leiless
Last active February 22, 2019 13:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save leiless/94ed1ec405fe149918ff5a3207bac704 to your computer and use it in GitHub Desktop.
Save leiless/94ed1ec405fe149918ff5a3207bac704 to your computer and use it in GitHub Desktop.
Fetch AXUIElement attribute's value from a given path
/**
* Fetch AXUIElement attribute's value from a given path
* @attributePath Parent-child path string
* Example: "AXMenuBar"
* "AXFocusedWindow, AXDocument"
* "AXFocusedWindow, AXCloseButton, AXEdited"
* @return see [self valueOfUIElement: attribute:]
*
* TRYME: reprototype to [self valueOfUIElement:(AXUIElementRef) attributePath:(NSString *) ...]
*/
+ (CFTypeRef _Nullable)valueOfUIElement:(AXUIElementRef _Nonnull)element attributePath:(nonnull NSString *)attributePath {
AXError e = kAXErrorFailure;
CFTypeRef value = NULL;
CFTypeRef *heap = NULL;
NSArray<NSString *> *list;
NSUInteger sz;
NSUInteger i;
NSString *attr;
ASSERT_NONNULL(element);
ASSERT_NONNULL(attributePath);
list = [attributePath componentsSeparatedByString:@","];
sz = [list count];
if (sz > 0) {
if ((heap = (CFTypeRef *) malloc(sz * sizeof(CFTypeRef))) != NULL) {
(void) memset(heap, 0, sz * sizeof(CFTypeRef));
}
}
if (heap == NULL) goto out_exit;
for (i = 0; i < sz; i++) {
heap[i] = value;
attr = [[list objectAtIndex:i] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
e = AXUIElementCopyAttributeValue(element, (__bridge CFStringRef) attr, &value);
if (e != kAXErrorSuccess) {
LOG_ERR("AXUIElementCopyAttributeValue() fail attribute: %@ error: %@", attr, [self axErrorName:e]);
break;
}
/* Stop when we met first non-AXUIElementRef value */
if (CFGetTypeID(value) != AXUIElementGetTypeID()) {
if (i != sz - 1) {
LOG_ERR("Met non-AXUIElementRef value in the interim idx: %lu attr: %@", i, attr);
e = kAXErrorFailure;
}
break;
}
element = (AXUIElementRef) value;
}
/* Release interim AXUIElementRef */
for (i = 0; i < sz; i++) {
CFSafeRelease(heap[i]);
}
free(heap);
out_exit:
return e == kAXErrorSuccess ? value : nil;
}
@leiless
Copy link
Author

leiless commented Feb 22, 2019

Test:

2019-02-22 21:03:38.371 office-badge[8638:158864] [DBG] >> Role:     AXApplication
2019-02-22 21:03:38.371 office-badge[8638:158864] [DBG] >> Document: file:///Users/lynnl/A.docx
2019-02-22 21:03:38.371 office-badge[8638:158864] [DBG] >> Edited:   1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment