title: Stop Intercepting Keyboard Input While App Running - CGEventTap
body: <p>What is the correct way to stop watching keyboard event taps using CGEventTap?</p>
  
  <p>I am building a simple background app that converts the output of specific keys. Thanks to <a href="https://stackoverflow.com/questions/5785630/modify-nsevent-to-send-a-different-key-than-the-one-that-was-pressed/5785895#5785895">this excellent post on CGEventTap</a>, I've been able to enable the key conversion. Unfortunately, I do not seem to be able to stop it short of killing the app.</p>
  
  <p>The following method is called when the user toggles a checkbox to turn the functionality ON or OFF. Toggle ON happens immediately. Toggle OFF can take a minute or more before it takes affect. I see via log that the "Disabled. Stop converting taps." is detected. But the key conversion just keeps on going. I don't understand why.</p>
  
  <pre><code>- (void)watchEventTap
  {    
          @autoreleasepool
          {
              CFRunLoopSourceRef runLoopSource = NULL;
              CFMachPortRef eventTap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, CGEventMaskBit(kCGEventKeyUp) | CGEventMaskBit(kCGEventKeyDown) | CGEventMaskBit(NX_SYSDEFINED), myCGEventCallback, NULL);
              runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
  
              if (!eventTap)
              {
                  NSLog(@"Couldn't create event tap!");
                  exit(1);
              }
  
              if (self.shortcutEnabled) // User default toggled ON
              {
                  NSLog(@"Enabled. Convert taps.");
                  CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
                  CGEventTapEnable(eventTap, true);
                  // CFRunLoopRun(); // This blocks rest of app from executing
              }
              else // User default toggled OFF
              {
                  NSLog(@"Disabled. Stop converting taps.");
                  CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
                  CGEventTapEnable(eventTap, false);
                  // Clean up the event tap and source after ourselves.
                  CFMachPortInvalidate(eventTap);
                  CFRunLoopSourceInvalidate(runLoopSource);
                  CFRelease(eventTap);
                  CFRelease(runLoopSource);
                  eventTap = NULL;
                  runLoopSource = NULL;
              }
          }
  //        exit(0);  // This blocks rest of app from executing
  }
  </code></pre>
  
  <p>Thanks for any suggestions. I'm new building Mac OS X apps, so please forgive me if I'm doing something ignorant.</p>