Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to retrieve the OSX application that currently receives key events

I am following the cocoa documentation to determine the current front most application in OSX - aka the application which receives key events. However, when I am executing the following swift the API always returns me the same value - XCode, but it never changes to chrome or any other application when I switch to them. I also tried to execute the compiled program but instead of constantly showing XCode it now shows whichever terminal app I am running.

What is the correct way of determining the application that receives the key events from OSX? Is my code in this regard broken?

import Cocoa

func getActiveApplication() -> String{
    // Return the localized name of the currently active application
    let ws = NSWorkspace.sharedWorkspace()
    let frontApp = ws.frontmostApplication
    return frontApp.localizedName
}

var frontMostApp : String
while true {
    frontMostApp = getActiveApplication();
    NSLog("front app: %@", frontMostApp)
    sleep(1);
}
like image 654
Marco Pashkov Avatar asked Sep 12 '14 00:09

Marco Pashkov


1 Answers

This thread is a bit old but was very helpful. I did some research based on Marco's post and uchuugaka's answer. The following is the result.

// swift 3.0
// compile: xcrun -sdk macosx swiftc -framework Cocoa foo.swift -o foo
// run: ./foo

import Cocoa

class MyObserver: NSObject {
    override init() {
        super.init()
        NSWorkspace.shared().notificationCenter.addObserver(self, 
            selector: #selector(printMe(_:)), 
            name: NSNotification.Name.NSWorkspaceDidActivateApplication, 
            object:nil)
    }
    dynamic private func printMe(_ notification: NSNotification) {
        let app = notification.userInfo!["NSWorkspaceApplicationKey"] as! NSRunningApplication
        print(app.localizedName!)
    }
}
let observer = MyObserver()
RunLoop.main.run()

I am a newbie in both Cocoa and Swift. I don't know if the above is efficient, but it works for me. I got help from How to create a minimal daemon process in a swift 2 command line tool? and Swift 3 NSNotificationCenter Keyboardwillshow/hide among numerous others.

Swift 4:

NSWorkspace.shared.notificationCenter.addObserver(self,    // HERE, shared
    selector: #selector(printMe(_:)), 
    name: NSWorkspace.didActivateApplicationNotification,  // HERE
    object:nil)

Edit (Swift 4)

The compiler says the printMe function must be @objc. (I don't know the meaning, but it worked when I prepend @objc at the beginning of the line. Here is the full code for easy copy-paste.

// swift 4.0
// compile: xcrun -sdk macosx swiftc -framework Cocoa foo.swift -o foo
// run: ./foo

import Cocoa

class MyObserver: NSObject {
    override init() {
        super.init()
        NSWorkspace.shared.notificationCenter.addObserver(self, 
            selector: #selector(printMe(_:)), 
            name: NSWorkspace.didActivateApplicationNotification, 
            object:nil)
    }
    @objc dynamic private func printMe(_ notification: NSNotification) {
        let app = notification.userInfo!["NSWorkspaceApplicationKey"] as! NSRunningApplication
        print(app.localizedName!)
    }
}
let observer = MyObserver()
RunLoop.main.run()
like image 158
chan1142 Avatar answered Sep 29 '22 01:09

chan1142