diff --git a/change/react-native-windows-fix-textinput-touch-keyboard.json b/change/react-native-windows-fix-textinput-touch-keyboard.json new file mode 100644 index 00000000000..2f77f204699 --- /dev/null +++ b/change/react-native-windows-fix-textinput-touch-keyboard.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Fix(textinput): show the touch keyboard on focus and on tap for the windowless island TextInput (no CoreWindow auto-invoke) via InputPane Win32 interop — re-tapping an already-focused field reopens a dismissed keyboard", + "packageName": "react-native-windows", + "email": "collindanielschneide@gmail.com", + "dependentChangeType": "patch" +} diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp index 2fd8fcde9a1..482f3a17e9b 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include "../Composition.Input.h" #include "../CompositionHelpers.h" #include "../RootComponentView.h" @@ -729,6 +731,10 @@ void WindowsTextInputComponentView::OnPointerPressed( emitter->onPressIn(pressInArgs); } + + // Tapping the field brings up the touch keyboard — including when the input is already + // focused (e.g. after the user dismissed the keyboard), which does not fire onGotFocus. + ShowSoftKeyboard(); } void WindowsTextInputComponentView::OnPointerReleased( @@ -1069,6 +1075,43 @@ void WindowsTextInputComponentView::onLostFocus( } } +void WindowsTextInputComponentView::ShowSoftKeyboard() noexcept { + // On a tablet with no physical keyboard the shell never auto-invokes the touch + // keyboard for a windowless RichEdit host: in the WinAppSDK island model there is no + // CoreWindow, and the RichEdit is hosted via ITextServices with no child input HWND, + // so the OS heuristic can't see a focused edit control and never fires. Request the + // touch keyboard explicitly via the InputPane Win32 interop, keyed off the island's + // top-level AppWindow HWND (rootComponentView()->GetHwndForParenting()). Gated to + // slate/tablet posture (SM_CONVERTIBLESLATEMODE == 0) so it does not pop on a + // laptop/convertible with a keyboard attached. Called on focus AND on pointer press, + // so tapping an already-focused input reopens a keyboard the user had dismissed (a tap + // on an already-focused field does not fire onGotFocus). Best-effort — never let + // keyboard invocation break input handling. + if (::GetSystemMetrics(SM_CONVERTIBLESLATEMODE) != 0) + return; + auto root = rootComponentView(); + if (!root) + return; + HWND hwnd = root->GetHwndForParenting(); + if (!hwnd) + return; + try { + auto interop = + winrt::get_activation_factory() + .as<::IInputPaneInterop>(); + winrt::Windows::UI::ViewManagement::InputPane inputPane{nullptr}; + if (interop && + SUCCEEDED(interop->GetForWindow( + hwnd, + winrt::guid_of(), + winrt::put_abi(inputPane))) && + inputPane) { + inputPane.TryShow(); + } + } catch (...) { + } +} + void WindowsTextInputComponentView::onGotFocus( const winrt::Microsoft::ReactNative::Composition::Input::RoutedEventArgs &args) noexcept { m_hasFocus = true; @@ -1085,6 +1128,9 @@ void WindowsTextInputComponentView::onGotFocus( m_textServices->TxSendMessage(EM_SETSEL, static_cast(0), static_cast(-1), &res); } } + + // Bring up the touch keyboard when this input gains focus. + ShowSoftKeyboard(); } std::string WindowsTextInputComponentView::DefaultControlType() const noexcept { diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h b/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h index d9915d6acc6..e6c7388ce38 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h @@ -121,6 +121,9 @@ struct WindowsTextInputComponentView void updateSpellCheck(bool value) noexcept; void ShowContextMenu(const winrt::Windows::Foundation::Point &position) noexcept; void calculateContentVerticalOffset() noexcept; + // Request the on-screen touch keyboard for this input (InputPane interop), called on + // focus and on tap. See the .cpp for the windowing-model rationale. + void ShowSoftKeyboard() noexcept; winrt::Windows::UI::Composition::CompositionSurfaceBrush m_brush{nullptr}; winrt::Microsoft::ReactNative::Composition::Experimental::ICaretVisual m_caretVisual{nullptr};