andrello andrello - 8 months ago 108
Swift Question

Handling cocoa key events (keys pressed) with swift in a console application

Ok so i'm trying to log on console output what keys are pressed. I just can't understand the cocoa structure, neither with Obj-c, nor swift. I'm not a master in these 2 languages but... Well here's my code:

import Cocoa
import Foundation
import AppKit

var loop = true
var idRegisterdEvent: AnyObject? = nil

func handlerEvent(myEvent: (NSEvent!)) -> Void {

while loop {

idRegisterdEvent = NSEvent.addGlobalMonitorForEventsMatchingMask(NSEventMask.KeyDownMask, handler: handlerEvent)

i know everything is wrong, yeah.. But man, these events, i can't understand how they work.


After spending a couple of hours on google I eventually read a couple of github resources. It turns out that someone has already figured it out.

Basically you need to create a NSApplicationDelegate, which enables your app to listen to system-events.

The following shows the bare minimum code needed(swift2):

func acquirePrivileges() -> Bool {
    let accessEnabled = AXIsProcessTrustedWithOptions(
        [kAXTrustedCheckOptionPrompt.takeUnretainedValue() as String: true])

    if accessEnabled != true {
        print("You need to enable the keylogger in the System Preferences")
    return accessEnabled == true

class ApplicationDelegate: NSObject, NSApplicationDelegate {
    func applicationDidFinishLaunching(notification: NSNotification?) {

        // keyboard listeners
            NSEventMask.KeyDownMask, handler: {(event: NSEvent) in

// preparing main loop
let application = NSApplication.sharedApplication()
let applicationDelegate = MyObserver()
application.delegate = applicationDelegate

If you are just interested in only catching non-accessibility events (e.g.: NSWorkspaceDidActivateApplicationNotification) you can get away with much fewer lines of code as you only need NSRunLoop.mainRunLoop().run(). I only added this example since I saw your while true event-loop, which never will let you listen to any system-events, since its blocking the main-thread.

class MyObserver: NSObject
    override init() {

        // app listeners
        NSWorkspace.sharedWorkspace().notificationCenter.addObserver(self, selector: "SwitchedApp:", name: NSWorkspaceDidActivateApplicationNotification, object: nil)

    func SwitchedApp(notification: NSNotification!)

let observer = MyObserver()

// simply to keep the command line tool alive - as a daemon process