Skip to content

Commit 50497af

Browse files
authored
[Fabric] Implement SpellCheck and AutoCorrect for TextInput (#14509)
1 parent d449c00 commit 50497af

File tree

8 files changed

+83
-3
lines changed

8 files changed

+83
-3
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "prerelease",
3+
"comment": "Implement SpellCheck and AutoCorrect for TextInput",
4+
"packageName": "react-native-windows",
5+
"email": "54227869+anupriya13@users.noreply.github.com",
6+
"dependentChangeType": "patch"
7+
}

packages/@react-native-windows/tester/src/js/examples-win/LegacyTests/TextInputTestPage.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ export class TextInputTestPage extends React.Component<
6262
style={{height: 80}}
6363
placeholder="MultiLine"
6464
multiline={true}
65+
spellCheck={false}
66+
autoCorrect={false}
6567
/>
6668
<TextInput
6769
testID="auto-caps-textinput-field"

packages/e2e-test-app-fabric/test/__snapshots__/snapshotPages.test.js.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29370,8 +29370,10 @@ exports[`snapshotAllPages LegacyTextInputTest 1`] = `
2937029370
testID="textinput-field"
2937129371
/>
2937229372
<TextInput
29373+
autoCorrect={false}
2937329374
multiline={true}
2937429375
placeholder="MultiLine"
29376+
spellCheck={false}
2937529377
style={
2937629378
{
2937729379
"height": 80,

packages/playground/Samples/textinput.tsx

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,33 @@ export default class Bootstrap extends React.Component<{}, any> {
8282
/>
8383
<TextInput
8484
style={styles.input}
85-
placeholder={'SpellChecking Disabled'}
85+
placeholder={'SpellChecking Enabled Autocorrect Disabled'}
86+
spellCheck={true}
87+
autoCorrect={false}
88+
/>
89+
<TextInput
90+
style={styles.input}
91+
placeholder={'SpellChecking Enabled Autocorrect Enabled'}
92+
spellCheck={true}
93+
autoCorrect={true}
94+
/>
95+
<TextInput
96+
style={styles.input}
97+
placeholder={'SpellChecking Disabled Autocorrect Disabled'}
98+
spellCheck={false}
99+
autoCorrect={false}
100+
/>
101+
<TextInput
102+
style={styles.input}
103+
placeholder={'SpellChecking Disabled Autocorrect Enabled'}
86104
spellCheck={false}
105+
autoCorrect={true}
106+
/>
107+
<TextInput
108+
style={styles.input}
109+
placeholder={
110+
'SpellChecking default (true) Autocorrect default (true)'
111+
}
87112
/>
88113
<TextInput
89114
style={styles.input}

vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,13 @@ struct CompTextHost : public winrt::implements<CompTextHost, ITextHost> {
463463
WindowsTextInputComponentView *m_outer;
464464
};
465465

466+
int WINAPI
467+
AutoCorrectOffCallback(LANGID langid, const WCHAR *pszBefore, WCHAR *pszAfter, LONG cchAfter, LONG *pcchReplaced) {
468+
wcsncpy_s(pszAfter, cchAfter, pszBefore, _TRUNCATE);
469+
*pcchReplaced = static_cast<LONG>(wcslen(pszAfter));
470+
return ATP_CHANGE;
471+
}
472+
466473
facebook::react::AttributedString WindowsTextInputComponentView::getAttributedString() const {
467474
// Use BaseTextShadowNode to get attributed string from children
468475

@@ -1067,6 +1074,20 @@ void WindowsTextInputComponentView::updateProps(
10671074
m_propBits |= TXTBIT_PARAFORMATCHANGE;
10681075
}
10691076

1077+
// Please note: spellcheck performs both red lines and autocorrect as per windows behaviour
1078+
bool shouldUpdateSpellCheck =
1079+
(!oldProps || (oldTextInputProps.spellCheck != newTextInputProps.spellCheck) ||
1080+
(oldTextInputProps.autoCorrect != newTextInputProps.autoCorrect));
1081+
1082+
if (shouldUpdateSpellCheck) {
1083+
bool effectiveSpellCheck = newTextInputProps.spellCheck || newTextInputProps.autoCorrect;
1084+
updateSpellCheck(effectiveSpellCheck);
1085+
}
1086+
1087+
if (!oldProps || oldTextInputProps.autoCorrect != newTextInputProps.autoCorrect) {
1088+
updateAutoCorrect(newTextInputProps.autoCorrect);
1089+
}
1090+
10701091
UpdatePropertyBits();
10711092
}
10721093

@@ -1591,4 +1612,23 @@ void WindowsTextInputComponentView::updateLetterSpacing(float letterSpacing) noe
15911612
m_textServices->TxSendMessage(EM_SETCHARFORMAT, SCF_SELECTION, reinterpret_cast<LPARAM>(&cf), &res));
15921613
}
15931614

1615+
void WindowsTextInputComponentView::updateAutoCorrect(bool enable) noexcept {
1616+
LRESULT lresult;
1617+
winrt::check_hresult(m_textServices->TxSendMessage(
1618+
EM_SETAUTOCORRECTPROC, enable ? 0 : reinterpret_cast<WPARAM>(AutoCorrectOffCallback), 0, &lresult));
1619+
}
1620+
1621+
void WindowsTextInputComponentView::updateSpellCheck(bool enable) noexcept {
1622+
LRESULT currentLangOptions;
1623+
winrt::check_hresult(m_textServices->TxSendMessage(EM_GETLANGOPTIONS, 0, 0, &currentLangOptions));
1624+
1625+
DWORD newLangOptions = static_cast<DWORD>(currentLangOptions);
1626+
if (enable) {
1627+
newLangOptions |= IMF_SPELLCHECKING;
1628+
}
1629+
1630+
LRESULT lresult;
1631+
winrt::check_hresult(
1632+
m_textServices->TxSendMessage(EM_SETLANGOPTIONS, IMF_SPELLCHECKING, enable ? newLangOptions : 0, &lresult));
1633+
}
15941634
} // namespace winrt::Microsoft::ReactNative::Composition::implementation

vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ struct WindowsTextInputComponentView
111111
const std::string &newcapitalizationType) noexcept;
112112

113113
void updateLetterSpacing(float letterSpacing) noexcept;
114+
void updateAutoCorrect(bool value) noexcept;
115+
void updateSpellCheck(bool value) noexcept;
114116

115117
winrt::Windows::UI::Composition::CompositionSurfaceBrush m_brush{nullptr};
116118
winrt::Microsoft::ReactNative::Composition::Experimental::ICaretVisual m_caretVisual{nullptr};

vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputProps.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ WindowsTextInputProps::WindowsTextInputProps(
2424
*/
2525

2626
allowFontScaling(convertRawProp(context, rawProps, "allowFontScaling", sourceProps.allowFontScaling, {true})),
27+
autoCorrect(convertRawProp(context, rawProps, "autoCorrect", sourceProps.autoCorrect, {true})),
2728
clearTextOnFocus(convertRawProp(context, rawProps, "clearTextOnFocus", sourceProps.clearTextOnFocus, {false})),
2829
editable(convertRawProp(context, rawProps, "editable", sourceProps.editable, {true})),
2930
maxLength(convertRawProp(context, rawProps, "maxLength", sourceProps.maxLength, {0})),
@@ -36,7 +37,7 @@ WindowsTextInputProps::WindowsTextInputProps(
3637
selection(convertRawProp(context, rawProps, "selection", sourceProps.selection, {})),
3738
selectionColor(convertRawProp(context, rawProps, "selectionColor", sourceProps.selectionColor, {})),
3839
selectTextOnFocus(convertRawProp(context, rawProps, "selectTextOnFocus", sourceProps.selectTextOnFocus, {false})),
39-
spellCheck(convertRawProp(context, rawProps, "spellCheck", sourceProps.spellCheck, {false})),
40+
spellCheck(convertRawProp(context, rawProps, "spellCheck", sourceProps.spellCheck, {true})),
4041
text(convertRawProp(context, rawProps, "text", sourceProps.text, {})),
4142
mostRecentEventCount(
4243
convertRawProp(context, rawProps, "mostRecentEventCount", sourceProps.mostRecentEventCount, {0})),

vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputProps.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ class WindowsTextInputProps final : public ViewProps, public BaseTextProps {
9797
setProp(const PropsParserContext &context, RawPropsPropNameHash hash, const char *propName, RawValue const &value);
9898

9999
bool allowFontScaling{true};
100+
bool autoCorrect{true};
100101
bool clearTextOnFocus{false};
101102
bool editable{true};
102103
int maxLength{0};
@@ -108,7 +109,7 @@ class WindowsTextInputProps final : public ViewProps, public BaseTextProps {
108109
CompWindowsTextInputSelectionStruct selection{};
109110
SharedColor selectionColor{};
110111
bool selectTextOnFocus{false};
111-
bool spellCheck{false};
112+
bool spellCheck{true};
112113
std::string text{};
113114
int mostRecentEventCount{0};
114115
bool secureTextEntry{false};

0 commit comments

Comments
 (0)