I'm trying to use Quartz Event Services, specifically event taps, on OS X to capture simulated key presses generated by a passive infrared sensor wired to a stripped keyboard PCB. Theoretically, with event taps I can choose to swallow and ignore the key presses and simply use the keyboard input to "wake" the computer. I can also use the event tap (only one "key" is wired so the motion detector always sends a "0") to modify the input to an arbitrary key or key combination that will, in turn, invoke arbitrary functionality on the host machine. To make things more complicated, the end host machine is an old G4 Powerbook (PPC) that can't really run anything beyond OS X 10.4, and my current development machine is a much newer Intel-based iMac running 10.9 and using Xcode 5.1.1.
I found the following code from an answer here, and it seems like it would be perfect. If I create a terminal application in Cocoa, I can use the code basically as-is. I also tried creating a window-based Cocoa application in case this was necessary for adding the application to the list of Accessibility apps that can "control" the computer under the Security/Privacy Preferences (Enable Access for Assistive Devices is deprecated in Mavericks). Neither app-type worked completely. The best I have been able to achieve is to get the program to recognize key presses of modifier keys (command, option, shift, ctl, etc), but I cannot get any response from key presses of "regular" keyboard keys, and I cannot seem to enact actually changing the captured key event. Furthermore, it seems like mouse events, specifically,mouse clicks, register as KeyUp and KeyDown events - even if I change the event mask from 'AllEvents to just 'KeyUp or 'KeyDown.
Here is my slightly modified version of the original code that is adapted to try to conform to Xcode 5 conventions. As you can see the heavy lifting is in the applicationDidFinishLaunching method rather than main() as in the original. Obviously, I had to create a method declaration in the AppDelegate.h file, which is also not part of the original code.
#import "AppDelegate.h"
#import <Cocoa/Cocoa.h>
#import <ApplicationServices/ApplicationServices.h>
#include <Carbon/Carbon.h>
@implementation AppDelegate
CGEventRef myCGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
NSLog(@"In the callback");
//0x0b is the virtual keycode for "b"
//0x09 is the virtual keycode for "v"
if ((type != kCGEventKeyDown) && (type != kCGEventKeyUp))
NSLog(@"event: %@", event);
if (CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode) == kVK_ANSI_S) {
NSLog(@"event matched");
CGEventSetIntegerValueField(event, kCGKeyboardEventKeycode, kVK_ANSI_1);
}
return event;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSLog(@"Hello?");
CFRunLoopSourceRef runLoopSource;
CFMachPortRef eventTap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, kCGEventMaskForAllEvents, myCGEventCallback, NULL);
if (!eventTap) {
NSLog(@"Couldn't create event tap!");
exit(1);
}
runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
CGEventTapEnable(eventTap, true);
CFRunLoopRun();
CFRelease(eventTap);
CFRelease(runLoopSource);
NSLog(@"goodbye");
}
@end
At this point, I'm just trying to get something working on 10.9 as a proof of concept before I attempt to backport to 10.4 compatibility. Sorry for the long post. First time asking for help here and just trying to be thorough. Thanks in advance for any and all responses!