diff --git a/Sources/COpenSwiftUI/Shims/UIKit/_UIHitTestContext.h b/Sources/COpenSwiftUI/Shims/UIKit/_UIHitTestContext.h index 6928bec73..5913fe238 100644 --- a/Sources/COpenSwiftUI/Shims/UIKit/_UIHitTestContext.h +++ b/Sources/COpenSwiftUI/Shims/UIKit/_UIHitTestContext.h @@ -27,7 +27,7 @@ NS_HEADER_AUDIT_BEGIN(nullability, sendability) @end OPENSWIFTUI_EXPORT -_UIHitTestContext * _Nullable _UICurrentHitTestContext(void) OPENSWIFTUI_SWIFT_NAME(getter:_UIHitTestContext.current); +_UIHitTestContext * _Nullable _UICurrentHitTestContext(void) OPENSWIFTUI_SWIFT_NAME(getter:_UIHitTestContext.current()); NS_HEADER_AUDIT_END(nullability, sendability) diff --git a/Sources/OpenSwiftUI/Integration/Hosting/AppKit/View/NSHostingView.swift b/Sources/OpenSwiftUI/Integration/Hosting/AppKit/View/NSHostingView.swift index 8f9df1243..8589471dc 100644 --- a/Sources/OpenSwiftUI/Integration/Hosting/AppKit/View/NSHostingView.swift +++ b/Sources/OpenSwiftUI/Integration/Hosting/AppKit/View/NSHostingView.swift @@ -116,6 +116,8 @@ open class NSHostingView: NSView, XcodeViewDebugDataProvider where Cont package let eventBindingManager = EventBindingManager() + private var hitTestEventMonitor: Any? + private lazy var eventBindingSource = BindingSource(hostingView: self) private lazy var eventBridge = AppKitEventBindingBridge( @@ -284,7 +286,20 @@ open class NSHostingView: NSView, XcodeViewDebugDataProvider where Cont eventBindingManager.delegate = self } HostingViewRegistry.shared.add(self) - // TODO + if _eventDebugTriggers.contains(.hitTest) { + hitTestEventMonitor = NSEvent.addLocalMonitorForEvents(matching: .leftMouseDown) { [weak self] event in + guard let self, event.window === self.window else { + return event + } + guard sequence(first: self as NSView, next: { $0.superview }) + .dropFirst().first(ofType: HostingViewProtocol.self) == nil else { + return event + } + let point = self.convert(event.locationInWindow, from: nil) + self.printHitTest(point) + return event + } + } Update.end() // TODO setNeedsUpdate() @@ -307,6 +322,9 @@ open class NSHostingView: NSView, XcodeViewDebugDataProvider where Cont updateRemovedState() // TODO HostingViewRegistry.shared.remove(self) + if let hitTestEventMonitor { + NSEvent.removeMonitor(hitTestEventMonitor) + } } /// The renderer configuration of the hosting view. diff --git a/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingView.swift b/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingView.swift index 64293daea..10cb85993 100644 --- a/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingView.swift +++ b/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingView.swift @@ -445,6 +445,45 @@ open class _UIHostingView: UIView, XcodeViewDebugDataProvider where Con foreignSubviews.remove(subview) } + // Audited for 6.5.4 + override dynamic open func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + printHitTestIfNeeded(at: point, with: event) + let result = super.hitTest(point, with: event) + guard GestureContainerFeature.isEnabled, + _UIHitTestContext.current != nil || CoreTesting.isRunning + else { + return result + } + if let result, foreignSubviews.allObjects.contains(where: { result.isDescendant(of: $0) }) { + return result + } + currentEvent = event + guard !UIViewIgnoresTouchEvents(self), self.point(inside: point, with: event) else { + return nil + } + return self + } + + // Audited for 6.5.4 + private func printHitTestIfNeeded(at point: CGPoint, with event: UIEvent?) { + guard _eventDebugTriggers.contains(.hitTest), let event, event.type == .touches else { + return + } + guard sequence(first: self as UIView, next: { $0.superview }) + .dropFirst().first(ofType: HostingViewProtocol.self) == nil + else { + return + } + let usesGestureContainer = GestureContainerFeature.isEnabled + let context = _UIHitTestContext.current + if usesGestureContainer { + guard let context else { return } + printHitTest(point, radius: context.radius) + } else { + guard context == nil else { return } + printHitTest(point) + } + } /// The UIKit notion of the safe area insets. open override var safeAreaInsets: UIEdgeInsets {