Created
May 15, 2009 12:07
-
-
Save liesen/112185 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Cocoa accessibility framework for intercepting Spotlight user input. */ | |
#import <Cocoa/Cocoa.h> | |
#import <AppKit/NSAccessibility.h> | |
static void searchFieldCallback(AXObserverRef observer, | |
AXUIElementRef element, | |
CFStringRef notification, | |
void *data) { | |
CFTypeRef subrole, value; | |
/** | |
* Check that the component in question is the search field. | |
* If so, print the current value. | |
*/ | |
if (AXUIElementCopyAttributeValue(element, kAXSubroleAttribute, &subrole) == kAXErrorSuccess && | |
CFGetTypeID(subrole) == CFStringGetTypeID() && | |
CFStringCompare(kAXSearchFieldSubrole, (CFStringRef)subrole, 0) == kCFCompareEqualTo && | |
AXUIElementCopyAttributeValue(element, kAXValueAttribute, &value) == kAXErrorSuccess && | |
CFGetTypeID(value) == CFStringGetTypeID()) { | |
NSLog(@"> %@", (NSString *) value); | |
} | |
if (subrole) { | |
CFRelease(subrole); | |
} | |
if (value) { | |
CFRelease(value); | |
} | |
} | |
// 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[]) | |
{ | |
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | |
if (!AXAPIEnabled()) { | |
NSLog(@"The accessibility API isn't enabled!"); | |
return 1; | |
} | |
if (argc != 2) { | |
NSLog(@"Usage: %s BUNDLE_IDENTIFIER\n", argv[0]); | |
return EXIT_FAILURE; | |
} | |
CFStringRef bundle_identifier = (CFStringRef)[NSString stringWithUTF8String:argv[1]]; | |
pid_t process_pid; | |
OSStatus status = FindProcessIDForBundleIdentifier(bundle_identifier, &process_pid); | |
if (status != noErr) { | |
NSLog(@"Could not find PID for bundle identifier \"%@\"", (NSString *)bundle_identifier); | |
return status; | |
} | |
AXObserverRef observer; | |
AXError err = AXObserverCreate(process_pid, searchFieldCallback, &observer); | |
if (err != kAXErrorSuccess) { | |
NSLog(@"Failed to create observer"); | |
return err; | |
} | |
// Sign up for notifications on the process ID for the specified bundle | |
AXUIElementRef element = AXUIElementCreateApplication(process_pid); | |
if (!element) { | |
NSLog(@"Couldn't register for element changes"); | |
return EXIT_FAILURE; | |
} | |
err = AXObserverAddNotification(observer, element, kAXValueChangedNotification, NULL); | |
CFRelease(element); | |
if (err != kAXErrorSuccess) { | |
NSLog(@"Failed adding observer"); | |
return err; | |
} | |
CFRunLoopAddSource(CFRunLoopGetMain(), | |
AXObserverGetRunLoopSource(observer), | |
kCFRunLoopCommonModes); | |
[NSApplication sharedApplication]; | |
[NSApp run]; | |
[pool drain]; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Cocoa accessibility framework for intercepting Spotlight user input. */ | |
#import <Cocoa/Cocoa.h> | |
#import <AppKit/NSAccessibility.h> | |
static void searchFieldCallback(AXObserverRef observer, | |
AXUIElementRef element, | |
CFStringRef notification, | |
void *data) { | |
CFTypeRef query1, query2; | |
/** | |
* Check that the component in question is the search field. | |
* If so, print the current value. | |
*/ | |
if (AXUIElementCopyAttributeValue(element, kAXSubroleAttribute, &query1) == kAXErrorSuccess && | |
CFGetTypeID(query1) == CFStringGetTypeID() && | |
CFStringCompare(kAXSearchFieldSubrole, (CFStringRef) query1, 0) == kCFCompareEqualTo && | |
AXUIElementCopyAttributeValue(element, kAXValueAttribute, &query2) == kAXErrorSuccess && | |
CFGetTypeID(query2) == CFStringGetTypeID()) { | |
NSLog(@"> %@", (NSString *)query2); | |
} | |
if (query1) | |
CFRelease(query1); | |
if (query2) | |
CFRelease(query2); | |
} | |
// 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[]) | |
{ | |
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | |
if (!AXAPIEnabled()) { | |
NSLog(@"The accessibility API isn't enabled!"); | |
return 1; | |
} | |
if (argc != 2) { | |
NSLog(@"Usage: %s BUNDLE_IDENTIFIER\n", argv[0]); | |
return EXIT_FAILURE; | |
} | |
CFStringRef bundle_identifier = (CFStringRef)[NSString stringWithUTF8String:argv[1]]; | |
pid_t process_pid; | |
OSStatus status = FindProcessIDForBundleIdentifier(bundle_identifier, &process_pid); | |
if (status != noErr) { | |
NSLog(@"Could not find PID for bundle identifier \"%@\"", (NSString *)bundle_identifier); | |
return status; | |
} | |
AXObserverRef observer; | |
AXError err = AXObserverCreate(process_pid, searchFieldCallback, &observer); | |
if (err != kAXErrorSuccess) { | |
NSLog(@"Failed to create observer"); | |
return err; | |
} | |
// Sign up for notifications on the process ID for the specified bundle | |
AXUIElementRef element = AXUIElementCreateApplication(process_pid); | |
if (!element) { | |
NSLog(@"Couldn't register for element changes"); | |
return EXIT_FAILURE; | |
} | |
err = AXObserverAddNotification(observer, element, kAXValueChangedNotification, NULL); | |
CFRelease(element); | |
if (err != kAXErrorSuccess) { | |
NSLog(@"Failed adding observer"); | |
return err; | |
} | |
CFRunLoopAddSource(CFRunLoopGetMain(), | |
AXObserverGetRunLoopSource(observer), | |
kCFRunLoopCommonModes); | |
[NSApplication sharedApplication]; | |
[NSApp run]; | |
[pool drain]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment