如何在Mac OS X中收听应用程序启动事件?
我写了一个AppleScript
来挂载SparseBundle
映像,我希望它在Time Machine
启动时准确地执行.
I wrote an AppleScript
to mount a SparseBundle
image and I want it to be executed exactly when Time Machine
launches.
现在,我使用on idle
语句定期检查Time Machine是否以AppleScript
运行:
Right now, I periodically check if Time Machine is running with AppleScript
using on idle
statement:
on idle
....
return <interval>
end idle
这不是一种可靠的方法.我认为为Application Launch
事件添加事件触发器将是更好的方法.
which isn't a robust way. In my opinion adding an event trigger for Application Launch
event would be a better approach.
能请你帮忙吗?
欢迎使用Objective-C
或Python
示例代码(我更喜欢Python
).
An Objective-C
or Python
sample code (I'd prefer Python
) is more than welcome.
您正在寻找的是 NSWorkspace ,这些可可类发布应用程序事件的通知,对于工作区,事情例如应用程序启动,驱动器安装等.
What you are looking for is, NSDistributedNotificationCenter or NSWorkspace , these cocoa classes post notifications of application events, For workspace, things like application launches, mounting of drives etc.
要在python中执行此操作,您需要 PyObjC ,基本上是苹果可可粉类的python绑定.该文档在其网站上很少,这是有原因的,因为该文档与Apple文档基本相同,因此它们仅包含pyobjc api和cocoa API之间的区别.如果您了解如何将目标c api转换为python,那么您就可以开始了.在此处检查: http://pyobjc.sourceforge.net/documentation/pyobjc-core/intro.html
To do this in python, you need PyObjC, which is basically python bindings for apple's cocoa classes. The documentation is sparse on their website, and there's a reason, as the documentation would be basically be the same as the Apple docs, so they only include the differences between the pyobjc api, and the cocoa API. If you understand how the objective c api is converted to python you are good to go. Check here: http://pyobjc.sourceforge.net/documentation/pyobjc-core/intro.html
我在下面提供了一个示例,该示例使用python侦听分布式通知.下面的代码基本上添加了一个观察者并侦听iTunes通知.您可以遵循类似的结构,但是可以添加NSWorkspace的观察者.为了弄清楚您应该听什么,有一个应用程序将显示通过系统的所有通知.它称为通知查看器.用它来弄清楚你应该听什么.您也可以将目标C代码转换为python.
I have included an example below which listens for Distributed notifications using python. The code below basically adds an observer and listens for itunes notifications. You could follow a similar structure, but instead add an observer for NSWorkspace. To figure out what you should be listening to, there is an application that will display all notifications going through your system. It's called notification watcher . Use this to figure out what you should be listening to. You could also convert the objective c code to python.
下面的代码在做什么
- 定义一个新类,该类继承自PyObjC定义的NSObject
- 定义一个方法,该方法将传递实际的通知并打印出来
- 创建Foundation.NSDistributedNotificationCenter.defaultCenter的实例
- 创建GetSongs的实例
- 注册一个观察者,将其传递给类,在收到通知时调用的方法以及哪个应用程序和应用程序.事件以监视即"com.apple.iTunes.playerInfo"
- 运行事件循环,
访问属性(目标c属性)会使您绊倒的一件事与访问python属性不同.即在python中,对于python中的目标c做class_name.att
,您必须像调用函数一样调用它,即从下面的示例中进行调用:song.userInfo()
One thing that will trip you up, accessing attributes (objective c attributes) do not work the same as accessing python attributes. i.e in python you do class_name.att
for objective c in python you have to call it like a function i.e from my example below: song.userInfo()
import Foundation
from AppKit import *
from PyObjCTools import AppHelper
class GetSongs(NSObject):
def getMySongs_(self, song):
print "song:", song
song_details = {}
ui = song.userInfo()
print 'ui:', ui
for x in ui:
song_details[x] = ui.objectForKey_(x)
print song_details
nc = Foundation.NSDistributedNotificationCenter.defaultCenter()
GetSongs = GetSongs.new()
nc.addObserver_selector_name_object_(GetSongs, 'getMySongs:', 'com.apple.iTunes.playerInfo',None)
NSLog("Listening for new tunes....")
AppHelper.runConsoleEventLoop()
这是实际输出的示例...(是BRITNEY ROCKS !,不是!;)
Here's an example of the actual output... (YES BRITNEY ROCKS!, NOT! ;)
song NSConcreteNotification 0x104c0a3b0 {name = com.apple.iTunes.playerInfo; object = com.apple.iTunes.player; userInfo = {
Album = Circus;
"Album Rating" = 0;
"Album Rating Computed" = 1;
Artist = "Britney Spears";
"Artwork Count" = 1;
Genre = Pop;
"Library PersistentID" = 8361352612761174229;
Location = "file://localhost/Users/izze/Music/iTunes/iTunes%20Music/Britney%20Spears/Circus/02%20Circus.mp3";
Name = Circus;
PersistentID = 4028778662306031905;
"Play Count" = 0;
"Play Date" = "2010-06-26 08:20:57 +0200";
"Player State" = Playing;
"Playlist PersistentID" = 7784218291109903761;
"Rating Computed" = 1;
"Skip Count" = 1;
"Skip Date" = "2010-06-26 12:20:57 +0200";
"Store URL" = "itms://itunes.com/link?n=Circus&an=Britney%20Spears&pn=Circus";
"Total Time" = 192444;
"Track Count" = 16;
"Track Number" = 2;
}}
ui {
Album = Circus;
"Album Rating" = 0;
"Album Rating Computed" = 1;
Artist = "Britney Spears";
"Artwork Count" = 1;
Genre = Pop;
"Library PersistentID" = 8361352612761174229;
Location = "file://localhost/Users/izze/Music/iTunes/iTunes%20Music/Britney%20Spears/Circus/02%20Circus.mp3";
Name = Circus;
PersistentID = 4028778662306031905;
"Play Count" = 0;
"Play Date" = "2010-06-26 08:20:57 +0200";
"Player State" = Playing;
"Playlist PersistentID" = 7784218291109903761;
"Rating Computed" = 1;
"Skip Count" = 1;
"Skip Date" = "2010-06-26 12:20:57 +0200";
"Store URL" = "itms://itunes.com/link?n=Circus&an=Britney%20Spears&pn=Circus";
"Total Time" = 192444;
"Track Count" = 16;
"Track Number" = 2;
}
{u'Album Rating Computed': 1, u'Album': u'Circus', u'Rating Computed': True, u'Name': u'Circus', u'Artist': u'Britney Spears', u'Track Number': 2, u'Skip Date': 2010-06-26 12:20:57 +0200, u'Library PersistentID': 8361352612761174229L, u'Player State': u'Playing', u'Total Time': 192444L, u'Genre': u'Pop', u'Playlist PersistentID': 7784218291109903761L, u'Album Rating': 0, u'Location': u'file://localhost/Users/izze/Music/iTunes/iTunes%20Music/Britney%20Spears/Circus/02%20Circus.mp3', u'Skip Count': 1, u'Track Count': 16L, u'Artwork Count': 1, u'Play Date': 2010-06-26 08:20:57 +0200, u'PersistentID': 4028778662306031905L, u'Play Count': 0, u'Store URL': u'itms://itunes.com/link?n=Circus&an=Britney%20Spears&pn=Circus'}