Мониторинг событий заставки в OSX
Я хочу отслеживать события заставки и блокировки экрана в окне OSX. Как первый проход, я в порядке с ними, просто печатая на консоли.
Следуя советам другого вопроса, я написал несколько Objective C для прослушивания Cocoa Уведомления для
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
%
Знания My Objective C и Cocoa очень ржавые, поэтому я не уверен, что я неправильно использую фреймворк, или если я зарегистрировал неправильные события (и где искать, чтобы выяснить, являются правильными событиями или нет).
Так что же я делаю неправильно?
Ответы
Ответ 1
Вы уже прокомментировали свою проблему.
while(1); // busy wait 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
Создание и прятка цикла запуска из main() приложения командной строки в OS X - довольно простая задача. Существует множество примеров, доступных для быстрого поиска.
Ответ 2
Изменить: дальнейшее тестирование показало, что com.apple.screensaver.didlaunch
также доступен, код здесь проверен на 10.6.8 и 10.8.4
Ваш код будет работать, если вы удалите [[NSRunLoop currentRunLoop] run];
и
инициализировать ScreenSaverMonitor из метода Cocoa application applicationDidFinishLaunching:
. (Просто создайте новый проект приложения Cocoa в XCode и добавьте свой код там, где это необходимо).
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);
}
Ответ 3
Похоже, что стратегия, которую вы пытаетесь использовать для этого, не будет работать, потому что уведомления com.apple.screensaver. * больше не поддерживаются.
В ответах на этот эквивалентный вопрос упоминается, что: "для Snow Leopard недоступны идентификаторы screenIsLocked и screenIsUnlocked".
Вы можете зарегистрироваться на экранные спящие, что, конечно, не одно и то же, но может быть приемлемой альтернативой для вас, прослушивая уведомление NSWorkspaceScreensDidSleepNotification или на компьютер, отправляющийся спать, прослушивая NSWorkspaceWillSleepNotification. Образец кода можно найти на этом форуме.
Sidenote: если вы используете nil для имени, вы получите много событий:
[center addObserver:self
selector:@selector(receive:)
name:nil
object:nil
];
Если вы это сделаете, вы увидите, что делаете все в основном правильно, потому что вы получите все виды событий, но не заставки.