14

我想监视 OSX 盒子上的屏幕保护程序和锁屏事件。作为第一遍,我可以将它们打印到控制台。

根据另一个问题的建议,我编写了一些 Objective C 来监听 com.apple.screensaver.didstartcom.apple.screensaver.didstopcom.apple.screenIsLockedcom.apple.screenIsUnlocked事件的 Cocoa 通知。

// 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
%

我的 Objective C 和 Cocoa 知识非常生疏,所以我不确定我是否使用错误的框架,或者我是否注册了错误的事件(也不知道在哪里查找这些是否是正确的事件或不是)。

那么我做错了什么?

4

3 回答 3

10

你已经评论了你的问题。

while(1); // busy wait's bad, I know, but easy to implement

以上几乎总是一个坏主意。

NSDistributedNotificationCenter 实际上需要一个正在运行的主线程 NSRunLoop 来操作。

http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Notifications/Articles/NotificationCenters.html#//apple_ref/doc/uid/20000216-BAJGDAFC

在 OS X 上从命令行应用程序的 main() 创建和旋转运行循环是一件相当简单的事情。通过快速搜索可以找到大量示例。

于 2013-06-05T18:15:46.607 回答
7

编辑:进一步测试表明com.apple.screensaver.didlaunch也可用,此处的代码在 10.6.8 和 10.8.4 上测试

如果您从 Cocoa 应用程序的方法中删除[[NSRunLoop currentRunLoop] run];并初始化 ScreenSaverMonitor,您的代码将起作用。applicationDidFinishLaunching:(只需在 XCode 中创建一个新的 Cocoa 应用程序项目并在适当的地方添加您的代码)。

屏幕保护程序监视器.h

#import <Foundation/Foundation.h>

@interface ScreenSaverMonitor : NSObject
-(id) init;
-(void) receive: (NSNotification*) notification;

@end

屏幕保护程序监视器.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

主文件

#import <Cocoa/Cocoa.h>

int main(int argc, char *argv[])
{
    return NSApplicationMain(argc, (const char **)argv);
}
于 2013-06-16T17:04:11.177 回答
2

您尝试使用的策略似乎不起作用,因为不再支持 com.apple.screensaver.* 通知。
在对这个等效问题的回复中,提到:“对于 Snow Leopard,screenIsLocked 和 screenIsUnlocked 通知不再可用。”
您可以注册屏幕睡眠,当然这不一样,但可能是您可以接受的替代方法,方法是收听 NSWorkspaceScreensDidSleepNotification 通知,或者通过收听 NSWorkspaceWillSleepNotification 让计算机进入睡眠状态。示例代码可以在这个论坛上找到。

旁注:如果您使用 nil 作为名称,您将收到很多事件:

[center addObserver:self
           selector:@selector(receive:)
               name:nil
             object:nil
];

如果你这样做,你会发现你所做的一切基本上都是正确的,因为你会收到各种各样的事件——但没有屏幕保护程序。

于 2013-06-12T14:13:16.577 回答