From 1a83dc36ce0af33ac7a3c311354fce4bfa5ba1a3 Mon Sep 17 00:00:00 2001 From: Minsik Kim Date: Wed, 9 Feb 2022 22:05:22 -0800 Subject: [PATCH] Fix a broken input for the Korean alphabet in TextInput (#32523) Summary: Fix https://github.com/facebook/react-native/issues/32503 Updating the attributed text in TextView/TextField while inputting Korean language will break input mechanism of the Korean alphabet. This results unexpected text input. This PR supersedes the previous fixes: https://github.com/facebook/react-native/issues/19809, https://github.com/facebook/react-native/issues/22546 ## Changelog [iOS] [Fixed] - Fix a broken input for the Korean alphabet in TextInput Pull Request resolved: https://github.com/facebook/react-native/pull/32523 Test Plan: https://user-images.githubusercontent.com/20317121/140013434-1674c391-54d6-4410-b4c1-c633697e639d.mov Reviewed By: lunaleaps, sammy-SC Differential Revision: D32470543 Pulled By: philIip fbshipit-source-id: e7e34bd362fa2ab2ca579103db01ad8d1a891c35 --- .../Text/TextInput/Multiline/RCTUITextView.m | 30 +------------------ .../Text/TextInput/RCTBaseTextInputView.m | 2 ++ .../TextInput/RCTTextInputComponentView.mm | 6 ++-- 3 files changed, 7 insertions(+), 31 deletions(-) diff --git a/Libraries/Text/TextInput/Multiline/RCTUITextView.m b/Libraries/Text/TextInput/Multiline/RCTUITextView.m index f4025965a7521f..92371bc8bf618e 100644 --- a/Libraries/Text/TextInput/Multiline/RCTUITextView.m +++ b/Libraries/Text/TextInput/Multiline/RCTUITextView.m @@ -147,21 +147,7 @@ - (void)setTextAlignment:(NSTextAlignment)textAlignment - (void)setAttributedText:(NSAttributedString *)attributedText { - // Using `setAttributedString:` while user is typing breaks some internal mechanics - // when entering complex input languages such as Chinese, Korean or Japanese. - // see: https://github.com/facebook/react-native/issues/19339 - - // We try to avoid calling this method as much as we can. - // If the text has changed, there is nothing we can do. - if (![super.attributedText.string isEqualToString:attributedText.string]) { - [super setAttributedText:attributedText]; - } else { - // But if the text is preserved, we just copying the attributes from the source string. - if (![super.attributedText isEqualToAttributedString:attributedText]) { - [self copyTextAttributesFrom:attributedText]; - } - } - + [super setAttributedText:attributedText]; [self textDidChange]; } @@ -311,18 +297,4 @@ - (CGRect)caretRectForPosition:(UITextPosition *)position #pragma mark - Utility Methods -- (void)copyTextAttributesFrom:(NSAttributedString *)sourceString -{ - [self.textStorage beginEditing]; - - NSTextStorage *textStorage = self.textStorage; - [sourceString enumerateAttributesInRange:NSMakeRange(0, sourceString.length) - options:NSAttributedStringEnumerationReverse - usingBlock:^(NSDictionary * _Nonnull attrs, NSRange range, BOOL * _Nonnull stop) { - [textStorage setAttributes:attrs range:range]; - }]; - - [self.textStorage endEditing]; -} - @end diff --git a/Libraries/Text/TextInput/RCTBaseTextInputView.m b/Libraries/Text/TextInput/RCTBaseTextInputView.m index c553fbd19b1a97..a4924923f190cb 100644 --- a/Libraries/Text/TextInput/RCTBaseTextInputView.m +++ b/Libraries/Text/TextInput/RCTBaseTextInputView.m @@ -104,6 +104,7 @@ - (BOOL)textOf:(NSAttributedString*)newText equals:(NSAttributedString*)oldText{ // Similarly, when the user is in the middle of inputting some text in Japanese/Chinese, there will be styling on the // text that we should disregard. See https://developer.apple.com/documentation/uikit/uitextinput/1614489-markedtextrange?language=objc // for more info. + // Also, updating the attributed text while inputting Korean language will break input mechanism. // If the user added an emoji, the system adds a font attribute for the emoji and stores the original font in NSOriginalFont. // Lastly, when entering a password, etc., there will be additional styling on the field as the native text view // handles showing the last character for a split second. @@ -116,6 +117,7 @@ - (BOOL)textOf:(NSAttributedString*)newText equals:(NSAttributedString*)oldText{ BOOL shouldFallbackToBareTextComparison = [self.backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"dictation"] || + [self.backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"ko-KR"] || self.backedTextInputView.markedTextRange || self.backedTextInputView.isSecureTextEntry || fontHasBeenUpdatedBySystem; diff --git a/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm index faa94328225442..1c3b916163cae1 100644 --- a/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm @@ -617,8 +617,9 @@ - (BOOL)_textOf:(NSAttributedString *)newText equals:(NSAttributedString *)oldTe // the settings on a dictation. // Similarly, when the user is in the middle of inputting some text in Japanese/Chinese, there will be styling on the // text that we should disregard. See - // https://developer.apple.com/documentation/uikit/uitextinput/1614489-markedtextrange?language=objc for more info. If - // the user added an emoji, the system adds a font attribute for the emoji and stores the original font in + // https://developer.apple.com/documentation/uikit/uitextinput/1614489-markedtextrange?language=objc for more info. + // Also, updating the attributed text while inputting Korean language will break input mechanism. + // If the user added an emoji, the system adds a font attribute for the emoji and stores the original font in // NSOriginalFont. Lastly, when entering a password, etc., there will be additional styling on the field as the native // text view handles showing the last character for a split second. __block BOOL fontHasBeenUpdatedBySystem = false; @@ -633,6 +634,7 @@ - (BOOL)_textOf:(NSAttributedString *)newText equals:(NSAttributedString *)oldTe BOOL shouldFallbackToBareTextComparison = [_backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"dictation"] || + [_backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"ko-KR"] || _backedTextInputView.markedTextRange || _backedTextInputView.isSecureTextEntry || fontHasBeenUpdatedBySystem; if (shouldFallbackToBareTextComparison) {