1 // Copyright 2015-present 650 Industries. All rights reserved. 2 3 import Foundation 4 import UIKit 5 6 class DevMenuTouchInterceptor { 7 static fileprivate let recognizer: DevMenuGestureRecognizer = DevMenuGestureRecognizer() 8 9 /** 10 Returns bool value whether the dev menu touch gestures are being intercepted. 11 */ 12 static var isInstalled: Bool = false { 13 willSet { 14 if isInstalled != newValue { 15 // Capture touch gesture from any window by swizzling default implementation from UIWindow. 16 swizzle() 17 18 // Make sure recognizer is enabled/disabled accordingly. 19 recognizer.isEnabled = newValue 20 } 21 } 22 } 23 swizzlenull24 static private func swizzle() { 25 DevMenuUtils.swizzle( 26 selector: #selector(getter: UIWindow.gestureRecognizers), 27 withSelector: #selector(getter: UIWindow.EXDevMenu_gestureRecognizers), 28 forClass: UIWindow.self 29 ) 30 } 31 } 32 33 extension UIWindow { 34 @objc open var EXDevMenu_gestureRecognizers: [UIGestureRecognizer]? { 35 // Just for thread safety, someone may uninstall the interceptor in the meantime and we would fall into recursive loop. 36 if !DevMenuTouchInterceptor.isInstalled { 37 return self.gestureRecognizers 38 } 39 40 // Check for the case where singleton instance of gesture recognizer is not created yet or is attached to different window. 41 let recognizer = DevMenuTouchInterceptor.recognizer 42 if recognizer.view != self { 43 // Remove it from the window it's attached to. 44 recognizer.view?.removeGestureRecognizer(recognizer) 45 46 // Attach to this window. 47 self.addGestureRecognizer(recognizer) 48 } 49 50 // `EXDevMenu_gestureRecognizers` implementation has been swizzled with `gestureRecognizers` - it might be confusing that we call it recursively, but we don't. 51 return self.EXDevMenu_gestureRecognizers 52 } 53 } 54