diff --git a/packages/@react-native-windows/tester/src/js/examples/TextInput/TextInputExample.windows.js b/packages/@react-native-windows/tester/src/js/examples/TextInput/TextInputExample.windows.js index 8c1bfc7adf2..bac75a6fd84 100644 --- a/packages/@react-native-windows/tester/src/js/examples/TextInput/TextInputExample.windows.js +++ b/packages/@react-native-windows/tester/src/js/examples/TextInput/TextInputExample.windows.js @@ -802,6 +802,22 @@ const examples: Array = [ ); }, }, + { + title: 'ContextMenuHidden set to True', + render: function (): React.Node { + return ( + + ContextMenuHidden (Right-click to test) + + + ); + }, + }, { title: 'Cursorcolor set to Green', render: function (): React.Node { diff --git a/packages/e2e-test-app-fabric/test/TextInputComponentTest.test.ts b/packages/e2e-test-app-fabric/test/TextInputComponentTest.test.ts index 2f2eadbf835..bbebf0af2f7 100644 --- a/packages/e2e-test-app-fabric/test/TextInputComponentTest.test.ts +++ b/packages/e2e-test-app-fabric/test/TextInputComponentTest.test.ts @@ -930,6 +930,23 @@ describe('TextInput Tests', () => { const dump = await dumpVisualTree('textinput-carethidden'); expect(dump).toMatchSnapshot(); }); + test('TextInputs can have contextMenuHidden', async () => { + const component = await app.findElementByTestID('textinput-contextmenuhidden'); + 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.`, + }, + ); + const dump = await dumpVisualTree('textinput-contextmenuhidden'); + expect(dump).toMatchSnapshot(); + }); test('Text have cursorColor', async () => { const component = await app.findElementByTestID('textinput-cursorColor'); await component.waitForDisplayed({timeout: 5000}); diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp index d364125d214..ba6ecb2cb28 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp @@ -736,7 +736,10 @@ void WindowsTextInputComponentView::OnPointerReleased( msg = WM_MBUTTONUP; break; case winrt::Microsoft::ReactNative::Composition::Input::PointerUpdateKind::RightButtonReleased: - msg = WM_RBUTTONUP; + // Don't send right button up to RichEdit if context menu is hidden + if (!windowsTextInputProps().contextMenuHidden) { + msg = WM_RBUTTONUP; + } break; case winrt::Microsoft::ReactNative::Composition::Input::PointerUpdateKind::XButton1Released: msg = WM_XBUTTONUP; @@ -797,6 +800,23 @@ void WindowsTextInputComponentView::OnKeyDown( const winrt::Microsoft::ReactNative::Composition::Input::KeyRoutedEventArgs &args) noexcept { // Do not forward tab keys into the TextInput, since we want that to do the tab loop instead. This aligns with WinUI // behavior We do forward Ctrl+Tab to the textinput. + + // Check for context menu keyboard shortcuts when contextMenuHidden is true + if (windowsTextInputProps().contextMenuHidden) { + // Block Menu key (VK_APPS) + if (args.Key() == winrt::Windows::System::VirtualKey::Application) { + args.Handled(true); + return; + } + // Block Shift+F10 + if (args.Key() == winrt::Windows::System::VirtualKey::F10 && + (args.KeyboardSource().GetKeyState(winrt::Windows::System::VirtualKey::Shift) & + winrt::Microsoft::UI::Input::VirtualKeyStates::Down) == winrt::Microsoft::UI::Input::VirtualKeyStates::Down) { + args.Handled(true); + return; + } + } + if (args.Key() != winrt::Windows::System::VirtualKey::Tab || (args.KeyboardSource().GetKeyState(winrt::Windows::System::VirtualKey::Control) & winrt::Microsoft::UI::Input::VirtualKeyStates::Down) == winrt::Microsoft::UI::Input::VirtualKeyStates::Down) {