Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fabric] Add onSubmitEditing and clearTextOnSubmit #12746

Merged
merged 5 commits into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "sumbitkeyevents working with shift",
"packageName": "react-native-windows",
"email": "tatianakapos@microsoft.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,28 @@ describe('TextInput Tests', () => {
'textinput-clear-on-submit',
);
await component.waitForDisplayed({timeout: 5000});
await app.waitUntil(
async () => {
await component.setValue('Hello World');
return (await component.getText()) === 'Hello World';
},
{
interval: 1500,
timeout: 5000,
timeoutMsg: `Unable to enter correct text.`,
},
);
await app.waitUntil(
async () => {
await component.setValue('\uE007');
return (await component.getText()) === '';
},
{
interval: 1500,
timeout: 5000,
timeoutMsg: `Unable to enter correct text.`,
},
);
const dump = await dumpVisualTree('textinput-clear-on-submit');
expect(dump).toMatchSnapshot();
});
Expand All @@ -283,11 +305,33 @@ describe('TextInput Tests', () => {
const dump = await dumpVisualTree('textinput-clear-on-submit-3');
expect(dump).toMatchSnapshot();
});
test('TextInputs can submit with custom key', async () => {
test('TextInputs can submit with custom key, multilined and submit with enter', async () => {
const component = await app.findElementByTestID(
'textinput-clear-on-submit-4',
);
await component.waitForDisplayed({timeout: 5000});
await app.waitUntil(
async () => {
await component.setValue('Hello World');
return (await component.getText()) === 'Hello World';
},
{
interval: 1500,
timeout: 5000,
timeoutMsg: `Unable to enter correct text.`,
},
);
await app.waitUntil(
async () => {
await component.setValue('\uE007');
return (await component.getText()) === '';
},
{
interval: 1500,
timeout: 5000,
timeoutMsg: `Unable to enter correct text.`,
},
);
const dump = await dumpVisualTree('textinput-clear-on-submit-4');
expect(dump).toMatchSnapshot();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2421,8 +2421,8 @@ exports[`TextInput Tests TextInputs can clear on submit 1`] = `
],
"Opacity": 0,
"Size": [
0,
0,
1,
19,
],
"Visual Type": "SpriteVisual",
},
Expand Down Expand Up @@ -6071,7 +6071,7 @@ exports[`TextInput Tests TextInputs can set their readOnly prop to true 1`] = `
}
`;

exports[`TextInput Tests TextInputs can submit with custom key 1`] = `
exports[`TextInput Tests TextInputs can submit with custom key, multilined and submit with enter 1`] = `
{
"Automation Tree": {
"AutomationId": "textinput-clear-on-submit-4",
Expand All @@ -6096,8 +6096,8 @@ exports[`TextInput Tests TextInputs can submit with custom key 1`] = `
],
"Opacity": 0,
"Size": [
0,
0,
1,
19,
],
"Visual Type": "SpriteVisual",
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,44 @@ void WindowsTextInputComponentView::OnKeyUp(
Super::OnKeyDown(source, args);
}

bool WindowsTextInputComponentView::ShouldSubmit(
const winrt::Microsoft::ReactNative::Composition::Input::KeyboardSource &source,
const winrt::Microsoft::ReactNative::Composition::Input::CharacterReceivedRoutedEventArgs &args) noexcept {
bool shouldSubmit = true;

if (shouldSubmit) {
if (!m_multiline && m_submitKeyEvents.size() == 0) {
// If no 'submitKeyEvents' are supplied, use the default behavior for single-line TextInput
shouldSubmit = args.KeyCode() == '\r';
} else if (m_submitKeyEvents.size() > 0) {
auto submitKeyEvent = m_submitKeyEvents.at(0);
// If 'submitKeyEvents' are supplied, use them to determine whether to emit onSubmitEditing' for either
// single-line or multi-line TextInput
if (args.KeyCode() == '\r') {
bool shiftDown = source.GetKeyState(winrt::Windows::System::VirtualKey::Shift) ==
winrt::Windows::UI::Core::CoreVirtualKeyStates::Down;
bool ctrlDown = source.GetKeyState(winrt::Windows::System::VirtualKey::Control) ==
winrt::Windows::UI::Core::CoreVirtualKeyStates::Down;
bool altDown = source.GetKeyState(winrt::Windows::System::VirtualKey::Control) ==
winrt::Windows::UI::Core::CoreVirtualKeyStates::Down;
bool metaDown = source.GetKeyState(winrt::Windows::System::VirtualKey::LeftWindows) ==
winrt::Windows::UI::Core::CoreVirtualKeyStates::Down ||
source.GetKeyState(winrt::Windows::System::VirtualKey::RightWindows) ==
winrt::Windows::UI::Core::CoreVirtualKeyStates::Down;
return (submitKeyEvent.shiftKey && shiftDown) || (submitKeyEvent.ctrlKey && ctrlDown) ||
(submitKeyEvent.altKey && altDown) || (submitKeyEvent.metaKey && metaDown) ||
(!submitKeyEvent.shiftKey && !submitKeyEvent.altKey && !submitKeyEvent.metaKey && !submitKeyEvent.altKey &&
!shiftDown && !ctrlDown && !altDown && !metaDown);
} else {
shouldSubmit = false;
}
} else {
shouldSubmit = false;
}
}
return shouldSubmit;
}

void WindowsTextInputComponentView::OnCharacterReceived(
const winrt::Microsoft::ReactNative::Composition::Input::KeyboardSource &source,
const winrt::Microsoft::ReactNative::Composition::Input::CharacterReceivedRoutedEventArgs &args) noexcept {
Expand All @@ -809,6 +847,24 @@ void WindowsTextInputComponentView::OnCharacterReceived(
return;
}

// Logic for submit events
if (ShouldSubmit(source, args)) {
// call onSubmitEditing event
if (m_eventEmitter && !m_comingFromJS) {
auto emitter = std::static_pointer_cast<const facebook::react::WindowsTextInputEventEmitter>(m_eventEmitter);
facebook::react::WindowsTextInputEventEmitter::OnSubmitEditing onSubmitEditingArgs;
onSubmitEditingArgs.text = GetTextFromRichEdit();
onSubmitEditingArgs.eventCount = ++m_nativeEventCount;
emitter->onSubmitEditing(onSubmitEditingArgs);
}

if (m_clearTextOnSubmit) {
// clear text from RichEdit
m_textServices->TxSetText(L"");
}
return;
}

WPARAM wParam = static_cast<WPARAM>(args.KeyCode());
LPARAM lParam = 0;
lParam = args.KeyStatus().RepeatCount; // bits 0-15
Expand Down Expand Up @@ -926,6 +982,7 @@ void WindowsTextInputComponentView::updateProps(
}

if (oldTextInputProps.multiline != newTextInputProps.multiline) {
m_multiline = newTextInputProps.multiline;
propBitsMask |= TXTBIT_MULTILINE | TXTBIT_WORDWRAP;
if (newTextInputProps.multiline) {
propBits |= TXTBIT_MULTILINE | TXTBIT_WORDWRAP;
Expand All @@ -952,6 +1009,16 @@ void WindowsTextInputComponentView::updateProps(
updateCursorColor(newTextInputProps.cursorColor, newTextInputProps.textAttributes.foregroundColor);
}

if (oldTextInputProps.clearTextOnSubmit != newTextInputProps.clearTextOnSubmit) {
m_clearTextOnSubmit = newTextInputProps.clearTextOnSubmit;
}

if ((!newTextInputProps.submitKeyEvents.empty())) {
m_submitKeyEvents = newTextInputProps.submitKeyEvents;
} else {
m_submitKeyEvents.clear();
}

/*
if (oldTextInputProps.textAttributes.foregroundColor != newTextInputProps.textAttributes.foregroundColor) {
if (newTextInputProps.textAttributes.foregroundColor)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ struct WindowsTextInputComponentView : WindowsTextInputComponentViewT<WindowsTex
void updateCursorColor(
const facebook::react::SharedColor &cursorColor,
const facebook::react::SharedColor &foregroundColor) noexcept;
bool ShouldSubmit(
const winrt::Microsoft::ReactNative::Composition::Input::KeyboardSource &source,
const winrt::Microsoft::ReactNative::Composition::Input::CharacterReceivedRoutedEventArgs &args) noexcept;

winrt::Windows::UI::Composition::CompositionSurfaceBrush m_brush{nullptr};
winrt::Microsoft::ReactNative::Composition::ISpriteVisual m_visual{nullptr};
Expand All @@ -132,6 +135,9 @@ struct WindowsTextInputComponentView : WindowsTextInputComponentViewT<WindowsTex
int m_cDrawBlock{0};
bool m_needsRedraw{false};
bool m_drawing{false};
bool m_clearTextOnSubmit{false};
bool m_multiline{false};
std::vector<facebook::react::CompWindowsTextInputSubmitKeyEventsStruct> m_submitKeyEvents;
};

} // namespace winrt::Microsoft::ReactNative::Composition::implementation
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,14 @@ void WindowsTextInputEventEmitter::onSelectionChange(const OnSelectionChange &ev
});
}

void WindowsTextInputEventEmitter::onSubmitEditing(OnSubmitEditing event) const {
dispatchEvent("textInputSubmitEditing", [event = std::move(event)](jsi::Runtime &runtime) {
auto payload = jsi::Object(runtime);
payload.setProperty(runtime, "eventCount", event.eventCount);
payload.setProperty(runtime, "target", event.target);
payload.setProperty(runtime, "text", event.text);
return payload;
});
}

} // namespace facebook::react
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,15 @@ class WindowsTextInputEventEmitter : public ViewEventEmitter {
Selection selection;
};

struct OnSubmitEditing {
int eventCount;
int target;
std::string text;
};

void onChange(OnChange value) const;
void onSelectionChange(const OnSelectionChange &value) const;
void onSubmitEditing(OnSubmitEditing value) const;
};

} // namespace facebook::react
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ static inline std::string toString(const CompWindowsTextInputSelectionStruct &va
}

struct CompWindowsTextInputSubmitKeyEventsStruct {
bool altKey;
bool ctrlKey;
bool metaKey;
bool shiftKey;
bool altKey{false};
bool ctrlKey{false};
bool metaKey{false};
bool shiftKey{false};
std::string code;
};

Expand Down