5

I have a basic keystroke converter app in development. The conversion works with the following:

CFRunLoopSourceRef runLoopSource = NULL;
CFMachPortRef eventTap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, kCGEventMaskForAllEvents, myCGEventCallback, NULL);
runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
CGEventTapEnable(eventTap, true);

As you might expect, kCGEventMaskForAllEvents is constantly firing for any mouse movement or click in addition to the keyboard, and I suspect tying up system resources. I tried substituting CGEventMaskBit(kCGEventKeyDown), which best I can tell from Quartz Event doc on Event Types is what I want, and would weed out mouse movements and clicks. Unfortunately, using this seems to just eat the keystrokes, rather than convert them.

What am I doing wrong?

The following works, but I still don't understand why CGEventMaskBit(kCGEventKeyUp) by itself isn't the correct implementation.

CGEventMaskBit(kCGEventKeyUp) | CGEventMaskBit(kCGEventKeyDown) | CGEventMaskBit(NX_SYSDEFINED)
DenVog
  • 4,226
  • 3
  • 43
  • 72
  • I have been looking into this a bit and im not sure if this is the answer or not. I also noticed when looking at your thing . NX_SYSDEFINED seems to not work for me – Fallenreaper May 13 '17 at 22:22

2 Answers2

2

because a keystroke key press consists of a keydown and a key up

Daij-Djan
  • 49,552
  • 17
  • 113
  • 135
  • So KeyDown and KeyUp aren't two separate events that can be detected independently? On iOS virtual buttons, I can detect touchUpInside as a different event from touchDown. – DenVog Feb 10 '13 at 22:27
2
  1. The discussion section of the CGEventTapCreate doc page says:

    Event taps receive key up and key down events if one of the following conditions is true:

    • The current process is running as the root user.
    • Access for assistive devices is enabled. In OS X v10.4, you can enable this feature using System Preferences, Universal Access panel, Keyboard view.

    Running as the root user definitely worked for me (MacOS Sierra.) I didn't try the assistive devices approach.

  2. To run as root inside XCode (I have 8.3.3 at this time), choose Product/Scheme/Edit Scheme.../Run/Info/Debug Process As: root

    XCode's Edit Scheme dialog

  3. In the CGEventTapCreate call, replace the kCGEventMaskForAllEvents argument with CGEventMaskBit(kCGEventKeyDown) | CGEventMaskBit(kCGEventKeyUp). Your callback will now get invoked for most key presses, except for modifier keys: shift, ctrl, cmd, some of teh function keys.

    To get the callback invoked for the modifier keys, add CGEventMaskBit(kCGEventKeyDown) | CGEventMaskBit(kCGEventKeyUp) | CGEventMaskBit(NX_SYSDEFINED). For some reason, with this change I also get the callback invoked for mouse button presses. This might be a side effect of how the Logitech mouse driver works -- I didn't investigate. But the volume of calls is much lower than before and doesn't include mouse moves.

    Dave Keck's response to this CocoaBuilder thread gets credit for figuring this out.

Oren Trutner
  • 23,752
  • 8
  • 54
  • 55