2013-06-05 11 views
12

Desidero monitorare lo screensaver e gli eventi lockscreen su un box OSX. Come primo passo, sto bene con loro solo stampando sulla console.Monitoraggio eventi salvaschermo in OSX

seguito the advice of another's question, ho scritto qualche Objective C per l'ascolto di cacao notifiche per le com.apple.screensaver.didstart, com.apple.screensaver.didstop, com.apple.screenIsLocked e com.apple.screenIsUnlocked eventi.

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

Si compila bene, ma quando l'eseguo, non mi sembra di osservare tutti gli eventi screensaver (pur avendo il salvaschermo si accende più volte):

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

mio Objective C e Cocoa la conoscenza è molto arrugginita, quindi non sono sicuro se sto usando il framework sbagliato, o se mi sono registrato per gli eventi sbagliati (né dove cercare se sono gli eventi giusti o meno).

Così che cosa è che sto facendo male?

risposta

9

Hai già commentato il tuo problema.

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

Quanto sopra è SEMPRE una cattiva idea.

NSDistributedNotificationCenter realtà richiede un running NSRunLoop thread principale per operare.

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

Creazione e girare un ciclo fuga dalla main() di un'applicazione a riga di comando su OS X è una cosa abbastanza semplice da fare. Ci sono molti esempi disponibili con una ricerca rapida.

+0

Buona idea! Ho sostituito 'while (1);' con '[[NSRunLoop currentRunLoop] run];', ma ancora nessun dado. – rampion

+0

Non sono sicuro di cosa stai incontrando qui. Ho preso in precedenza il codice modificato, corretto un errore del compilatore e apportato modifiche minori alla registrazione, e sembra funzionare bene per me. Nello specifico, ho modificato la riga #import in #import e ho modificato le istruzioni printf in fprintf in stderr. (Funziona meglio come stderr viene svuotato immediatamente piuttosto che bufferato come printf. – GoannaGuy

+2

In realtà, la mia versione ottimizzata, che ho consolidato in un unico file sorgente, è disponibile qui: http://pastie.org/8013106 Include una build modificata comando in basso che si costruisce un po 'più veloce, poiché si collega a Foundation.framework invece che al più grande Cocoa.framework (ma dovrebbe funzionare bene) – GoannaGuy

2

Sembra la strategia si sta cercando di utilizzare per questo non funzionerà, perché la com.apple.screensaver. * Le notifiche non sono più supportati.
Nelle risposte al this equivalent question, si è detto che: 'per Snow Leopard le notifiche screenIsLocked e screenIsUnlocked non sono più disponibili.'
È possibile registrarsi per schermo dorme, che ovviamente non è la stessa, ma può essere un'alternativa accettabile per voi, ascoltando la notifica NSWorkspaceScreensDidSleepNotification, o al computer di andare a dormire ascoltando il NSWorkspaceWillSleepNotification. Il codice di esempio può essere trovato on this forum.

Nota a margine: se si usa nil per il nome, si riceverà un sacco di eventi:

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

Se non che, si vedrà che si sta facendo tutto in fondo a destra, perché riceverai tutte tipo di eventi - ma nessun salvaschermo.

+1

A partire da 10.10, le notifiche di com.apple.screensaver. * Vengono comunque inviate (così come screenIsLocked/screenIsUnlocked). Inoltre, 'NSDistributedNotificationCenter' non ti consente di registrarti per tutte le notifiche, almeno in un'app sandbox. Si ottiene l'avviso, "*** tenta di registrarsi per tutte le notifiche distribuite sventate dalla sandboxing." – zpasternack

5

Edit: ulteriori test hanno dimostrato che com.apple.screensaver.didlaunch è anche disponibile, il codice qui è testato su 10.6.8 e 10.8.4

Il codice funziona se si rimuove [[NSRunLoop currentRunLoop] run]; e inizializzare ScreenSaverMonitor dal metodo di un'applicazione Cocoa applicationDidFinishLaunching: . (Basta creare un nuovo progetto di applicazione Cocoa in XCode e aggiungere il codice, se appropriato).

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); 
} 
Problemi correlati