Skip to content

Instantly share code, notes, and snippets.

@rsms
Forked from liesen/gist:109666
Created May 10, 2009 16:45
Show Gist options
  • Save rsms/109668 to your computer and use it in GitHub Desktop.
Save rsms/109668 to your computer and use it in GitHub Desktop.
A small utility that observes any changes of a search field of a given application
/* Cocoa accessibility framework for intercepting Spotlight user input. */
#import <Cocoa/Cocoa.h>
#import <AppKit/NSAccessibility.h>
static CFStringRef kSpotlightBundleIdentifier = CFSTR("com.apple.spotlight");
static void SpotlightCallback(AXObserverRef observer,
AXUIElementRef element,
CFStringRef notification,
void *data) {
CFTypeRef subrole;
if (AXUIElementCopyAttributeValue(element, kAXSubroleAttribute, &subrole) == kAXErrorSuccess &&
CFGetTypeID(subrole) == CFStringGetTypeID() &&
CFStringCompare(kAXSearchFieldSubrole, (CFStringRef) subrole, 0) == kCFCompareEqualTo) {
CFTypeRef query;
if (AXUIElementCopyAttributeValue(element, kAXValueAttribute, &query) == kAXErrorSuccess &&
CFGetTypeID(query) == CFStringGetTypeID()) {
NSLog(@"> %s", CFStringGetCStringPtr(query, CFStringGetSystemEncoding()));
CFRelease(query);
}
}
}
// Figure out the PID for a bundle identifier
static OSStatus FindProcessIDForBundleIdentifier(CFStringRef identifier, pid_t *pid) {
ProcessSerialNumber psn = {0, kNoProcess};
OSStatus status;
while ((status = GetNextProcess(&psn)) == noErr) {
CFDictionaryRef info = ProcessInformationCopyDictionary(
&psn, kProcessDictionaryIncludeAllInformationMask);
CFStringRef bundle;
if (CFDictionaryGetValueIfPresent(info, kCFBundleIdentifierKey, (const void **) &bundle) &&
CFStringCompare(bundle, identifier, 0) == kCFCompareEqualTo) {
return GetProcessPID(&psn, pid);
}
}
return status;
}
int main(int argc, char *argv[])
{
if (!AXAPIEnabled()) {
NSLog(@"AXAPIEnabled == FALSE. Poop!");
return 1;
}
pid_t spotlight;
OSStatus status = FindProcessIDForBundleIdentifier(kSpotlightBundleIdentifier, &spotlight);
if (status != noErr) {
NSLog(@"Could not find PID for Spotlight");
return status;
}
AXObserverRef observer;
AXError err = AXObserverCreate(spotlight, SpotlightCallback, &observer);
if (err != kAXErrorSuccess) {
NSLog(@"Failed to create observer");
return err;
}
// Sign up for notification's when Spotlight's "value" changes
AXUIElementRef element = AXUIElementCreateApplication(spotlight);
err = AXObserverAddNotification(observer, element, kAXValueChangedNotification, NULL);
CFRelease(element);
if (err != kAXErrorSuccess) {
NSLog(@"Failed adding observer");
return err;
}
CFRunLoopAddSource(CFRunLoopGetMain(),
AXObserverGetRunLoopSource(observer),
kCFRunLoopCommonModes);
return NSApplicationMain(argc, (const char **) argv);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment