Skip to content

Instantly share code, notes, and snippets.

@ts95
Last active February 14, 2022 19:49
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save ts95/300c5a815393087c72cc to your computer and use it in GitHub Desktop.
Save ts95/300c5a815393087c72cc to your computer and use it in GitHub Desktop.
OS X detect new screenshot event with Swift
import Foundation
typealias NewFileCallback = (fileURL: NSURL) -> Void
class ScreenshotDetector: NSObject, NSMetadataQueryDelegate {
let query = NSMetadataQuery()
var newFileCallback: NewFileCallback?
override init() {
super.init()
let center = NSNotificationCenter.defaultCenter()
center.addObserver(self, selector: Selector("queryUpdated:"), name: NSMetadataQueryDidStartGatheringNotification, object: query)
center.addObserver(self, selector: Selector("queryUpdated:"), name: NSMetadataQueryDidUpdateNotification, object: query)
center.addObserver(self, selector: Selector("queryUpdated:"), name: NSMetadataQueryDidFinishGatheringNotification, object: query)
query.delegate = self
query.predicate = NSPredicate(format: "kMDItemIsScreenCapture = 1")
query.startQuery()
}
deinit {
query.stopQuery()
}
func queryUpdated(notification: NSNotification) {
if let userInfo = notification.userInfo {
for v in userInfo.values {
let items = v as! [NSMetadataItem]
if items.count > 0 {
let item = items[0]
if let filename = item.valueForAttribute("kMDItemFSName") as? String {
let filenameWithPath = NSString(string: "~/Desktop/" + filename).stringByExpandingTildeInPath
let url = NSURL(fileURLWithPath: filenameWithPath, isDirectory: false)
if let cb = self.newFileCallback {
cb(fileURL: url)
}
}
}
}
}
}
}
////////////////////////////
// Usage //
////////////////////////////
// Because this object is observing events it should stay
// in memory for the duration of its usage.
// In a view controller for instance it should be allocated
// in the class scope. If its reference is stored inside
// a method it will be deallocated automatically when the
// method returns and consequently stop obsering any events.
let detector = ScreenshotDetector()
// The actual callback can be assigned anywhere there's
// a reference to the instance.
detector.newFileCallback = { fileURL in
// fileURL is an NSURL instance of the screenshot file.
}
@Kodi-BilFlix
Copy link

Hi,
I tried to call this class, but I made a mistake.

2020-02-09 19:00:51.389151+0100 XXX [59278:4184587] -[XXX.ScreenshotDetector queryUpdated:]: unrecognized selector sent to instance 0x600000221400
2020-02-09 19:00:51.389514+0100 XXX[59278:4184587] Failed to set (contentViewController) user defined inspected property on (NSWindow): -[XXX.ScreenshotDetector queryUpdated:]: unrecognized selector sent to instance 0x600000221400
2020-02-09 19:00:51.876467+0100 XXX[59278:4184587] -[XXX.ScreenshotDetector queryUpdated:]: unrecognized selector sent to instance 0x600000221400
2020-02-09 19:00:51.912782+0100 XXX[59278:4184587] [General] -[XXX.ScreenshotDetector queryUpdated:]: unrecognized selector sent to instance 0x600000221400
please help me

@jsproull
Copy link

Does this require sandbox permissions? I'm not receiving any notifications.

@ts95
Copy link
Author

ts95 commented Dec 16, 2020

I'm pretty sure this approach to subscribing to screenshot updates doesn't work anymore. It broke a couple of years ago and I haven't looked further into it since.

@jsproull
Copy link

Yeah looks like if I remove sandboxing it works. Which is fine for my demo app. There might be an entitlement I can set but for now that's fine. 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment