我想监视OSX盒子上的屏幕保护程序和锁屏事件。作为第一关,我很好,他们只是打印到控制台。
在the advice of another's question之后,我写了一些目标C来监听Cocoa Notifications
com.apple.screensaver.didstart
,com.apple.screensaver.didstop
,com.apple.screenIsLocked
和com.apple.screenIsUnlocked
个事件。
// ScreenSaverMonitor.h
#import <Foundation/NSObject.h>
#import <Foundation/NSNotification.h>
@interface ScreenSaverMonitor: NSObject {}
-(id) init;
-(void) receive: (NSNotification*) notification;
@end
// ScreenSaverMonitor.m
#import "ScreenSaverMonitor.h"
#import <Foundation/NSString.h>
#import <Foundation/NSDistributedNotificationCenter.h>
#import <Foundation/NSRunLoop.h>
#import <stdio.h>
@implementation ScreenSaverMonitor
-(id) init {
NSDistributedNotificationCenter * center
= [NSDistributedNotificationCenter defaultCenter];
[center addObserver: self
selector: @selector(receive:)
name: @"com.apple.screensaver.didstart"
object: nil
];
[center addObserver: self
selector: @selector(receive:)
name: @"com.apple.screensaver.didstop"
object: nil
];
[center addObserver: self
selector: @selector(receive:)
name: @"com.apple.screenIsLocked"
object: nil
];
[center addObserver: self
selector: @selector(receive:)
name: @"com.apple.screenIsUnlocked"
object: nil
];
printf("running loop... (^C to quit)");
[[NSRunLoop currentRunLoop] run];
printf("...ending loop");
return self;
}
-(void) receive: (NSNotification*) notification {
printf("%s\n", [[notification name] UTF8String] );
}
@end
// ScreenSaverMonitorMain.m
#import "ScreenSaverMonitor.h"
int main( int argc, char ** argv) {
[[ScreenSaverMonitor alloc] init];
return 0;
}
它编译得很好,但是当我运行它时,我似乎没有观察到任何屏幕保护程序事件(尽管屏幕保护程序多次出现):
% gcc -Wall ScreenSaverMonitor.m ScreenSaverMonitorMain.m -o ScreenSaverMonitor -lobjc -framework Cocoa
% ./ScreenSaverMonitor
running loop (^C to quit)...
^C
%
我的目标C和Cocoa知识非常生疏,所以我不确定我是否使用了错误的框架,或者我是否注册了错误的事件(也不知道在哪里查看这些是否是是不是正确的事件。)
那么我做错了什么?
答案 0 :(得分:9)
您已经对您的问题发表了评论。
while(1); // busy wait's bad, I know, but easy to implement
以上几乎总是一个坏主意。
NSDistributedNotificationCenter实际上需要运行主线程NSRunLoop才能运行。
从OS X上的命令行应用程序的main()创建和旋转运行循环是一件相当简单的事情。快速搜索有很多例子。
答案 1 :(得分:6)
编辑:进一步测试显示com.apple.screensaver.didlaunch
也可用,此处的代码在10.6.8和10.8.4上进行测试
如果您删除[[NSRunLoop currentRunLoop] run];
和,则代码将有效
从Cocoa应用程序的applicationDidFinishLaunching:
方法初始化ScreenSaverMonitor。 (只需在XCode中创建一个新的Cocoa应用程序项目,并在适当的位置添加代码)。
ScreenSaverMonitor.h
#import <Foundation/Foundation.h>
@interface ScreenSaverMonitor : NSObject
-(id) init;
-(void) receive: (NSNotification*) notification;
@end
ScreenSaverMonitor.m
#import "ScreenSaverMonitor.h"
#import <Foundation/NSString.h>
#import <Foundation/NSDistributedNotificationCenter.h>
#import <Foundation/NSRunLoop.h>
#import <stdio.h>
@implementation ScreenSaverMonitor
-(id) init {
NSDistributedNotificationCenter * center
= [NSDistributedNotificationCenter defaultCenter];
[center addObserver: self
selector: @selector(receive:)
name: @"com.apple.screensaver.didlaunch"
object: nil
];
[center addObserver: self
selector: @selector(receive:)
name: @"com.apple.screensaver.didstart"
object: nil
];
[center addObserver: self
selector: @selector(receive:)
name: @"com.apple.screensaver.didstop"
object: nil
];
[center addObserver: self
selector: @selector(receive:)
name: @"com.apple.screenIsLocked"
object: nil
];
[center addObserver: self
selector: @selector(receive:)
name: @"com.apple.screenIsUnlocked"
object: nil
];
return self;
}
-(void) receive: (NSNotification*) notification {
printf("%s\n", [[notification name] UTF8String] );
}
@end
AppDelegate.h
#import <Cocoa/Cocoa.h>
#import "ScreenSaverMonitor.h"
@interface AppDelegate : NSObject <NSApplicationDelegate>
@property (assign) IBOutlet NSWindow *window;
@property (retain) ScreenSaverMonitor *monitor;
@end
AppDelegate.m
#import "AppDelegate.h"
#import "ScreenSaverMonitor.h"
@implementation AppDelegate
@synthesize monitor;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
self.monitor = [[ScreenSaverMonitor alloc] init];
}
@end
的main.m
#import <Cocoa/Cocoa.h>
int main(int argc, char *argv[])
{
return NSApplicationMain(argc, (const char **)argv);
}
答案 2 :(得分:2)
您尝试使用的策略似乎不起作用,因为不再支持com.apple.screensaver。*通知。
在对this equivalent question的回复中,提到:'对于Snow Leopard,screenIsLocked和screenIsUnlocked通知不再可用。'
您可以通过监听NSWorkspaceScreensDidSleepNotification通知来注册屏幕睡眠,这当然是不一样的,但可能是一个可接受的替代方案,或者通过监听NSWorkspaceWillSleepNotification来进入睡眠状态的计算机。可以找到示例代码on this forum。
旁注:如果您使用nil作为名称,您将收到许多事件:
[center addObserver:self
selector:@selector(receive:)
name:nil
object:nil
];
如果你这样做,你会发现你做的一切基本上都是正确的,因为你会收到所有类型的事件 - 但没有屏幕保护程序。