如何检索当前接收关键事件的 OSX 应用程序

Posted

技术标签:

【中文标题】如何检索当前接收关键事件的 OSX 应用程序【英文标题】:How to retrieve the OSX application that currently receives key events 【发布时间】:2014-09-12 00:38:46 【问题描述】:

我正在关注cocoa documentation 来确定 OSX 中当前的最前端应用程序 - 也就是接收关键事件的应用程序。 但是,当我执行以下 swift 时,API 总是返回相同的值 - XCode,但当我切换到它们时,它永远不会更改为 chrome 或任何其他应用程序。我还尝试执行编译后的程序,但不是一直显示XCode,而是现在显示我正在运行的任何终端应用程序。

确定从 OSX 接收关键事件的应用程序的正确方法是什么?我这方面的代码有问题吗?

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);

【问题讨论】:

【参考方案1】:

这个帖子有点旧,但很有帮助。我根据 Marco 的帖子和 uchuugaka 的回答做了一些研究。结果如下。

// 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()

我是 Cocoa 和 Swift 的新手。我不知道以上是否有效,但它对我有用。我从 How to create a minimal daemon process in a swift 2 command line tool? 和 Swift 3 NSNotificationCenter Keyboardwillshow/hide 等众多其他人那里得到了帮助。

斯威夫特 4:

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

编辑 (Swift 4)

编译器说printMe 函数必须是@objc。 (我不知道是什么意思,但是当我在行首添加@objc 时它起作用了。这是用于轻松复制粘贴的完整代码。

// 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()

【讨论】:

“RunLoop.main.run()”有什么作用? 没有它,应用程序立即结束。【参考方案2】:

您应该做一件不同的事情,那就是遵循 NSWorkSpace 通知,告诉您应用程序退出活动或变为活动状态。 这是关键,尤其是当您在调试模式下运行时。 在调试模式下,Xcode 将您的应用程序作为子进程生成。 在发布模式下,它基本上与在终端中调用 open 命令相同。 在调试模式下,如果您过早地调用此代码并且只调用一次,您将无法捕捉到更改。记住它是动态的。

【讨论】:

以上是关于如何检索当前接收关键事件的 OSX 应用程序的主要内容,如果未能解决你的问题,请参考以下文章

OSX 10.10 应用程序没有获得焦点或事件循环

如何使用 Backand 检索当前登录的用户

初始化显示事件接收器失败

获取在 OSX 上的应用程序中打开的文档的名称(python)

如何检测服务和广播接收器中的关键事件

在android studio中使用firebase实时数据库检索当前登录用户的数据