Skip to content

Commit 21e0c91

Browse files
Fix TextInput onChange double firing using RichEdit modify flag approach
Co-authored-by: HariniMalothu17 <[email protected]>
1 parent 2938058 commit 21e0c91

File tree

2 files changed

+68
-61
lines changed

2 files changed

+68
-61
lines changed

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

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,13 +1283,20 @@ void WindowsTextInputComponentView::OnTextUpdated() noexcept {
12831283

12841284
m_state->updateState(std::move(data));
12851285

1286-
if (m_eventEmitter && !m_comingFromJS && !m_comingFromState) {
1286+
if (m_eventEmitter && !m_comingFromJS) {
12871287
// call onChange event
12881288
auto emitter = std::static_pointer_cast<const facebook::react::WindowsTextInputEventEmitter>(m_eventEmitter);
1289-
facebook::react::WindowsTextInputEventEmitter::OnChange onChangeArgs;
1290-
onChangeArgs.text = GetTextFromRichEdit();
1291-
onChangeArgs.eventCount = ++m_nativeEventCount;
1292-
emitter->onChange(onChangeArgs);
1289+
// Check if RichEdit says the control was modified
1290+
LRESULT modified = 0;
1291+
m_textServices->TxSendMessage(EM_GETMODIFY, 0, 0, &modified);
1292+
if (modified) {
1293+
// Clear the modify flag
1294+
m_textServices->TxSendMessage(EM_SETMODIFY, FALSE, 0, nullptr);
1295+
facebook::react::WindowsTextInputEventEmitter::OnChange onChangeArgs;
1296+
onChangeArgs.text = GetTextFromRichEdit();
1297+
onChangeArgs.eventCount = ++m_nativeEventCount;
1298+
emitter->onChange(onChangeArgs);
1299+
}
12931300
if (windowsTextInputProps().multiline) {
12941301
auto [contentWidth, contentHeight] = GetContentSize();
12951302
facebook::react::WindowsTextInputEventEmitter::OnContentSizeChange onContentSizeChangeArgs;

vnext/codegen/rnwcoreJSI-generated.cpp

Lines changed: 56 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -946,41 +946,6 @@ NativeAnimatedTurboModuleCxxSpecJSI::NativeAnimatedTurboModuleCxxSpecJSI(std::sh
946946
methodMap_["removeListeners"] = MethodMetadata {1, __hostFunction_NativeAnimatedTurboModuleCxxSpecJSI_removeListeners};
947947
methodMap_["queueAndExecuteBatchedOperations"] = MethodMetadata {1, __hostFunction_NativeAnimatedTurboModuleCxxSpecJSI_queueAndExecuteBatchedOperations};
948948
}
949-
static jsi::Value __hostFunction_NativeAppearanceCxxSpecJSI_getColorScheme(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
950-
auto result = static_cast<NativeAppearanceCxxSpecJSI *>(&turboModule)->getColorScheme(
951-
rt
952-
);
953-
return result ? jsi::Value(std::move(*result)) : jsi::Value::null();
954-
}
955-
static jsi::Value __hostFunction_NativeAppearanceCxxSpecJSI_setColorScheme(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
956-
static_cast<NativeAppearanceCxxSpecJSI *>(&turboModule)->setColorScheme(
957-
rt,
958-
count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt)
959-
);
960-
return jsi::Value::undefined();
961-
}
962-
static jsi::Value __hostFunction_NativeAppearanceCxxSpecJSI_addListener(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
963-
static_cast<NativeAppearanceCxxSpecJSI *>(&turboModule)->addListener(
964-
rt,
965-
count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt)
966-
);
967-
return jsi::Value::undefined();
968-
}
969-
static jsi::Value __hostFunction_NativeAppearanceCxxSpecJSI_removeListeners(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
970-
static_cast<NativeAppearanceCxxSpecJSI *>(&turboModule)->removeListeners(
971-
rt,
972-
count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asNumber()
973-
);
974-
return jsi::Value::undefined();
975-
}
976-
977-
NativeAppearanceCxxSpecJSI::NativeAppearanceCxxSpecJSI(std::shared_ptr<CallInvoker> jsInvoker)
978-
: TurboModule("Appearance", jsInvoker) {
979-
methodMap_["getColorScheme"] = MethodMetadata {0, __hostFunction_NativeAppearanceCxxSpecJSI_getColorScheme};
980-
methodMap_["setColorScheme"] = MethodMetadata {1, __hostFunction_NativeAppearanceCxxSpecJSI_setColorScheme};
981-
methodMap_["addListener"] = MethodMetadata {1, __hostFunction_NativeAppearanceCxxSpecJSI_addListener};
982-
methodMap_["removeListeners"] = MethodMetadata {1, __hostFunction_NativeAppearanceCxxSpecJSI_removeListeners};
983-
}
984949
static jsi::Value __hostFunction_NativeAppStateCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
985950
return static_cast<NativeAppStateCxxSpecJSI *>(&turboModule)->getConstants(
986951
rt
@@ -1026,6 +991,41 @@ NativeAppThemeCxxSpecJSI::NativeAppThemeCxxSpecJSI(std::shared_ptr<CallInvoker>
1026991
: TurboModule("AppTheme", jsInvoker) {
1027992
methodMap_["getConstants"] = MethodMetadata {0, __hostFunction_NativeAppThemeCxxSpecJSI_getConstants};
1028993
}
994+
static jsi::Value __hostFunction_NativeAppearanceCxxSpecJSI_getColorScheme(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
995+
auto result = static_cast<NativeAppearanceCxxSpecJSI *>(&turboModule)->getColorScheme(
996+
rt
997+
);
998+
return result ? jsi::Value(std::move(*result)) : jsi::Value::null();
999+
}
1000+
static jsi::Value __hostFunction_NativeAppearanceCxxSpecJSI_setColorScheme(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
1001+
static_cast<NativeAppearanceCxxSpecJSI *>(&turboModule)->setColorScheme(
1002+
rt,
1003+
count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt)
1004+
);
1005+
return jsi::Value::undefined();
1006+
}
1007+
static jsi::Value __hostFunction_NativeAppearanceCxxSpecJSI_addListener(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
1008+
static_cast<NativeAppearanceCxxSpecJSI *>(&turboModule)->addListener(
1009+
rt,
1010+
count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt)
1011+
);
1012+
return jsi::Value::undefined();
1013+
}
1014+
static jsi::Value __hostFunction_NativeAppearanceCxxSpecJSI_removeListeners(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
1015+
static_cast<NativeAppearanceCxxSpecJSI *>(&turboModule)->removeListeners(
1016+
rt,
1017+
count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asNumber()
1018+
);
1019+
return jsi::Value::undefined();
1020+
}
1021+
1022+
NativeAppearanceCxxSpecJSI::NativeAppearanceCxxSpecJSI(std::shared_ptr<CallInvoker> jsInvoker)
1023+
: TurboModule("Appearance", jsInvoker) {
1024+
methodMap_["getColorScheme"] = MethodMetadata {0, __hostFunction_NativeAppearanceCxxSpecJSI_getColorScheme};
1025+
methodMap_["setColorScheme"] = MethodMetadata {1, __hostFunction_NativeAppearanceCxxSpecJSI_setColorScheme};
1026+
methodMap_["addListener"] = MethodMetadata {1, __hostFunction_NativeAppearanceCxxSpecJSI_addListener};
1027+
methodMap_["removeListeners"] = MethodMetadata {1, __hostFunction_NativeAppearanceCxxSpecJSI_removeListeners};
1028+
}
10291029
static jsi::Value __hostFunction_NativeBlobModuleCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
10301030
return static_cast<NativeBlobModuleCxxSpecJSI *>(&turboModule)->getConstants(
10311031
rt
@@ -1129,27 +1129,6 @@ NativeClipboardCxxSpecJSI::NativeClipboardCxxSpecJSI(std::shared_ptr<CallInvoker
11291129
methodMap_["getString"] = MethodMetadata {0, __hostFunction_NativeClipboardCxxSpecJSI_getString};
11301130
methodMap_["setString"] = MethodMetadata {1, __hostFunction_NativeClipboardCxxSpecJSI_setString};
11311131
}
1132-
static jsi::Value __hostFunction_NativeDeviceEventManagerCxxSpecJSI_invokeDefaultBackPressHandler(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
1133-
static_cast<NativeDeviceEventManagerCxxSpecJSI *>(&turboModule)->invokeDefaultBackPressHandler(
1134-
rt
1135-
);
1136-
return jsi::Value::undefined();
1137-
}
1138-
1139-
NativeDeviceEventManagerCxxSpecJSI::NativeDeviceEventManagerCxxSpecJSI(std::shared_ptr<CallInvoker> jsInvoker)
1140-
: TurboModule("DeviceEventManager", jsInvoker) {
1141-
methodMap_["invokeDefaultBackPressHandler"] = MethodMetadata {0, __hostFunction_NativeDeviceEventManagerCxxSpecJSI_invokeDefaultBackPressHandler};
1142-
}
1143-
static jsi::Value __hostFunction_NativeDeviceInfoCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
1144-
return static_cast<NativeDeviceInfoCxxSpecJSI *>(&turboModule)->getConstants(
1145-
rt
1146-
);
1147-
}
1148-
1149-
NativeDeviceInfoCxxSpecJSI::NativeDeviceInfoCxxSpecJSI(std::shared_ptr<CallInvoker> jsInvoker)
1150-
: TurboModule("DeviceInfo", jsInvoker) {
1151-
methodMap_["getConstants"] = MethodMetadata {0, __hostFunction_NativeDeviceInfoCxxSpecJSI_getConstants};
1152-
}
11531132
static jsi::Value __hostFunction_NativeDevLoadingViewCxxSpecJSI_showMessage(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
11541133
static_cast<NativeDevLoadingViewCxxSpecJSI *>(&turboModule)->showMessage(
11551134
rt,
@@ -1293,6 +1272,27 @@ NativeDevSettingsCxxSpecJSI::NativeDevSettingsCxxSpecJSI(std::shared_ptr<CallInv
12931272
methodMap_["removeListeners"] = MethodMetadata {1, __hostFunction_NativeDevSettingsCxxSpecJSI_removeListeners};
12941273
methodMap_["setIsShakeToShowDevMenuEnabled"] = MethodMetadata {1, __hostFunction_NativeDevSettingsCxxSpecJSI_setIsShakeToShowDevMenuEnabled};
12951274
}
1275+
static jsi::Value __hostFunction_NativeDeviceEventManagerCxxSpecJSI_invokeDefaultBackPressHandler(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
1276+
static_cast<NativeDeviceEventManagerCxxSpecJSI *>(&turboModule)->invokeDefaultBackPressHandler(
1277+
rt
1278+
);
1279+
return jsi::Value::undefined();
1280+
}
1281+
1282+
NativeDeviceEventManagerCxxSpecJSI::NativeDeviceEventManagerCxxSpecJSI(std::shared_ptr<CallInvoker> jsInvoker)
1283+
: TurboModule("DeviceEventManager", jsInvoker) {
1284+
methodMap_["invokeDefaultBackPressHandler"] = MethodMetadata {0, __hostFunction_NativeDeviceEventManagerCxxSpecJSI_invokeDefaultBackPressHandler};
1285+
}
1286+
static jsi::Value __hostFunction_NativeDeviceInfoCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
1287+
return static_cast<NativeDeviceInfoCxxSpecJSI *>(&turboModule)->getConstants(
1288+
rt
1289+
);
1290+
}
1291+
1292+
NativeDeviceInfoCxxSpecJSI::NativeDeviceInfoCxxSpecJSI(std::shared_ptr<CallInvoker> jsInvoker)
1293+
: TurboModule("DeviceInfo", jsInvoker) {
1294+
methodMap_["getConstants"] = MethodMetadata {0, __hostFunction_NativeDeviceInfoCxxSpecJSI_getConstants};
1295+
}
12961296
static jsi::Value __hostFunction_NativeDialogManagerAndroidCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
12971297
return static_cast<NativeDialogManagerAndroidCxxSpecJSI *>(&turboModule)->getConstants(
12981298
rt

0 commit comments

Comments
 (0)