Fix a broken input for the Korean alphabet in TextInput (#32523)

Summary:
<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->

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

<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
https://github.com/facebook/react-native/wiki/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
This commit is contained in:
Minsik Kim 2022-02-09 22:05:22 -08:00 коммит произвёл Facebook GitHub Bot
Родитель f7e7e89335
Коммит 1a83dc36ce
3 изменённых файлов: 7 добавлений и 31 удалений

Просмотреть файл

@ -147,21 +147,7 @@ static UIColor *defaultPlaceholderColor()
- (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 @@ static UIColor *defaultPlaceholderColor()
#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<NSAttributedStringKey,id> * _Nonnull attrs, NSRange range, BOOL * _Nonnull stop) {
[textStorage setAttributes:attrs range:range];
}];
[self.textStorage endEditing];
}
@end

Просмотреть файл

@ -104,6 +104,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame)
// 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 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame)
BOOL shouldFallbackToBareTextComparison =
[self.backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"dictation"] ||
[self.backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"ko-KR"] ||
self.backedTextInputView.markedTextRange ||
self.backedTextInputView.isSecureTextEntry ||
fontHasBeenUpdatedBySystem;

Просмотреть файл

@ -617,8 +617,9 @@ using namespace facebook::react;
// 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 @@ using namespace facebook::react;
BOOL shouldFallbackToBareTextComparison =
[_backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"dictation"] ||
[_backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"ko-KR"] ||
_backedTextInputView.markedTextRange || _backedTextInputView.isSecureTextEntry || fontHasBeenUpdatedBySystem;
if (shouldFallbackToBareTextComparison) {