I would like to implement the same kind of behavior as the Dropoverapp application, specifically being able to perform a specific action when files are dragged (such as opening a window, for example).
I have written the code below to capture the mouse coordinates, drag, drop, and click globally. However, I don't know how to determine the nature of what is being dropped. Do you have any ideas on how to detect the nature of what is being dragged outside the application's scope?
Here is my current code:
import SwiftUI import CoreGraphics struct ContentView: View { @State private var mouseX: CGFloat = 0.0 @State private var mouseY: CGFloat = 0.0 @State private var isClicked: Bool = false @State private var isDragging: Bool = false private var mouseTracker = MouseTracker.shared var body: some View { VStack { Text("Mouse coordinates: \(mouseX, specifier: "%.2f"), \(mouseY, specifier: "%.2f")") .padding() Text(isClicked ? "Mouse is clicked" : "Mouse is not clicked") .padding() Text(isDragging ? "Mouse is dragging" : "Mouse is not dragging") .padding() } .frame(width: 400, height: 200) .onAppear { mouseTracker.startTracking { newMouseX, newMouseY, newIsClicked, newIsDragging in self.mouseX = newMouseX self.mouseY = newMouseY self.isClicked = newIsClicked self.isDragging = newIsDragging } } } } class MouseTracker { static let shared = MouseTracker() private var eventTap: CFMachPort? private var runLoopSource: CFRunLoopSource? private var isClicked: Bool = false private var isDragging: Bool = false private var callback: ((CGFloat, CGFloat, Bool, Bool) -> Void)? func startTracking(callback: @escaping (CGFloat, CGFloat, Bool, Bool) -> Void) { self.callback = callback let mask: CGEventMask = (1 << CGEventType.mouseMoved.rawValue) | (1 << CGEventType.leftMouseDown.rawValue) | (1 << CGEventType.leftMouseUp.rawValue) | (1 << CGEventType.leftMouseDragged.rawValue) // Pass 'self' via 'userInfo' let selfPointer = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque()) guard let eventTap = CGEvent.tapCreate( tap: .cghidEventTap, place: .headInsertEventTap, options: .defaultTap, eventsOfInterest: mask, callback: MouseTracker.mouseEventCallback, userInfo: selfPointer ) else { print("Failed to create event tap") return } self.eventTap = eventTap runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0) CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, .commonModes) CGEvent.tapEnable(tap: eventTap, enable: true) } // Static callback function private static let mouseEventCallback: CGEventTapCallBack = { _, eventType, event, userInfo in guard let userInfo = userInfo else { return Unmanaged.passUnretained(event) } // Retrieve the instance of MouseTracker from userInfo let tracker = Unmanaged<MouseTracker>.fromOpaque(userInfo).takeUnretainedValue() let location = NSEvent.mouseLocation // Update the click and drag state switch eventType { case .leftMouseDown: tracker.isClicked = true tracker.isDragging = false case .leftMouseUp: tracker.isClicked = false tracker.isDragging = false case .leftMouseDragged: tracker.isDragging = true default: break } // Call the callback on the main thread DispatchQueue.main.async { tracker.callback?(location.x, location.y, tracker.isClicked, tracker.isDragging) } return Unmanaged.passUnretained(event) } }