Search code examples
xcodemacoskeyboard-eventscgeventtapmedia-keys

CGEventTapCreate and CFMachPortCreateRunLoopSource fails EXC_BAD_ACCESS


I am trying to tap into the HID events of OSX. I found a snippet for testing it. However my code always seem to fail with EXC_BAD_ACCESS at the CFMachPortCreateRunLoopSource line. It seems that downEventTap is null. Reading the documentation tells me that this needs to be run on the main thread, I am pretty sure I am on the main thread, and wrapping things up in dispatch_async(dispatch_get_main_queue(), ^{ still gives me null. I am calling listen from application didFinishLaunching and added

@interface AppDelegate (){
  CFRunLoopSourceRef downSourceRef;
}

This is how I think creating an Event tap is to be done:

CGEventRef onKeyDown(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
  NSLog(@"DOWN (%lli)", CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode));
  // When it matches, I return CGEventCreate(NULL) to stop the event
  return event;
}
-(void)listen{

  CFMachPortRef downEventTap = CGEventTapCreate(kCGHIDEventTap,kCGHeadInsertEventTap,kCGEventTapOptionDefault,CGEventMaskBit(kCGEventKeyDown),&onKeyDown,(__bridge void *)(self));
  downSourceRef = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, downEventTap, 0); //<-- Crash exc_bad_access: downEventTap = 0x0,downSourceRef= 0x0
  CFRelease(downEventTap);
  CFRunLoopAddSource(CFRunLoopGetCurrent(), downSourceRef, kCFRunLoopDefaultMode);
  CFRelease(downSourceRef);
}

Solution

  • You most likely do not have the permissions required to tap the event which causes CGEventTapCreate to return NULL, which causes CFMachPortCreateRunLoopSource to segfault when trying to dereference said NULL.