我正在尋找方式讓我的應用程序在用戶使用Command-Shift-3
或Command-Shift-4
截取屏幕截圖時收到通知。當用戶截圖時檢測到
一個例子是Droplr和Cloud App等應用程序自動上傳截圖。
我一直在四處搜尋,發現它可能與達爾文通知有關,但我不確定從哪裏開始。
我正在尋找方式讓我的應用程序在用戶使用Command-Shift-3
或Command-Shift-4
截取屏幕截圖時收到通知。當用戶截圖時檢測到
一個例子是Droplr和Cloud App等應用程序自動上傳截圖。
我一直在四處搜尋,發現它可能與達爾文通知有關,但我不確定從哪裏開始。
這是在之前的評論中提及了,但是你可以使用一個NSMetadataQuery
搜索文件,其中kMDItemIsScreenCapture = 1
。這是一個添加到屏幕截圖文件中的特殊屬性。
我剛剛颳起顯示如何做到這一點的演示,並張貼在GitHub上:
https://github.com/davedelong/Demos/blob/master/ScreenShot%20Detector
youll必須註冊一個對象,以收到系統通知,當用戶需要一個屏幕截圖
這樣:
[[NSNotificationCenter defaultCenter] addObserver: theObjectToRecieveTheNotification selector:@selector(theMethodToPerformWhenNotificationIsRecieved) name:@"theNameOftheScreenCapturedNotification" object: optionallyAnObjectOrArgumentThatIsPassedToTheMethodToBecalled];
不知道通知的名字是什麼,但它可能是在那裏。
不要忘記註銷自己以及在dealloc中:
[NSNotificationCenter defaultCenter] removeObserver:自我]。
我已經知道如何做,但問題是知道要觀察的通知。據我所知,當用戶截圖時沒有一個。 – Joshua 2010-12-23 11:34:07
這是怎麼我都做到了,這是一個有點複雜,但我會盡量帶你通過一步一步來:
在我們開始之前,你頭文件聲明如下變量和方法:
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://stackoverflow.com/questions/2815502/自動截圖上傳在Mac上就像雲應用程序,這似乎有一個很好的答案 – 2010-12-23 08:22:45
這是一個很好的答案,我會看看。謝謝。 – Joshua 2010-12-23 11:42:35
剛發佈我的答案:http://stackoverflow.com/questions/4516852/detect-when-a-user-takes-a-screenshot/4519189#4519189。 – Joshua 2010-12-23 13:34:30