LKS_EventHandlerMaker.m 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. #ifdef SHOULD_COMPILE_LOOKIN_SERVER
  2. //
  3. // LKS_EventHandlerMaker.m
  4. // LookinServer
  5. //
  6. // Created by Li Kai on 2019/8/7.
  7. // https://lookin.work
  8. //
  9. #import "LKS_EventHandlerMaker.h"
  10. #import "LookinTuple.h"
  11. #import "LookinEventHandler.h"
  12. #import "LookinObject.h"
  13. #import "LookinWeakContainer.h"
  14. #import "LookinIvarTrace.h"
  15. #import "LookinServerDefines.h"
  16. #import "LKS_GestureTargetActionsSearcher.h"
  17. #import "LKS_MultiplatformAdapter.h"
  18. @implementation LKS_EventHandlerMaker
  19. + (NSArray<LookinEventHandler *> *)makeForView:(UIView *)view {
  20. if (!view) {
  21. return nil;
  22. }
  23. NSMutableArray<LookinEventHandler *> *allHandlers = nil;
  24. if ([view isKindOfClass:[UIControl class]]) {
  25. NSArray<LookinEventHandler *> *targetActionHandlers = [self _targetActionHandlersForControl:(UIControl *)view];
  26. if (targetActionHandlers.count) {
  27. if (!allHandlers) {
  28. allHandlers = [NSMutableArray array];
  29. }
  30. [allHandlers addObjectsFromArray:targetActionHandlers];
  31. }
  32. }
  33. NSArray<LookinEventHandler *> *gestureHandlers = [self _gestureHandlersForView:view];
  34. if (gestureHandlers.count) {
  35. if (!allHandlers) {
  36. allHandlers = [NSMutableArray array];
  37. }
  38. [allHandlers addObjectsFromArray:gestureHandlers];
  39. }
  40. return allHandlers.copy;
  41. }
  42. + (NSArray<LookinEventHandler *> *)_gestureHandlersForView:(UIView *)view {
  43. if (view.gestureRecognizers.count == 0) {
  44. return nil;
  45. }
  46. NSArray<LookinEventHandler *> *handlers = [view.gestureRecognizers lookin_map:^id(NSUInteger idx, __kindof UIGestureRecognizer *recognizer) {
  47. LookinEventHandler *handler = [LookinEventHandler new];
  48. handler.handlerType = LookinEventHandlerTypeGesture;
  49. handler.eventName = NSStringFromClass([recognizer class]);
  50. NSArray<LookinTwoTuple *> *targetActionInfos = [LKS_GestureTargetActionsSearcher getTargetActionsFromRecognizer:recognizer];
  51. handler.targetActions = [targetActionInfos lookin_map:^id(NSUInteger idx, LookinTwoTuple *rawTuple) {
  52. NSObject *target = ((LookinWeakContainer *)rawTuple.first).object;
  53. if (!target) {
  54. // 该 target 已被释放
  55. return nil;
  56. }
  57. LookinStringTwoTuple *newTuple = [LookinStringTwoTuple new];
  58. newTuple.first = [LKS_Helper descriptionOfObject:target];
  59. newTuple.second = (NSString *)rawTuple.second;
  60. return newTuple;
  61. }];
  62. handler.inheritedRecognizerName = [self _inheritedRecognizerNameForRecognizer:recognizer];
  63. handler.gestureRecognizerIsEnabled = recognizer.enabled;
  64. if (recognizer.delegate) {
  65. handler.gestureRecognizerDelegator = [LKS_Helper descriptionOfObject:recognizer.delegate];
  66. }
  67. handler.recognizerIvarTraces = [recognizer.lks_ivarTraces lookin_map:^id(NSUInteger idx, LookinIvarTrace *trace) {
  68. return [NSString stringWithFormat:@"(%@ *) -> %@", trace.hostClassName, trace.ivarName];
  69. }];
  70. handler.recognizerOid = [recognizer lks_registerOid];
  71. return handler;
  72. }];
  73. return handlers;
  74. }
  75. + (NSString *)_inheritedRecognizerNameForRecognizer:(UIGestureRecognizer *)recognizer {
  76. if (!recognizer) {
  77. NSAssert(NO, @"");
  78. return nil;
  79. }
  80. static NSArray<Class> *baseRecognizers;
  81. static dispatch_once_t onceToken;
  82. dispatch_once(&onceToken, ^{
  83. // 注意这里 UIScreenEdgePanGestureRecognizer 在 UIPanGestureRecognizer 前面,因为 UIScreenEdgePanGestureRecognizer 继承于 UIPanGestureRecognizer
  84. #if TARGET_OS_TV
  85. baseRecognizers = @[[UILongPressGestureRecognizer class],
  86. [UIPanGestureRecognizer class],
  87. [UISwipeGestureRecognizer class],
  88. [UITapGestureRecognizer class]];
  89. #elif TARGET_OS_VISION
  90. baseRecognizers = @[[UILongPressGestureRecognizer class],
  91. [UIPanGestureRecognizer class],
  92. [UISwipeGestureRecognizer class],
  93. [UIRotationGestureRecognizer class],
  94. [UIPinchGestureRecognizer class],
  95. [UITapGestureRecognizer class]];
  96. #else
  97. baseRecognizers = @[[UILongPressGestureRecognizer class],
  98. [UIScreenEdgePanGestureRecognizer class],
  99. [UIPanGestureRecognizer class],
  100. [UISwipeGestureRecognizer class],
  101. [UIRotationGestureRecognizer class],
  102. [UIPinchGestureRecognizer class],
  103. [UITapGestureRecognizer class]];
  104. #endif
  105. });
  106. __block NSString *result = @"UIGestureRecognizer";
  107. [baseRecognizers enumerateObjectsUsingBlock:^(Class _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  108. if ([recognizer isMemberOfClass:obj]) {
  109. // 自身就是基本款,则直接置为 nil
  110. result = nil;
  111. *stop = YES;
  112. return;
  113. }
  114. if ([recognizer isKindOfClass:obj]) {
  115. result = NSStringFromClass(obj);
  116. *stop = YES;
  117. return;
  118. }
  119. }];
  120. return result;
  121. }
  122. + (NSArray<LookinEventHandler *> *)_targetActionHandlersForControl:(UIControl *)control {
  123. static dispatch_once_t onceToken;
  124. static NSArray<NSNumber *> *allEvents = nil;
  125. dispatch_once(&onceToken,^{
  126. allEvents = @[@(UIControlEventTouchDown), @(UIControlEventTouchDownRepeat), @(UIControlEventTouchDragInside), @(UIControlEventTouchDragOutside), @(UIControlEventTouchDragEnter), @(UIControlEventTouchDragExit), @(UIControlEventTouchUpInside), @(UIControlEventTouchUpOutside), @(UIControlEventTouchCancel), @(UIControlEventValueChanged), @(UIControlEventEditingDidBegin), @(UIControlEventEditingChanged), @(UIControlEventEditingDidEnd), @(UIControlEventEditingDidEndOnExit)];
  127. if (@available(iOS 9.0, *)) {
  128. allEvents = [allEvents arrayByAddingObject:@(UIControlEventPrimaryActionTriggered)];
  129. }
  130. });
  131. NSSet *allTargets = control.allTargets;
  132. if (!allTargets.count) {
  133. return nil;
  134. }
  135. NSMutableArray<LookinEventHandler *> *handlers = [NSMutableArray array];
  136. [allEvents enumerateObjectsUsingBlock:^(NSNumber * _Nonnull eventNum, NSUInteger idx, BOOL * _Nonnull stop) {
  137. UIControlEvents event = [eventNum unsignedIntegerValue];
  138. NSMutableArray<LookinStringTwoTuple *> *targetActions = [NSMutableArray array];
  139. [allTargets enumerateObjectsUsingBlock:^(id _Nonnull target, BOOL * _Nonnull stop) {
  140. NSArray<NSString *> *actions = [control actionsForTarget:target forControlEvent:event];
  141. [actions enumerateObjectsUsingBlock:^(NSString * _Nonnull action, NSUInteger idx, BOOL * _Nonnull stop) {
  142. LookinStringTwoTuple *tuple = [LookinStringTwoTuple new];
  143. tuple.first = [LKS_Helper descriptionOfObject:target];
  144. tuple.second = action;
  145. [targetActions addObject:tuple];
  146. }];
  147. }];
  148. if (targetActions.count) {
  149. LookinEventHandler *handler = [LookinEventHandler new];
  150. handler.handlerType = LookinEventHandlerTypeTargetAction;
  151. handler.eventName = [self _nameFromControlEvent:event];
  152. handler.targetActions = targetActions.copy;
  153. [handlers addObject:handler];
  154. }
  155. }];
  156. return handlers;
  157. }
  158. + (NSString *)_nameFromControlEvent:(UIControlEvents)event {
  159. static dispatch_once_t onceToken;
  160. static NSDictionary<NSNumber *, NSString *> *eventsAndNames = nil;
  161. dispatch_once(&onceToken,^{
  162. NSMutableDictionary<NSNumber *, NSString *> *eventsAndNames_m = @{
  163. @(UIControlEventTouchDown): @"UIControlEventTouchDown",
  164. @(UIControlEventTouchDownRepeat): @"UIControlEventTouchDownRepeat",
  165. @(UIControlEventTouchDragInside): @"UIControlEventTouchDragInside",
  166. @(UIControlEventTouchDragOutside): @"UIControlEventTouchDragOutside",
  167. @(UIControlEventTouchDragEnter): @"UIControlEventTouchDragEnter",
  168. @(UIControlEventTouchDragExit): @"UIControlEventTouchDragExit",
  169. @(UIControlEventTouchUpInside): @"UIControlEventTouchUpInside",
  170. @(UIControlEventTouchUpOutside): @"UIControlEventTouchUpOutside",
  171. @(UIControlEventTouchCancel): @"UIControlEventTouchCancel",
  172. @(UIControlEventValueChanged): @"UIControlEventValueChanged",
  173. @(UIControlEventEditingDidBegin): @"UIControlEventEditingDidBegin",
  174. @(UIControlEventEditingChanged): @"UIControlEventEditingChanged",
  175. @(UIControlEventEditingDidEnd): @"UIControlEventEditingDidEnd",
  176. @(UIControlEventEditingDidEndOnExit): @"UIControlEventEditingDidEndOnExit",
  177. }.mutableCopy;
  178. if (@available(iOS 9.0, *)) {
  179. eventsAndNames_m[@(UIControlEventPrimaryActionTriggered)] = @"UIControlEventPrimaryActionTriggered";
  180. }
  181. eventsAndNames = eventsAndNames_m.copy;
  182. });
  183. NSString *name = eventsAndNames[@(event)];
  184. return name;
  185. }
  186. @end
  187. #endif /* SHOULD_COMPILE_LOOKIN_SERVER */