Home > Net >  How can I build a dynamic CGEventFlags in Swift?
How can I build a dynamic CGEventFlags in Swift?

Time:08-11

I have several keyboard shortcuts that my app is using and I would like to dynamically build the correct CGEventFlags for each shortcut. I know there are questions that describe how to do this with a static event, but I would like to run dynamic CGEvents and I'm having trouble elegantly creating the correct value. I'll also be honest, bit masks don't make much sense to me. Is there any way to convert this to the dynamically get the correct CGEventFlag? Here's what I've been trying to do without success:

let shortcut = "control shift option command L"

var flags = [CGEventFlags]()

if shortcut.contains("control ") { flags.append(.maskControl) }
if shortcut.contains("shift ")   { flags.append(.maskShift) }
if shortcut.contains("option ")  { flags.append(.maskAlternate) }
if shortcut.contains("command ") { flags.append(.maskCommand) }              


let mask = flags.someConversionFunction()... 

CodePudding user response:

CGEventFlags conforms to OptionSet, which means that you can use set operations on it (as OptionSet inherits from SetAlgebra) and not worry about bit operations at all.

So basically, think of a variable of type CGEventFlags as a set of flags. For example, you can insert and remove flags from it, as well as forming unions and intersections with other CGEventFlags.

var flags: CGEventFlags = []

if shortcut.contains("control ") { flags.insert(.maskControl) }
if shortcut.contains("shift ")   { flags.insert(.maskShift) }
if shortcut.contains("option ")  { flags.insert(.maskAlternate) }
if shortcut.contains("command ") { flags.insert(.maskCommand) }  

// now you can assign "flags" to CGEvent.flags

If you do have a [CGEventFlags] and want to convert to a single CGEventFlags, just use the init(_:) initialiser - this is the same initialiser as the one you use to convert [Int] to a Set<Int>. It's a bit counterintuitive, but CGEventFlags is a set of CGEventFlags.

Here I rewrote your code to be less imperative (without the mutable var), as an example of converting from [CGEventFlags] to CGEventFlags:

let shortcut = "control shift option command L"
let eventFlagDictionary: [_: CGEventFlags] = [
    "control": .maskControl,
    "shift": .maskShift,
    "option": .maskAlternate,
    "command": .maskCommand
]
let flags = CGEventFlags(
    // the below is a [CGEventFlags]
    shortcut.split(separator: " ")
        .compactMap { eventFlagDictionary[String($0)] }
)
  • Related