cmacoskeyboard-eventskeydowncgeventtap

CGEventTapCreate detecting multiple keyboard inputs


I'm working on a macOS menubar app that locks any mouse events. What I'm trying to achieve is that after sending mouse events to the CGEventRef based callback, I cannot click anywhere (naturally) but the problem is I cannot quit the loop because of that.

Every time I need to close it, I'm switching to the Xcode app to stop the running app.

This is the main function and the events that I'm sending to the callback function;

void lockTrackpad(void) {
    // For keyboard inputs, I add CGEventMaskBit(kCGEventKeyUp)| CGEventMaskBit(kCGEventKeyDown)| CGEventMaskBit(NX_SYSDEFINED)
    CGEventMask mask = (
                        CGEventMaskBit(kCGEventMouseMoved)
                        | CGEventMaskBit(kCGEventLeftMouseUp)
                        | CGEventMaskBit(kCGEventLeftMouseDown)
                        | CGEventMaskBit(kCGEventRightMouseUp)
                        | CGEventMaskBit(kCGEventRightMouseDown)
                        | CGEventMaskBit(kCGEventScrollWheel)
                        );
    
    eventTap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, mask, CGEventCallback_r, nil);
    
    ...
}

And this is the callback function;

CGEventRef CGEventCallback_r(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
    CGKeyCode keycode = (CGKeyCode)CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);
    printf("Event Tap: %d\n", keycode);

    if (keycode == 43) {
        printf("quit the application \n");
        exit(EXIT_SUCCESS);
    }
    
    return nil;
}

What I want is, for example when the loop is running, if press "control + U + L", I want to run some function to exit the loop. I believe in order to get the keyboard input, I should send the keyboard events as well but I couldn't figure out how to detect my keyboard shortcuts.

I want to do something like this;

CGEventRef CGEventCallback_r(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
    CGKeyCode keycode = (CGKeyCode)CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);

    // When pressing "control + U + L", call a function
    if (...) {
        printf("pressed control + U + L \n");
        doSomething();
    }

    return nil;
}

Solution

  • I figured out like this;

    CGEventRef CGEventCallback_r(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
        
        if (type == kCGEventKeyDown) {
            CGKeyCode keyCode = (CGKeyCode)CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);
            
            if (CGEventGetFlags(event) & kCGEventFlagMaskControl) {
                // control key is pressed
                controlKeyPressed = true;
            }
            if (keyCode == kVK_ANSI_U) {
                // u key is pressed
                uKeyPressed = true;
            }
            if (keyCode == kVK_ANSI_L) {
                // l key is pressed
                lKeyPressed = true;
            }
            if (controlKeyPressed && uKeyPressed && lKeyPressed) {
                // doSomething();
            }
            return event;
        } else if (type == kCGEventKeyUp) {
            CGKeyCode keyCode = (CGKeyCode)CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);
            // set the variable to false just like above.
        }
        
        if (keycode == 43) {
            printf("quit the application \n");
            exit(EXIT_SUCCESS);
        }
        
        return nil;
    }
    

    Also, don't forget to put your variables on a global scope.