import AppKit // MARK: - Event Capture Window class EventCaptureWindow: NSWindow { override var canBecomeKey: Bool { return true } override var canBecomeMain: Bool { return true } override func sendEvent(_ event: NSEvent) { // During screenshot selection, we want to capture ALL events // and prevent them from reaching other windows switch event.type { case .leftMouseDown, .leftMouseUp, .leftMouseDragged, .rightMouseDown, .rightMouseUp, .rightMouseDragged, .otherMouseDown, .otherMouseUp, .otherMouseDragged, .mouseMoved, .mouseEntered, .mouseExited, .scrollWheel, .keyDown, .keyUp: // Process the event normally through our view hierarchy super.sendEvent(event) // DO NOT pass the event to other windows - this prevents // other windows from being dragged or interacted with return default: // For other event types, allow normal processing super.sendEvent(event) } } } // MARK: - Event Capture View class EventCaptureView: NSView { weak var screenshotApp: ScreenshotApp? var shouldDisplayAllScreensActiveText: Bool = false // Nieuwe property override init(frame frameRect: NSRect) { super.init(frame: frameRect) setupView() } required init?(coder: NSCoder) { super.init(coder: coder) setupView() } private func setupView() { // This view will handle mouse events - no special setup needed self.wantsLayer = true // Zorg ervoor dat de view een layer heeft voor efficiënt tekenen } override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) // Belangrijk voor standaard teken gedrag if shouldDisplayAllScreensActiveText { // Teken "Alle Schermen Actief" tekst-overlay bovenaan het scherm van deze view let instructionText = "All Screens Mode, Click to Capture, ESC to Cancel" let attributes: [NSAttributedString.Key: Any] = [ .font: NSFont.systemFont(ofSize: 18, weight: .medium), .foregroundColor: NSColor.white.withAlphaComponent(0.9), .strokeColor: NSColor.black.withAlphaComponent(0.5), // Tekst outline .strokeWidth: -2.0, // Negatief voor outline binnen de letters .paragraphStyle: { let style = NSMutableParagraphStyle() style.alignment = .center return style }() ] let attributedString = NSAttributedString(string: instructionText, attributes: attributes) let textSize = attributedString.size() // self.bounds is de grootte van deze EventCaptureView, die het hele scherm beslaat. let viewBounds = self.bounds let textRect = NSRect(x: (viewBounds.width - textSize.width) / 2, y: viewBounds.height - textSize.height - 30, // 30px van de top van het scherm width: textSize.width, height: textSize.height) let backgroundPadding: CGFloat = 10 let backgroundRect = NSRect( x: textRect.origin.x - backgroundPadding, y: textRect.origin.y - backgroundPadding, width: textRect.width + (2 * backgroundPadding), height: textRect.height + (2 * backgroundPadding) ) let BORDER_RADIUS: CGFloat = 10 let textBackgroundPath = NSBezierPath(roundedRect: backgroundRect, xRadius: BORDER_RADIUS, yRadius: BORDER_RADIUS) NSColor.black.withAlphaComponent(0.4).setFill() textBackgroundPath.fill() attributedString.draw(in: textRect) // NSLog("🎨 EventCaptureView: Drew 'Alle Schermen Actief' text.") } } override func mouseDown(with event: NSEvent) { guard let app = screenshotApp else { // Even if app is nil, consume the event to prevent it from reaching other windows return } if app.isMultiMonitorSelectionActive && !app.isDragging { let globalLocation = NSEvent.mouseLocation print("🎯 Event capture - starting selection at: \(globalLocation)") // SET MOUSE TRACKING VARIABLES FOR SINGLE CLICK DETECTION let allScreenModifier: UInt = (1 << 0) // Command key app.isAllScreenModifierPressed = app.isModifierPressed(event.modifierFlags, modifier: allScreenModifier) app.mouseDownLocation = globalLocation app.mouseDownTime = CACurrentMediaTime() app.hasMouseMoved = false // Hide crosshairs during drag to prevent stuck crosshair issue hideCrosshairs() app.startDragSelection(at: globalLocation) } // DO NOT call super.mouseDown - this prevents the event from propagating } override func mouseDragged(with event: NSEvent) { guard let app = screenshotApp else { // Even if app is nil, consume the event to prevent it from reaching other windows return } if app.isMultiMonitorSelectionActive && app.isDragging { let globalLocation = NSEvent.mouseLocation app.hasMouseMoved = true // MARK THAT MOUSE HAS MOVED app.updateDragSelection(to: globalLocation) } // DO NOT call super.mouseDragged - this prevents the event from propagating } override func mouseUp(with event: NSEvent) { guard let app = screenshotApp else { // Even if app is nil, consume the event to prevent it from reaching other windows return } if app.isMultiMonitorSelectionActive && app.isDragging { let globalLocation = NSEvent.mouseLocation // CHECK FOR SINGLE CLICK FIRST let timeSinceMouseDown = CACurrentMediaTime() - app.mouseDownTime let distanceMoved = sqrt(pow(globalLocation.x - app.mouseDownLocation.x, 2) + pow(globalLocation.y - app.mouseDownLocation.y, 2)) print("🎯 EventCaptureView - mouse up at: \(globalLocation)") print("🎯 Time since down: \(timeSinceMouseDown)s, distance: \(distanceMoved)px, moved: \(app.hasMouseMoved), allScreenModifierPressed: \(app.isAllScreenModifierPressed), allScreensToggled: \(app.isAllScreensCaptureToggledOn)") // 1. NIEUW: Als "alle schermen" modus is GETOGGLED AAN, en het is een klik (geen drag) if app.isAllScreensCaptureToggledOn && !app.hasMouseMoved && distanceMoved < 5.0 && timeSinceMouseDown < 0.5 { print("🎯 Click detected (toggle ON) - capturing all screens") app.deactivateMultiMonitorSelection() app.captureAllScreens() // captureAllScreens reset zelf de toggle app.resetTrackingVariables() return } // 2. Prioriteit: Single click voor huidige scherm (als toggle NIET aanstaat) if !app.hasMouseMoved && distanceMoved < 5.0 && timeSinceMouseDown < 0.5 && !app.isAllScreenModifierPressed { print("🎯 Single click detected (toggle OFF) - capturing current screen") app.deactivateMultiMonitorSelection() app.captureCurrentScreen(at: globalLocation) app.resetTrackingVariables() // RESET for clean state return } // 4. Anders, normale selectie beëindigen print("🎯 Ending drag selection normally") app.endDragSelection(at: globalLocation) // Show crosshairs again after drag ends showCrosshairs() } // DO NOT call super.mouseUp - this prevents the event from propagating } override func rightMouseDown(with event: NSEvent) { // Handle right-click to cancel selection guard let app = screenshotApp else { return } if app.isMultiMonitorSelectionActive { print("🎯 Event capture - right-click, canceling selection") app.cancelMultiMonitorSelection() } // DO NOT call super.rightMouseDown - this prevents the event from propagating } override func rightMouseUp(with event: NSEvent) { // Consume right mouse up events during selection // DO NOT call super.rightMouseUp - this prevents the event from propagating } override func otherMouseDown(with event: NSEvent) { // Consume other mouse button events during selection // DO NOT call super.otherMouseDown - this prevents the event from propagating } override func otherMouseUp(with event: NSEvent) { // Consume other mouse button events during selection // DO NOT call super.otherMouseUp - this prevents the event from propagating } override func scrollWheel(with event: NSEvent) { // Consume scroll wheel events during selection // DO NOT call super.scrollWheel - this prevents the event from propagating } override func keyDown(with event: NSEvent) { // Only handle ESC key if multi-monitor selection is active if event.keyCode == 53 && screenshotApp?.isMultiMonitorSelectionActive == true { // ESC key screenshotApp?.cancelMultiMonitorSelection() return // Consume event } // The Command-key handling has been moved to the flagsChanged handler // in MultiMonitorSystem.swift to implement the toggle correctly. super.keyDown(with: event) } override func keyUp(with event: NSEvent) { // ... existing code ... super.keyUp(with: event) } override var acceptsFirstResponder: Bool { return true } override func becomeFirstResponder() -> Bool { print("⌨️ EventCaptureView becoming first responder") return super.becomeFirstResponder() } private func hideCrosshairs() { // Find all crosshair views in the window hierarchy and hide them if let window = self.window { findAndHideCrosshairs(in: window.contentView) } } private func showCrosshairs() { // Find all crosshair views in the window hierarchy and show them if let window = self.window { findAndShowCrosshairs(in: window.contentView) } } private func findAndHideCrosshairs(in view: NSView?) { guard let view = view else { return } for subview in view.subviews { if let crosshair = subview as? CrosshairCursorView { crosshair.stopTracking() } findAndHideCrosshairs(in: subview) } } private func findAndShowCrosshairs(in view: NSView?) { guard let view = view else { return } for subview in view.subviews { if let crosshair = subview as? CrosshairCursorView { crosshair.isHidden = false crosshair.startTracking() } findAndShowCrosshairs(in: subview) } } }