2013-06-05 6 views
12

Ich möchte Bildschirmschoner und Lockscreen-Ereignisse auf einer OSX-Box überwachen. Als ersten Durchlauf bin ich damit einverstanden, dass sie nur auf die Konsole drucken.Überwachung Bildschirmschoner Ereignisse in OSX

the advice of another's question Folgen, schrieb ich einige Objective C für Cocoa Benachrichtigungen zu hören für die com.apple.screensaver.didstart, com.apple.screensaver.didstop, com.apple.screenIsLocked und com.apple.screenIsUnlocked Veranstaltungen.

// 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; 
} 

Es kompiliert gut, aber wenn ich es laufen, ich scheine keine Bildschirmschoner Ereignisse zu beobachten (trotz der auf sie mehrmals kommen Bildschirmschoner mit):

% gcc -Wall ScreenSaverMonitor.m ScreenSaverMonitorMain.m -o ScreenSaverMonitor -lobjc -framework Cocoa 
% ./ScreenSaverMonitor 
running loop (^C to quit)... 
^C 
% 

Meine Objective-C und Cocoa Wissen ist sehr rostig, daher bin ich mir nicht sicher, ob ich das Framework falsch verwende oder ob ich mich für die falschen Ereignisse registriert habe (und auch nicht, wo ich nachsehen muss, ob das die richtigen Ereignisse sind oder nicht).

Also was mache ich falsch?

Antwort

9

Sie haben Ihr Problem bereits kommentiert.

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

Das oben genannte ist fast immer eine schlechte Idee.

NSDistributedNotificationCenter benötigt zur Ausführung tatsächlich einen laufenden Haupt-Thread NSRunLoop.

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

Erstellen und eine Laufschleife von dem main() einer Kommandozeilen-Anwendung auf OS X Spinnen ist eine ziemlich einfache Sache zu tun. Es gibt viele Beispiele mit einer schnellen Suche.

+0

Gute Idee! Ich habe 'while (1);' durch '[[NSRunLoop currentRunLoop] run];' ersetzt, aber immer noch keine Würfel. – rampion

+0

Ich bin mir nicht sicher, worauf Sie hier stoßen. Ich habe Ihren bearbeiteten Code oben genommen, einen Compiler-Fehler behoben und geringfügige Protokollierungsänderungen vorgenommen, und es scheint mir gut zu funktionieren. Insbesondere habe ich die Zeile #import in #import geändert und die printf-Anweisungen in fprintf in stderr geändert. (Dies funktioniert besser, da stderr sofort geleert und nicht gepuffert wird wie printf. – GoannaGuy

+2

Meine optimierte Version, die ich in einer einzigen Quelldatei zusammenfasste, ist hier verfügbar: http://pastie.org/8013106 Sie enthält einen modifizierten Build Befehl an der Unterseite, die ein bisschen schneller baut, da es gegen Foundation.framework statt der größeren Cocoa.framework linken (aber sollte entweder gut funktionieren) – GoannaGuy

2

Es scheint, dass die Strategie, die Sie verwenden möchten, nicht funktioniert, da die Benachrichtigungen von com.apple.screensaver. * Nicht mehr unterstützt werden.
In den Antworten auf this equivalent question heißt es: "Für Snow Leopard sind die Meldungen screenIsLocked und screenIsUnlocked nicht mehr verfügbar."
Sie können sich für Bildschirmschoner registrieren, was natürlich nicht das Gleiche ist, aber eine akzeptable Alternative für Sie darstellt, indem Sie die NSWorkspaceScreensDidSleepNotification-Benachrichtigung abhören oder den Computer in den Ruhezustand versetzen, indem Sie die NSWorkspaceWillSleepNotification abhören. Beispielcode kann on this forum gefunden werden.

Nebenbei bemerkt: Wenn Sie Null für den Namen verwenden, werden Sie viele Veranstaltungen erhalten:

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

Wenn Sie das tun, werden Sie sehen, dass Sie alles, was im Grunde richtig machen, weil Sie alle erhalten Art von Ereignissen - aber keine Bildschirmschoner.

+1

Ab 10.10 werden die Benachrichtigungen von com.apple.screensaver. * Weiterhin gesendet (ebenso wie screenIsLocked/screenIsUnlocked). Mit NSDistributedNotificationCenter können Sie sich nicht für alle Benachrichtigungen registrieren, zumindest nicht in einer Sandbox-App. Sie erhalten die Warnung, "*** versuchen, sich für alle verteilten Benachrichtigungen, die durch Sandboxing vereitelt werden, zu registrieren." – zpasternack

5

Edit: weitere Tests haben gezeigt, dass com.apple.screensaver.didlaunch auch verfügbar ist, hier der Code auf 10.6.8 getestet und 10.8.4

wird Ihr Code funktioniert, wenn Sie [[NSRunLoop currentRunLoop] run]; entfernen und initialisieren ScreenSaverMonitor von einer applicationDidFinishLaunching: Methode der Cocoa-Anwendung . (Erstellen Sie einfach ein neues Cocoa-Anwendungsprojekt in XCode und fügen Sie gegebenenfalls Ihren Code hinzu).

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); 
} 
Verwandte Themen