@@ -697,10 +697,17 @@ void WindowsTextInputComponentView::OnPointerPressed(
697697 }
698698
699699 if (m_textServices && msg) {
700- LRESULT lresult;
701- DrawBlock db (*this );
702- auto hr = m_textServices->TxSendMessage (msg, static_cast <WPARAM>(wParam), static_cast <LPARAM>(lParam), &lresult);
703- args.Handled (hr != S_FALSE);
700+ if (msg == WM_RBUTTONUP && !windowsTextInputProps ().contextMenuHidden ) {
701+ ShowContextMenu (position);
702+ args.Handled (true );
703+ } else if (msg == WM_RBUTTONUP && windowsTextInputProps ().contextMenuHidden ) {
704+ args.Handled (true );
705+ } else {
706+ LRESULT lresult;
707+ DrawBlock db (*this );
708+ auto hr = m_textServices->TxSendMessage (msg, static_cast <WPARAM>(wParam), static_cast <LPARAM>(lParam), &lresult);
709+ args.Handled (hr != S_FALSE);
710+ }
704711 }
705712
706713 // Emits the OnPressIn event
@@ -844,8 +851,8 @@ void WindowsTextInputComponentView::OnPointerWheelChanged(
844851}
845852void WindowsTextInputComponentView::OnKeyDown (
846853 const winrt::Microsoft::ReactNative::Composition::Input::KeyRoutedEventArgs &args) noexcept {
847- // Do not forward tab keys into the TextInput, since we want that to do the tab loop instead. This aligns with WinUI
848- // behavior We do forward Ctrl+Tab to the textinput.
854+ // Do not forward tab keys into the TextInput, since we want that to do the tab loop instead. This aligns with
855+ // WinUI behavior We do forward Ctrl+Tab to the textinput.
849856 if (args.Key () != winrt::Windows::System::VirtualKey::Tab ||
850857 (args.KeyboardSource ().GetKeyState (winrt::Windows::System::VirtualKey::Control) &
851858 winrt::Microsoft::UI::Input::VirtualKeyStates::Down) == winrt::Microsoft::UI::Input::VirtualKeyStates::Down) {
@@ -872,8 +879,8 @@ void WindowsTextInputComponentView::OnKeyDown(
872879
873880void WindowsTextInputComponentView::OnKeyUp (
874881 const winrt::Microsoft::ReactNative::Composition::Input::KeyRoutedEventArgs &args) noexcept {
875- // Do not forward tab keys into the TextInput, since we want that to do the tab loop instead. This aligns with WinUI
876- // behavior We do forward Ctrl+Tab to the textinput.
882+ // Do not forward tab keys into the TextInput, since we want that to do the tab loop instead. This aligns with
883+ // WinUI behavior We do forward Ctrl+Tab to the textinput.
877884 if (args.Key () != winrt::Windows::System::VirtualKey::Tab ||
878885 (args.KeyboardSource ().GetKeyState (winrt::Windows::System::VirtualKey::Control) &
879886 winrt::Microsoft::UI::Input::VirtualKeyStates::Down) == winrt::Microsoft::UI::Input::VirtualKeyStates::Down) {
@@ -943,8 +950,8 @@ bool WindowsTextInputComponentView::ShouldSubmit(
943950
944951void WindowsTextInputComponentView::OnCharacterReceived (
945952 const winrt::Microsoft::ReactNative::Composition::Input::CharacterReceivedRoutedEventArgs &args) noexcept {
946- // Do not forward tab keys into the TextInput, since we want that to do the tab loop instead. This aligns with WinUI
947- // behavior We do forward Ctrl+Tab to the textinput.
953+ // Do not forward tab keys into the TextInput, since we want that to do the tab loop instead. This aligns with
954+ // WinUI behavior We do forward Ctrl+Tab to the textinput.
948955 if ((args.KeyCode () == ' \t ' ) &&
949956 ((args.KeyboardSource ().GetKeyState (winrt::Windows::System::VirtualKey::Control) &
950957 winrt::Microsoft::UI::Input::VirtualKeyStates::Down) != winrt::Microsoft::UI::Input::VirtualKeyStates::Down)) {
@@ -1827,4 +1834,47 @@ void WindowsTextInputComponentView::updateSpellCheck(bool enable) noexcept {
18271834 winrt::check_hresult (
18281835 m_textServices->TxSendMessage (EM_SETLANGOPTIONS, IMF_SPELLCHECKING, enable ? newLangOptions : 0 , &lresult));
18291836}
1837+
1838+ void WindowsTextInputComponentView::ShowContextMenu (const winrt::Windows::Foundation::Point &position) noexcept {
1839+ HMENU menu = CreatePopupMenu ();
1840+ if (!menu)
1841+ return ;
1842+
1843+ CHARRANGE selection;
1844+ LRESULT res;
1845+ m_textServices->TxSendMessage (EM_EXGETSEL, 0 , reinterpret_cast <LPARAM>(&selection), &res);
1846+
1847+ bool hasSelection = selection.cpMin != selection.cpMax ;
1848+ bool isEmpty = GetTextFromRichEdit ().empty ();
1849+ bool isReadOnly = windowsTextInputProps ().editable == false ;
1850+ bool canPaste = !isReadOnly && IsClipboardFormatAvailable (CF_UNICODETEXT);
1851+
1852+ AppendMenuW (menu, MF_STRING | (hasSelection && !isReadOnly ? 0 : MF_GRAYED), 1 , L" Cut" );
1853+ AppendMenuW (menu, MF_STRING | (hasSelection ? 0 : MF_GRAYED), 2 , L" Copy" );
1854+ AppendMenuW (menu, MF_STRING | (canPaste ? 0 : MF_GRAYED), 3 , L" Paste" );
1855+ AppendMenuW (menu, MF_STRING | (!isEmpty && !isReadOnly ? 0 : MF_GRAYED), 4 , L" Select All" );
1856+
1857+ POINT cursorPos;
1858+ GetCursorPos (&cursorPos);
1859+
1860+ HWND hwnd = GetActiveWindow ();
1861+
1862+ int cmd = TrackPopupMenu (
1863+ menu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD | TPM_NONOTIFY, cursorPos.x , cursorPos.y , 0 , hwnd, NULL );
1864+
1865+ if (cmd == 1 ) { // Cut
1866+ m_textServices->TxSendMessage (WM_CUT, 0 , 0 , &res);
1867+ OnTextUpdated ();
1868+ } else if (cmd == 2 ) { // Copy
1869+ m_textServices->TxSendMessage (WM_COPY, 0 , 0 , &res);
1870+ } else if (cmd == 3 ) { // Paste
1871+ m_textServices->TxSendMessage (WM_PASTE, 0 , 0 , &res);
1872+ OnTextUpdated ();
1873+ } else if (cmd == 4 ) { // Select All
1874+ m_textServices->TxSendMessage (EM_SETSEL, 0 , -1 , &res);
1875+ }
1876+
1877+ DestroyMenu (menu);
1878+ }
1879+
18301880} // namespace winrt::Microsoft::ReactNative::Composition::implementation
0 commit comments