Skip to content

Commit

Permalink
Fix a broken input for the Korean alphabet in TextInput (#32523)
Browse files Browse the repository at this point in the history
Summary:
<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->

Fix #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: #19809, #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: #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
  • Loading branch information
kmsbernard authored and Andrei Shikov committed Feb 24, 2022
1 parent 43d67cd commit 48f9733
Show file tree
Hide file tree
Showing 3 changed files with 7 additions and 31 deletions.
30 changes: 1 addition & 29 deletions Libraries/Text/TextInput/Multiline/RCTUITextView.m
Original file line number Diff line number Diff line change
Expand Up @@ -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];
}

Expand Down Expand Up @@ -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<NSAttributedStringKey,id> * _Nonnull attrs, NSRange range, BOOL * _Nonnull stop) {
[textStorage setAttributes:attrs range:range];
}];

[self.textStorage endEditing];
}

@end
2 changes: 2 additions & 0 deletions Libraries/Text/TextInput/RCTBaseTextInputView.m
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) {
Expand Down

0 comments on commit 48f9733

Please sign in to comment.