#import @implementation ChatInputTextViewImplTargetForAction - (instancetype)initWithTarget:(id _Nullable)target { self = [super init]; if (self != nil) { _target = target; } return self; } @end @interface ChatInputTextViewImpl () { UIGestureRecognizer *_tapRecognizer; } @end @implementation ChatInputTextViewImpl - (instancetype _Nonnull)initWithFrame:(CGRect)frame textContainer:(NSTextContainer * _Nullable)textContainer disableTiling:(bool)disableTiling { self = [super initWithFrame:frame textContainer:textContainer]; if (self != nil) { if (disableTiling) { SEL selector = NSSelectorFromString(@"_disableTiledViews"); if (selector && [self respondsToSelector:selector]) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" [self performSelector:selector]; #pragma clang diagnostic pop } } if (@available(iOS 17.0, *)) { } else { _tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(workaroundTapGesture:)]; _tapRecognizer.cancelsTouchesInView = false; _tapRecognizer.delaysTouchesBegan = false; _tapRecognizer.delaysTouchesEnded = false; _tapRecognizer.delegate = self; [self addGestureRecognizer:_tapRecognizer]; } } return self; } - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { return true; } - (void)workaroundTapGesture:(UITapGestureRecognizer *)recognizer { if (recognizer.state == UIGestureRecognizerStateEnded) { static Class promptClass = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ promptClass = NSClassFromString([[NSString alloc] initWithFormat:@"%@AutocorrectInlinePrompt", @"UI"]); }); UIView *result = [self hitTest:[recognizer locationInView:self] withEvent:nil]; if (result != nil && [result class] == promptClass) { if (_dropAutocorrectioniOS16) { _dropAutocorrectioniOS16(); } } } } - (BOOL)canPerformAction:(SEL)action withSender:(id)sender { if (_targetForAction) { ChatInputTextViewImplTargetForAction *result = _targetForAction(action); if (result) { return result.target != nil; } } if (_shouldRespondToAction) { if (!_shouldRespondToAction(action)) { return false; } } if (action == @selector(paste:)) { NSArray *items = [UIMenuController sharedMenuController].menuItems; if (((UIMenuItem *)items.firstObject).action == @selector(toggleBoldface:)) { return false; } return true; } #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wundeclared-selector" static SEL promptForReplaceSelector; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ promptForReplaceSelector = NSSelectorFromString(@"_promptForReplace:"); }); if (action == promptForReplaceSelector) { return false; } #pragma clang diagnostic pop if (action == @selector(toggleUnderline:)) { return false; } return [super canPerformAction:action withSender:sender]; } - (id)targetForAction:(SEL)action withSender:(id)__unused sender { if (_targetForAction) { ChatInputTextViewImplTargetForAction *result = _targetForAction(action); if (result) { return result.target; } } return [super targetForAction:action withSender:sender]; } - (void)copy:(id)sender { if (_shouldCopy == nil || _shouldCopy()) { [super copy:sender]; } } - (void)paste:(id)sender { if (_shouldPaste == nil || _shouldPaste()) { [super paste:sender]; } } - (NSArray *)keyCommands { UIKeyCommand *plainReturn = [UIKeyCommand keyCommandWithInput:@"\r" modifierFlags:kNilOptions action:@selector(handlePlainReturn:)]; return @[ plainReturn ]; } - (void)handlePlainReturn:(id)__unused sender { if (_shouldReturn) { _shouldReturn(); } } - (void)deleteBackward { bool notify = self.text.length == 0; [super deleteBackward]; if (notify) { if (_backspaceWhileEmpty) { _backspaceWhileEmpty(); } } } @end