swift3cgeventtap

Parsing Keyboard Shortcuts from CGEvent


I'm trying to parse a CGEvent from myCGEventCallback for keyboard events. I can get access to modifier flags, keycode, UniChar.

So far I managed to get it to work for some combinations like command+shift+f, but I have a couple of problems for some other combinations.

  1. Control and option seem to give me a UniChar of some symbols instead of alphabet. For example, option+g will give me option+copyright symbol instead of option+g.
  2. I can't get function keys and cursors from UniChar.

What's the best way to interpret the result? For example, I want to get a result like control+g, option+control+g, or option+shift+f1, and so on. Here is the code for myCGEventCallback. Thanks!

func myCGEventCallback(proxy : CGEventTapProxy, type : CGEventType, event : CGEvent, refcon : UnsafeMutableRawPointer?) -> Unmanaged<CGEvent>? {
    if type == .keyDown {
        let flags = event.flags
        var msg = ""
        if flags.contains(.maskAlphaShift) {
            msg+="caps+"
        }
        if flags.contains(.maskShift) {
            msg+="shift+"
        }
        if flags.contains(.maskControl) {
            msg+="control+"
        }
        if flags.contains(.maskAlternate) {
            msg+="option+"
        }
        if flags.contains(.maskCommand) {
            msg += "command+"
        }
        if flags.contains(.maskSecondaryFn) {
            msg += "function+"
        }

        var keyCode = event.getIntegerValueField(.keyboardEventKeycode)
        var char = UniChar()
        var length = 0
        event.keyboardGetUnicodeString(maxStringLength: 1, actualStringLength: &length, unicodeString: &char)

        msg+="\(Character(UnicodeScalar(char)!))"
        debugPrint(msg)
    }
    return Unmanaged.passRetained(event)
}

Solution

  • I ended up just converting CGEvent to NSEvent by initializing NSEvent with CGEvent, and get charactersIgnoringModifiers. Non-characters like escape and backspace won't work though. Here's the entire CGEventCallback.

    func myCGEventCallback(proxy : CGEventTapProxy, type : CGEventType, event : CGEvent, refcon : UnsafeMutableRawPointer?) -> Unmanaged<CGEvent>? {
        if type == .keyDown {
            let flags = event.flags
            var msg = ""
            if flags.contains(.maskAlphaShift) {
                msg+="caps+"
            }
            if flags.contains(.maskShift) {
                msg+="shift+"
            }
            if flags.contains(.maskControl) {
                msg+="control+"
            }
            if flags.contains(.maskAlternate) {
                msg+="option+"
            }
            if flags.contains(.maskCommand) {
                msg += "command+"
            }
            if flags.contains(.maskSecondaryFn) {
                msg += "function+"
            }
            if let other = NSEvent(cgEvent: event), let chars = other.charactersIgnoringModifiers {
               msg += chars
                debugPrint(msg)
            }
        }
        return Unmanaged.passRetained(event)
    }