2010-12-23 67 views
10

我正在尋找方式讓我的應用程序在用戶使用Command-Shift-3Command-Shift-4截取屏幕截圖時收到通知。當用戶截圖時檢測到

一個例子是Droplr和Cloud App等應用程序自動上傳截圖。

我一直在四處搜尋,發現它可能與達爾文通知有關,但我不確定從哪裏開始。

+0

看看這個類似的問題:http://stackoverflow.com/questions/2815502/自動截圖上傳在Mac上就像雲應用程序,這似乎有一個很好的答案 – 2010-12-23 08:22:45

+0

這是一個很好的答案,我會看看。謝謝。 – Joshua 2010-12-23 11:42:35

+0

剛發佈我的答案:http://stackoverflow.com/questions/4516852/detect-when-a-user-takes-a-screenshot/4519189#4519189。 – Joshua 2010-12-23 13:34:30

回答

-3

youll必須註冊一個對象,以收到系統通知,當用戶需要一個屏幕截圖

這樣:

[[NSNotificationCenter defaultCenter] addObserver: theObjectToRecieveTheNotification selector:@selector(theMethodToPerformWhenNotificationIsRecieved) name:@"theNameOftheScreenCapturedNotification" object: optionallyAnObjectOrArgumentThatIsPassedToTheMethodToBecalled]; 

不知道通知的名字是什麼,但它可能是在那裏。

不要忘記註銷自己以及在dealloc中:

[NSNotificationCenter defaultCenter] removeObserver:自我]。

+3

我已經知道如何做,但問題是知道要觀察的通知。據我所知,當用戶截圖時沒有一個。 – Joshua 2010-12-23 11:34:07

3

這是怎麼我都做到了,這是一個有點複雜,但我會盡量帶你通過一步一步來:


在我們開始之前,你頭文件聲明如下變量和方法:

BOOL shouldObserveDesktop; 
NSDictionary *knownScreenshotsOnDesktop; 
NSString *screenshotLocation; 
NSString *screenshotFilenameSuffix; 

- (void)startObservingDesktop; 
- (void)stopObservingDesktop; 
- (NSDictionary *)screenshotsOnDesktop; 
- (NSDictionary *)screenshotsAtPath:(NSString *)dirpath modifiedAfterDate:(NSDate *)lmod; 
- (void)checkForScreenshotsAtPath:(NSString *)dirpath; 
- (NSDictionary *)findUnprocessedScreenshotsOnDesktop; 

現在,在您實現文件,首先添加以下代碼:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 
    screenshotLocation = [[NSString stringWithString:@"~/Desktop"] retain]; 
    screenshotFilenameSuffix = [[NSString stringWithString:@".png"] retain]; 
    knownScreenshotsOnDesktop = [[self screenshotsOnDesktop] retain]; 
    [self startObservingDesktop]; 
} 

設置所有方法被調用時的變量。接下來,添加:

- (void)onDirectoryNotification:(NSNotification *)n { 
    id obj = [n object]; 
    if (obj && [obj isKindOfClass:[NSString class]]) { 
     [self checkForScreenshotsAtPath:screenshotLocation]; 
    } 
} 

- (void)startObservingDesktop { 
    if (shouldObserveDesktop) 
     return; 
    NSDistributedNotificationCenter *dnc = [NSDistributedNotificationCenter defaultCenter]; 
    [dnc addObserver:self selector:@selector(onDirectoryNotification:) name:@"com.apple.carbon.core.DirectoryNotification" object:nil suspensionBehavior:NSNotificationSuspensionBehaviorDeliverImmediately]; 
    shouldObserveDesktop = YES; 
} 

- (void)stopObservingDesktop { 
    if (!shouldObserveDesktop) 
     return; 
    NSDistributedNotificationCenter *dnc = [NSDistributedNotificationCenter defaultCenter]; 
    [dnc removeObserver:self name:@"com.apple.carbon.core.DirectoryNotification" object:nil]; 
    shouldObserveDesktop = NO; 
} 

這裏我們觀察進行屏幕截圖時將被調用,它傳遞的方法調用(在這種情況下onDirectoryNotification:)的通知。也有停止觀察桌面/通知的方法。通知調用checkForScreenshotsAtPath:,它將檢查桌面上的屏幕截圖。以下是該方法的代碼,它調用其他方法:

-(void)checkForScreenshotsAtPath:(NSString *)dirpath {   
    NSDictionary *files; 
    NSArray *paths; 

    // find new screenshots 
    if (!(files = [self findUnprocessedScreenshotsOnDesktop])) 
     return; 

    // sort on key (path) 
    paths = [files keysSortedByValueUsingComparator:^(id a, id b) { return [b compare:a]; }]; 

    // process each file 
    for (NSString *path in paths) { 
     // Process the file at the path 
    } 
} 

-(NSDictionary *)findUnprocessedScreenshotsOnDesktop { 
    NSDictionary *currentFiles; 
    NSMutableDictionary *files; 
    NSMutableSet *newFilenames; 

    currentFiles = [self screenshotsOnDesktop]; 
    files = nil; 

    if ([currentFiles count]) { 
     newFilenames = [NSMutableSet setWithArray:[currentFiles allKeys]]; 
     // filter: remove allready processed screenshots 
     [newFilenames minusSet:[NSSet setWithArray:[knownScreenshotsOnDesktop allKeys]]]; 
     if ([newFilenames count]) { 
      files = [NSMutableDictionary dictionaryWithCapacity:1]; 
      for (NSString *path in newFilenames) { 
       [files setObject:[currentFiles objectForKey:path] forKey:path]; 
      } 
     } 
    } 

    knownScreenshotsOnDesktop = currentFiles; 
    return files; 
} 

-(NSDictionary *)screenshotsOnDesktop { 
    NSDate *lmod = [NSDate dateWithTimeIntervalSinceNow:-5]; // max 5 sec old 
    return [self screenshotsAtPath:screenshotLocation modifiedAfterDate:lmod]; 
} 

他們是第3種方法,反過來電話通知和下面的代碼是最後的方法screenshotsAtPath:modifiedAfterDate:我會提醒你的是極長的,因爲它要確認該文件絕對是截圖:

-(NSDictionary *)screenshotsAtPath:(NSString *)dirpath modifiedAfterDate:(NSDate *)lmod { 
    NSFileManager *fm = [NSFileManager defaultManager]; 
    NSArray *direntries; 
    NSMutableDictionary *files = [NSMutableDictionary dictionary]; 
    NSString *path; 
    NSDate *mod; 
    NSError *error; 
    NSDictionary *attrs; 

    dirpath = [dirpath stringByExpandingTildeInPath]; 

    direntries = [fm contentsOfDirectoryAtPath:dirpath error:&error]; 
    if (!direntries) { 
     return nil; 
    } 

    for (NSString *fn in direntries) { 

     // always skip dotfiles 
     if ([fn hasPrefix:@"."]) { 
      //[log debug:@"%s skipping: filename begins with a dot", _cmd]; 
      continue; 
     } 

     // skip any file not ending in screenshotFilenameSuffix (".png" by default) 
     if (([fn length] < 10) || 
      // ".png" suffix is expected 
      (![fn compare:screenshotFilenameSuffix options:NSCaseInsensitiveSearch range:NSMakeRange([fn length]-5, 4)] != NSOrderedSame) 
      ) 
     { 
      continue; 
     } 

     // build path 
     path = [dirpath stringByAppendingPathComponent:fn]; 

     // Skip any file which name does not contain a space. 
     // You want to avoid matching the filename against 
     // all possible screenshot file name schemas (must be hundreds), we make the 
     // assumption that all language formats have this in common: it contains at least one space. 
     if ([fn rangeOfString:@" "].location == NSNotFound) { 
      continue; 
     } 

     // query file attributes (rich stat) 
     attrs = [fm attributesOfItemAtPath:path error:&error]; 
     if (!attrs) { 
      continue; 
     } 

     // must be a regular file 
     if ([attrs objectForKey:NSFileType] != NSFileTypeRegular) { 
      continue; 
     } 

     // check last modified date 
     mod = [attrs objectForKey:NSFileModificationDate]; 
     if (lmod && (!mod || [mod compare:lmod] == NSOrderedAscending)) { 
      // file is too old 
      continue; 
     } 

     // find key for NSFileExtendedAttributes 
     NSString *xattrsKey = nil; 
     for (NSString *k in [attrs keyEnumerator]) { 
      if ([k isEqualToString:@"NSFileExtendedAttributes"]) { 
       xattrsKey = k; 
       break; 
      } 
     } 
     if (!xattrsKey) { 
      // no xattrs 
      continue; 
     } 
     NSDictionary *xattrs = [attrs objectForKey:xattrsKey]; 
     if (!xattrs || ![xattrs objectForKey:@"com.apple.metadata:kMDItemIsScreenCapture"]) { 
      continue; 
     } 

     // ok, let's use this file 
     [files setObject:mod forKey:path]; 
    } 

    return files; 
} 

嗯,有你有它。這就是我在用戶截圖時能夠檢測到的情況,它可能有一些錯誤,但目前看起來工作正常。如果你想在這裏的所有代碼是它在pastebin的鏈接。COM:

- http://pastebin.com/gBAbCBJB

實現 - http://pastebin.com/VjQ6P3zQ