diff --git a/README.md b/README.md index faeaf25..940c580 100644 --- a/README.md +++ b/README.md @@ -67,3 +67,20 @@ class AppDelegate: UIResponder, UIApplicationDelegate { return true } ``` + + +#### Propagate touch events to other windows +The following configuration allows you to share a touch event received in one window with other windows. + +```swift +v.shouldPropagateEventAcrossWindows = true +``` + +In the given configuration, even when windows overlap, typically only one window receives a touch event. +Moreover, if a touch event starts in one window, such as Window A, it will only be responsive in Window A, even if it moves to another window, like Window B. + +Therefore, the touch event can be shared so that the marker of the tapped point will be displayed in the other window even in such a case. + + +## License +TouchTracker is released under the MIT License. See [LICENSE](./LICENSE) diff --git a/Sources/TouchTracker/Cocoa/TouchPointUIView.swift b/Sources/TouchTracker/Cocoa/TouchPointUIView.swift index 41d245a..12d390b 100644 --- a/Sources/TouchTracker/Cocoa/TouchPointUIView.swift +++ b/Sources/TouchTracker/Cocoa/TouchPointUIView.swift @@ -78,14 +78,14 @@ class TouchPointUIView: UIWindow { self.image = image self.isShowLocation = isShowLocation - let frame = CGRect(origin: location, + let frame = CGRect(origin: .zero, size: .init(width: radius * 2, height: radius * 2)) super.init(frame: frame) setupViews() setupViewConstraints() - windowLevel = .statusBar + windowLevel = .init(10000005) isUserInteractionEnabled = false } @@ -121,8 +121,6 @@ class TouchPointUIView: UIWindow { } func setupViewConstraints() { - translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ self.heightAnchor.constraint(equalToConstant: radius * 2), self.widthAnchor.constraint(equalToConstant: radius * 2), diff --git a/Sources/TouchTracker/Cocoa/TouchTrackingUIView.swift b/Sources/TouchTracker/Cocoa/TouchTrackingUIView.swift index e295518..d1a6d93 100644 --- a/Sources/TouchTracker/Cocoa/TouchTrackingUIView.swift +++ b/Sources/TouchTracker/Cocoa/TouchTrackingUIView.swift @@ -1,9 +1,9 @@ // // CocoaTrackPointManager.swift -// +// // // Created by p-x9 on 2023/04/14. -// +// // #if canImport(UIKit) @@ -43,6 +43,10 @@ public class TouchTrackingUIView: UIView { /// display mode of touched points. public var displayMode: DisplayMode + /// A boolean value that indicates whether the event should propagate across windows. + /// If set to `true`, the touch events received in one window will also be shared + /// with other windows when applicable. + public var shouldPropagateEventAcrossWindows: Bool = false var touches: Set = [] var locations: [CGPoint] = [] { @@ -55,7 +59,7 @@ public class TouchTrackingUIView: UIView { public var isEnabled: Bool = true var pointWindows = [TouchPointUIView]() - + /// initializer /// - Parameters: /// - radius: radius of mark on touched point @@ -134,25 +138,6 @@ public class TouchTrackingUIView: UIView { } } - public override func touchesBegan(_ touches: Set, with event: UIEvent?) { - self.touches.formUnion(touches) - updateLocations() - } - - public override func touchesMoved(_ touches: Set, with event: UIEvent?) { - updateLocations() - } - - public override func touchesEnded(_ touches: Set, with event: UIEvent?) { - self.touches.subtract(touches) - updateLocations() - } - - public override func touchesCancelled(_ touches: Set, with event: UIEvent?) { - self.touches.subtract(touches) - updateLocations() - } - func updateLocations() { if !isEnabled { self.touches = [] @@ -179,6 +164,7 @@ public class TouchTrackingUIView: UIView { pointWindows[touches.count.., with receiver: UIWindow) { + if !shouldPropagateEventAcrossWindows && window != receiver { + return + } + self.touches.formUnion(touches) + updateLocations() + } + + func touchesMoved(_ touches: Set, with receiver: UIWindow) { + if !shouldPropagateEventAcrossWindows && window != receiver { + return + } + updateLocations() + } + + func touchesEndedOrCancelled(_ touches: Set, with receiver: UIWindow) { + if !shouldPropagateEventAcrossWindows && window != receiver { + return + } + self.touches.subtract(touches) + updateLocations() + } +} + #endif diff --git a/Sources/TouchTracker/Extension/UIWindow+.swift b/Sources/TouchTracker/Extension/UIWindow+.swift index 771d197..4dcd4e2 100644 --- a/Sources/TouchTracker/Extension/UIWindow+.swift +++ b/Sources/TouchTracker/Extension/UIWindow+.swift @@ -45,7 +45,15 @@ extension UIWindow { let moved = touches.filter { $0.phase == .moved } let ended = touches.filter { $0.phase == .cancelled || $0.phase == .ended } - let touchLocationViews: [UIView] = find(for: TouchLocationCocoaView.self) + find(for: TouchTrackingUIView.self) + let touchLocationViews: [any TouchTrackable] = UIApplication.shared.connectedScenes + .lazy + .compactMap { $0 as? UIWindowScene } + .reduce([]) { partialResult, scene in + partialResult + scene.windows + } + .reduce([]) { partialResult, window in + partialResult + window.find(for: TouchLocationCocoaView.self) + window.find(for: TouchTrackingUIView.self) + } touchLocationViews .filter { @@ -56,13 +64,13 @@ extension UIWindow { } .forEach { view in if !began.isEmpty { - view.touchesBegan(began, with: event) + view.touchesBegan(began, with: self) } if !moved.isEmpty { - view.touchesMoved(moved, with: event) + view.touchesMoved(moved, with: self) } if !ended.isEmpty { - view.touchesEnded(ended, with: event) + view.touchesEndedOrCancelled(ended, with: self) } } } diff --git a/Sources/TouchTracker/Extension/UIWindowScene+.swift b/Sources/TouchTracker/Extension/UIWindowScene+.swift new file mode 100644 index 0000000..20e140a --- /dev/null +++ b/Sources/TouchTracker/Extension/UIWindowScene+.swift @@ -0,0 +1,40 @@ +// +// UIWindowScene+.swift +// +// +// Created by p-x9 on 2023/09/05. +// +// + +#if canImport(UIKit) +import UIKit + +extension UIWindowScene { + static func keyboardScene(for screen: UIScreen) -> UIWindowScene? { + // _keyboardWindowSceneForScreen:create: + let obfuString = [":etaer", "c:nee", "rcSroF", "e", "necSwod", "niWdraobyek_"] + let name = String(obfuString.joined(separator: "").reversed()) + + let selector = Selector(name) + guard UIWindowScene.responds(to: selector), + let scene = UIWindowScene.perform(selector, with: screen, with: false).takeUnretainedValue() as? UIWindowScene else { + return nil + } + + return scene + } + + var allWindows: [UIWindow] { + // _allWindows + let name = String(["_", "al", "lWin", "dows"].joined(separator: "")) + let selector = Selector(name) + guard self.responds(to: selector), + let windows = self.perform(selector).takeUnretainedValue() as? [UIWindow] else { + return [] + } + + return windows + } +} + +#endif diff --git a/Sources/TouchTracker/TouchLocationCocoaView.swift b/Sources/TouchTracker/TouchLocationCocoaView.swift index bba4230..f585e42 100644 --- a/Sources/TouchTracker/TouchLocationCocoaView.swift +++ b/Sources/TouchTracker/TouchLocationCocoaView.swift @@ -27,27 +27,24 @@ class TouchLocationCocoaView: UIView { fatalError("init(coder:) has not been implemented") } - override func touchesBegan(_ touches: Set, with event: UIEvent?) { - self.touches.formUnion(touches) - self.locations = self.touches.map { $0.location(in: self) } + override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { + false } +} - override func touchesMoved(_ touches: Set, with event: UIEvent?) { +extension TouchLocationCocoaView: TouchTrackable { + func touchesBegan(_ touches: Set, with receiver: UIWindow) { + self.touches.formUnion(touches) self.locations = self.touches.map { $0.location(in: self) } } - override func touchesCancelled(_ touches: Set, with event: UIEvent?) { - self.touches.subtract(touches) + func touchesMoved(_ touches: Set, with receiver: UIWindow) { self.locations = self.touches.map { $0.location(in: self) } } - override func touchesEnded(_ touches: Set, with event: UIEvent?) { + func touchesEndedOrCancelled(_ touches: Set, with receiver: UIWindow) { self.touches.subtract(touches) self.locations = self.touches.map { $0.location(in: self) } } - - override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { - false - } } #endif diff --git a/Sources/TouchTracker/TouchTrackable.swift b/Sources/TouchTracker/TouchTrackable.swift new file mode 100644 index 0000000..133df3c --- /dev/null +++ b/Sources/TouchTracker/TouchTrackable.swift @@ -0,0 +1,18 @@ +// +// TouchTrackable.swift +// +// +// Created by p-x9 on 2023/09/03. +// +// + +#if canImport(UIKit) +import UIKit + +protocol TouchTrackable: UIView { + func touchesBegan(_ touches: Set, with receiver: UIWindow) + func touchesMoved(_ touches: Set, with receiver: UIWindow) + func touchesEndedOrCancelled(_ touches: Set, with receiver: UIWindow) +} + +#endif