2011-01-06 14 views
0

Ich schreibe ein Befehlszeilen-Foundation-Tool in Mac OS X und möchte das Tool auf einem Tastendruck wie "q" beenden. Der Code startet eine asynchrone Anforderung zum Abrufen von Daten von einem Remote-Server. Dies erfordert den NSRunLoop. Zumindest verstehe ich, dass ich das tun muss.Stop NSRunLoop auf Keypress

Kann mir jemand sagen, wie man den Runloop auf dem spezifischen Tastendruck stoppt?

Unten ist das Code-Snippet.

int main (int argc, const char * argv[]) { 

BOOL keepRunning = YES; 
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 

Requestor *myRequestor = [[Requestor alloc] init]; 
[myRequestor GetData]; 

NSRunLoop *runLoop; 
runLoop = [NSRunLoop currentRunLoop]; 

while (keepRunning && [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]); 

[pool drain]; 
return 0; 
} 

Vielen Dank!

Antwort

3

Ich habe dies nicht selbst getan, aber ich würde erwarten, dass Sie [[NSFileHandle fileHandleWithStandardInput] readInBackgroundAndNotify] verwenden und registrieren möchten, um die NSFileHandleReadCompletionNotification Benachrichtigung zu erhalten. Wenn Sie ein "q" erhalten, tun Sie, was immer Sie benötigen, und rufen Sie exit().

0

Nun, meine anfänglichen Theorien und Experimente, die mit Ihrem vorhandenen Code beginnen, sind nicht viel in der Art von verwendbarem Code erschienen.

Ich stelle mir vor, dass Sie nach etwas suchen, wie Sie unter Windows etwas in einem Kommandozeilen-Shell-Fenster ausführen können, und wenn der Prozess beendet ist, sagt es etwa so aus: Drücken Sie die Q-Taste weitermachen...". Wenn Sie das Fenster nach vorne bringen (wenn es nicht schon ganz vorne ist) und die Q-Taste drücken, wird das Fenster geschlossen.

Planen Sie, dieses Befehlszeilentool von Ihrer primären Anwendung aus aufzurufen, oder ist dieses Befehlszeilentool etwas, mit dem der Endbenutzer direkt interagiert? (Wenn sie zum Beispiel von einem Terminal-Fenster aus aufgerufen würden, hmm, dann könnte Kens Code wahrscheinlich mit meinem kombiniert werden, um Folgendes zu machen: Beachten Sie, dass dies in der aktuellen Form nur funktioniert, wenn Sie drücken Q und dann drücken Sie die Eingabetaste?

#import <Cocoa/Cocoa.h> 

@interface Requestor : NSObject <NSApplicationDelegate> { 
    BOOL   gotData; 
    NSFileHandle *stdIn; 
} 
- (void)getData; 
- (void)requestorGotData:(id)sender; 
@end 

@implementation Requestor 

- (id)init { 
    if (self = [super init]) { 
     gotData = NO; 
     stdIn = nil; 
     [NSApp setDelegate:self]; 
    } 
    return self; 
} 

- (void)getData { 
    NSLog(@"getting data........."); 
    gotData = NO; 

    [self performSelector:@selector(requestorGotData:) 
       withObject:nil 
       afterDelay:5.0]; 
} 

Pause

- (void)requestorGotData:(id)sender { 
    NSLog(@"got data"); 
    gotData = YES; 
    NSLog(@"Press 'Q' key to continue..."); 
    stdIn = [[NSFileHandle fileHandleWithStandardInput] retain]; 
    [[NSNotificationCenter defaultCenter] 
     addObserver:self 
      selector:@selector(fileHandleReadCompletion:) 
       name:NSFileHandleReadCompletionNotification 
      object:stdIn]; 
    [stdIn readInBackgroundAndNotify]; 
} 

- (void)fileHandleReadCompletion:(NSNotification *)notification { 
    NSLog(@"fileHandleReadCompletion:"); 
    NSData *data = [[notification userInfo] 
        objectForKey:NSFileHandleNotificationDataItem]; 
    NSLog(@"data == %@", data); 
    NSString *string = [[[NSString alloc] 
          initWithData:data 
         encoding:NSUTF8StringEncoding] autorelease]; 
    if (string) { 
     string = [string stringByTrimmingCharactersInSet: 
        [NSCharacterSet whitespaceAndNewlineCharacterSet]]; 
     if ([[string lowercaseString] isEqualToString:@"q"]) { 
      [stdIn closeFile]; 
      [stdIn release]; 
      [[NSNotificationCenter defaultCenter] removeObserver:self]; 
      [NSApp terminate:nil]; 
     } else { 
      [stdIn readInBackgroundAndNotify]; 
     } 
    } 
} 
@end 

Pause

int main (int argc, const char * argv[]) { 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 

    [NSApplication sharedApplication]; 

    Requestor *requestor = [[Requestor alloc] init]; 
    [requestor getData]; 

    [NSApp run]; 

    [requestor release]; 

    [pool drain]; 
    return 0; 
} 
+0

Ich war neugierig, also kompilierte ich es (Entfernen der Requestor-Zeilen). Es baut und läuft, nutzt aber 100% CPU und das Schlagen q tut nichts;) Werden Ereignisse ohne Fenster so erfasst? Scheint wie libcurses ist der Standard Weg, damit umzugehen. – d11wtq

+0

Ich denke, er will ein q auf der stdin Rohr, nicht ein Tastendruck, wenn die "App hat Fokus". Ein Befehlszeilenprogramm hat niemals den Fokus. Portable Unix-Programme können sicherlich mit dem Benutzer über die Tastatur interagieren. – Ken

+0

@Ken: einverstanden. Versucht, Ihre Methode zu enthüllen und es funktioniert, obwohl es in seiner aktuellen Form erfordert der Benutzer nach dem Buchstaben Q drücken .... – NSGod

0

Wenn Sie nicht bereits libcurses betrachtet haben, helfen, dass vielleicht Sie. Es Es ist wirklich einfach, Tastenanschläge damit zu fangen, aber was ich nicht 100% ig bin, ist, wenn Sie es zum Funktionieren bringen können, ohne das gesamte Terminalfenster zu benutzen.

Die Flüche biss allein ist nur:

#include <ncurses.h> 

initscr(); 

/* snip */ 

char c; 
while (c = getch()) { 
    if (c == 'q') { 
    // Put your cleanup and shutdown logic here 
    } 

    /* any other keypresses you might want to handle */ 
} 

EDIT | Sie wollen diese enge Schleife wahrscheinlich nicht in Ihre Laufschleife einfügen ... rufen Sie einfach jedes Mal, wenn der Runloop tickt, getch() an.