5

CapsLock appears to be one of the two trickiest keys to remap (the other being the power button).

I can global-intercept NSEvent-s:

    _eventTap = CGEventTapCreate( kCGHIDEventTap, 
                                  kCGHeadInsertEventTap,
                                  kCGEventTapOptionDefault,
                                     CGEventMaskBit( kCGEventFlagsChanged ),
                                  (CGEventTapCallBack)_tapCallback,
                                  (__bridge void *)(self));

:

However, I don't get an event for each key up/down. What actually happens is this:

(initial state of CapsLock off)

Key down: NSSystemDefined: 40a00 NSSystemDefined: 40b00 (Green light is on at this point)

Key up: NSSystemDefined: 40b00

Key down: NSSystemDefined: 40a00 (Green light is OFF at this point)

Key up: (nothing)

So I can't map at this level.

But I figured I could monitor at a lower level using IOKit, which detects every keyboard key down/up event, and then eat the CAPSLOCK events at this level (by returning NULL):

- (CGEventRef)processEvent:(CGEventRef)cgEvent
{
    NSEvent* event = [NSEvent eventWithCGEvent:cgEvent];

    NSUInteger modifiers = [event modifierFlags] &
        ( NSCommandKeyMask | NSAlternateKeyMask | NSShiftKeyMask | NSControlKeyMask | NSAlphaShiftKeyMask );

    NSUInteger flags_changed = _modifiers ^ modifiers;
    if( flags_changed & NSAlphaShiftKeyMask )
    {
        NSLog( @"Eating CAPSLOCK" );
        return NULL;
    }

    _modifiers = modifiers;
    :

However, that doesn't prevent CapsLock from doing its thing (i.e. capitalising typed letters).

I've even tried removing the CapsLock modifier flag from every keyboard event within the handler:

if( modifiers & NSAlphaShiftKeyMask )
    event = [NSEvent keyEventWithType: event.type
                             location: NSZeroPoint
                        modifierFlags: event.modifierFlags & ! NSAlphaShiftKeyMask
                            timestamp: event.timestamp
                         windowNumber: event.windowNumber
                              context: event.context
                           characters: event.characters
          charactersIgnoringModifiers: event.charactersIgnoringModifiers
                            isARepeat: event.isARepeat
                              keyCode: event.keyCode ];

... But no luck!

Is there any way to tame this pesky CapsLock key?

EDIT: How to simulate Caps Lock keystroke with CGEventCreateKeyboardEvent in OS X

Community
  • 1
  • 1
P i
  • 29,020
  • 36
  • 159
  • 267
  • 1
    `event.modifierFlags & ! NSAlphaShiftKeyMask` doesn't do what you want. You used the logical negate operator rather than the bitwise negate operator. You wanted `event.modifierFlags & ~NSAlphaShiftKeyMask`. However, that doesn't explain the issue you're seeing. Your code would effectively remove the alpha-shift modifier flag. It's just that it would also remove all other modifier flags, too. You might want to look at the so-called device-dependent modifier flags, which aren't really device-dependent, in the lower 16 bits. For example, `NX_DEVICE_ALPHASHIFT_STATELESS_MASK` from IOLLEvent.h. – Ken Thomases May 30 '15 at 10:29

1 Answers1

0

I believe Karabiner Elements does it with its own keyboard driver, take a look at the source code.

Devon
  • 1,019
  • 9
  • 20