CFRunLoopRunInMode is exiting with code 1, as if n

2019-03-05 13:30发布

问题:

I have created a CGEventTap like this:

GetCurrentProcess(psn);

var mask =  1 << kCGEventLeftMouseDown | // CGEventMaskBit(kCGEventLeftMouseDown)
            1 << kCGEventLeftMouseUp | 
            1 << kCGEventRightMouseDown |
            1 << kCGEventRightMouseUp |
            1 << kCGEventOtherMouseDown |
            1 << kCGEventOtherMouseUp |
            1 << kCGEventScrollWheel;

mouseEventTap = CGEventTapCreateForPSN(&psn, kCGHeadInsertEventTap, kCGEventTapOptionDefault, mask, null);

if (!mouseEventTap.isNull()) {
      aRLS = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, mouseEventTap, 0);
      CFRelease(mouseEventTap);

      if (!aRLS.isNull()) {
            aLoop = CFRunLoopGetCurrent();

            CFRunLoopAddSource(aLoop, aRLS, kCFRunLoopCommonModes);

            CFRelease(aRLS);
            CFRelease(aLoop);

            rez = CFRunLoopRunInMode(ostypes.CONST.kCFRunLoopCommonModes, 10, false); // figure out how to make this run indefinitely
            // rez is 1 :(

      }

}

My CFRunLoopRun is exiting immediately, instead of running for 10seconds. And it says code is 1 which means no sources are in that mode. But I clearly did a CFRunLoopAddSource to the common modes option kCFRunLoopRunFinished. The run loop mode mode has no sources or timers.. Anyone know whats up? This is on not-main thread.

回答1:

You can't run a run loop in kCFRunLoopCommonModes. This is clearly stated in the documentation for CFRunLoopRunInMode().

kCFRunLoopCommonModes is a virtual mode. It's basically a set of other modes. It can only be used when adding (or removing) a source to a run loop to say "monitor this source when the run loop is run in any of the modes in the set". But when you run a run loop, you have to run it in a specific, real mode, not this virtual mode which represents a set of other modes.

I recommend that, when you're working on a private thread and only want to monitor private sources, that you add the source to a custom mode and run the run loop in that mode. A custom mode is just a string with a unique value. For example, something like "com.yourcompany.yourproject.yourmodespurpose". Using a custom mode makes sure that the run loop never does anything unexpected, like firing a source added by the frameworks.

You must not release aLoop. Functions that don't have "Create" or "Copy" in their name do not give you ownership.

You will need a loop around your call to CFRunLoopRunInMode() because it will return every time it handles an event from your source (kCFRunLoopRunHandledSource == 4) or hits the timeout (kCFRunLoopRunTimedOut == 3). You should break out of the loop if it ever returns anything else.