swiftmacosdetectmodifiernsevent

How to detect Caps Lock status on macOS with Swift without a window?


I have tried KeyDown and NSEvent, but they require a NSWindow object to be active. My hope is that I can put an app on the status bar and alert the user when it has pressed CapsLock, even if the user is in any other app. My app idea doesn't have a window for settings or anything else, is just an indicator. Can it even be done? I am guessing the AppDelegate but can't figure out how to make it receive modifier events. Any help really appreciated!

I have looked on stack overflow for a "duplicate" but no one has ever asked this question as far as I searched.


Solution

  • You just need to monitor the NSEvent modifier flags changed for capslock. The easiest way is to create a method that takes a NSEvent and check if the modifierFlags property intersection with .deviceIndependentFlagsMask contains .capsLock:

    func isCapslockEnabled(with event: NSEvent) -> Bool {
        event.modifierFlags.intersection(.deviceIndependentFlagsMask).contains(.capsLock)
    }
    

    Now you just need to add global monitoring event to your applicationDidFinishLaunching method:

    func applicationDidFinishLaunching(_ aNotification: Notification) {
        NSEvent.addGlobalMonitorForEvents(matching: .flagsChanged, handler: flagsChanged)
    }
    

    And create a method to deal with the event of flagsChanged:

    func flagsChanged(with event: NSEvent) {
        print("Capslock is Enabled:", isCapslockEnabled(with: event))
    }
    

    Edit/update:

    As already mentioned in comments, to check the initial state of the capsLock key you can check the NSEvent ModifierFlags capsLock property capsLock

    NSEvent.ModifierFlags.capsLock