From 8004002e5ebf79956617ccb4d2b51d0856b5490c Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 23 Jul 2021 16:59:08 +0100 Subject: [PATCH] Fix handling keys also used as accelerators in wxMSW wxComboBox wxComboBox::MSWShouldPreProcessMessage() didn't take into account many keys that must be handled in wxComboBox even if they're used as accelerators, including plain (i.e. without Ctrl modifier) Delete, Home and End that are used by the embedded text control, if there is one. Fix this by reusing wxTextCtrl::MSWShouldPreProcessMessage() which already handled these keys correctly, by moving it to wxTextEntry, which can be used from both classes. Also add a check for wxCB_READONLY to prevent overriding the accelerators using the keys that the combobox doesn't need when there is no text control in it. Closes #19227. --- include/wx/msw/textentry.h | 4 ++ src/msw/combobox.cpp | 23 ++--------- src/msw/textctrl.cpp | 85 ++++++++------------------------------ src/msw/textentry.cpp | 70 +++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 88 deletions(-) diff --git a/include/wx/msw/textentry.h b/include/wx/msw/textentry.h index b21078b15a..9de5182066 100644 --- a/include/wx/msw/textentry.h +++ b/include/wx/msw/textentry.h @@ -84,6 +84,10 @@ protected: // Returns true if this control uses standard file names completion. bool MSWUsesStandardAutoComplete() const; + // Returns false if this message shouldn't be preprocessed, but is always + // handled by the EDIT control represented by this object itself. + bool MSWShouldPreProcessMessage(WXMSG* msg) const; + // Helper for wxTE_PROCESS_ENTER handling: activates the default button in // the dialog containing this control if any. bool ClickDefaultButtonIfPossible(); diff --git a/src/msw/combobox.cpp b/src/msw/combobox.cpp index 8d2001c417..94a9c03385 100644 --- a/src/msw/combobox.cpp +++ b/src/msw/combobox.cpp @@ -383,26 +383,9 @@ bool wxComboBox::MSWCommand(WXUINT param, WXWORD id) bool wxComboBox::MSWShouldPreProcessMessage(WXMSG *pMsg) { - // prevent command accelerators from stealing editing - // hotkeys when we have the focus - if (wxIsCtrlDown()) - { - WPARAM vkey = pMsg->wParam; - - switch (vkey) - { - case 'C': - case 'V': - case 'X': - case VK_INSERT: - case VK_DELETE: - case VK_HOME: - case VK_END: - return false; - } - } - - return wxChoice::MSWShouldPreProcessMessage(pMsg); + return (HasFlag(wxCB_READONLY) || + wxTextEntry::MSWShouldPreProcessMessage(pMsg)) && + wxChoice::MSWShouldPreProcessMessage(pMsg); } #if wxUSE_OLE diff --git a/src/msw/textctrl.cpp b/src/msw/textctrl.cpp index f1f54209a7..8fff33e265 100644 --- a/src/msw/textctrl.cpp +++ b/src/msw/textctrl.cpp @@ -2058,80 +2058,29 @@ void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event) bool wxTextCtrl::MSWShouldPreProcessMessage(WXMSG* msg) { - // check for our special keys here: if we don't do it and the parent frame - // uses them as accelerators, they wouldn't work at all, so we disable - // usual preprocessing for them - if ( msg->message == WM_KEYDOWN ) + // Handle keys specific to (multiline) text controls here. + if ( msg->message == WM_KEYDOWN && !(HIWORD(msg->lParam) & KF_ALTDOWN) ) { - const WPARAM vkey = msg->wParam; - if ( HIWORD(msg->lParam) & KF_ALTDOWN ) + switch ( msg->wParam ) { - // Alt-Backspace is accelerator for "Undo" - if ( vkey == VK_BACK ) - return false; - } - else // no Alt - { - // we want to process some Ctrl-foo and Shift-bar but no key - // combinations without either Ctrl or Shift nor with both of them - // pressed - const int ctrl = wxIsCtrlDown(), - shift = wxIsShiftDown(); - switch ( ctrl + shift ) - { - default: - wxFAIL_MSG( wxT("how many modifiers have we got?") ); - wxFALLTHROUGH; + case VK_RETURN: + // This key must be handled only by multiline controls and only + // if it's pressed on its own, not with some modifier. + if ( !wxIsShiftDown() && !wxIsCtrlDown() && IsMultiLine() ) + return false; + break; - case 0: - switch ( vkey ) - { - case VK_RETURN: - // This one is only special for multi line controls. - if ( !IsMultiLine() ) - break; - wxFALLTHROUGH; - - case VK_DELETE: - case VK_HOME: - case VK_END: - return false; - } - wxFALLTHROUGH; - case 2: - break; - - case 1: - // either Ctrl or Shift pressed - if ( ctrl ) - { - switch ( vkey ) - { - case 'A': - case 'C': - case 'V': - case 'X': - case VK_INSERT: - case VK_DELETE: - case VK_HOME: - case VK_END: - return false; - - case VK_BACK: - if ( MSWNeedsToHandleCtrlBackspace() ) - return false; - } - } - else // Shift is pressed - { - if ( vkey == VK_INSERT || vkey == VK_DELETE ) - return false; - } - } + case VK_BACK: + if ( wxIsCtrlDown() && !wxIsShiftDown() && + MSWNeedsToHandleCtrlBackspace() ) + return false; + break; } } - return wxControl::MSWShouldPreProcessMessage(msg); + // Delegate all the other checks to the base classes. + return wxTextEntry::MSWShouldPreProcessMessage(msg) && + wxControl::MSWShouldPreProcessMessage(msg); } void wxTextCtrl::OnChar(wxKeyEvent& event) diff --git a/src/msw/textentry.cpp b/src/msw/textentry.cpp index 4b009bd325..6b0205c750 100644 --- a/src/msw/textentry.cpp +++ b/src/msw/textentry.cpp @@ -1072,4 +1072,74 @@ bool wxTextEntry::ClickDefaultButtonIfPossible() wxWindow::MSWGetDefaultButtonFor(GetEditableWindow())); } +bool wxTextEntry::MSWShouldPreProcessMessage(WXMSG* msg) const +{ + // check for our special keys here: if we don't do it and the parent frame + // uses them as accelerators, they wouldn't work at all, so we disable + // usual preprocessing for them + if ( msg->message == WM_KEYDOWN ) + { + const WPARAM vkey = msg->wParam; + if ( HIWORD(msg->lParam) & KF_ALTDOWN ) + { + // Alt-Backspace is accelerator for "Undo" + if ( vkey == VK_BACK ) + return false; + } + else // no Alt + { + // we want to process some Ctrl-foo and Shift-bar but no key + // combinations without either Ctrl or Shift nor with both of them + // pressed + const int ctrl = wxIsCtrlDown(), + shift = wxIsShiftDown(); + switch ( ctrl + shift ) + { + default: + wxFAIL_MSG( wxT("how many modifiers have we got?") ); + wxFALLTHROUGH; + + case 0: + switch ( vkey ) + { + case VK_DELETE: + case VK_HOME: + case VK_END: + return false; + } + break; + + case 1: + // either Ctrl or Shift pressed + if ( ctrl ) + { + switch ( vkey ) + { + case 'A': + case 'C': + case 'V': + case 'X': + case VK_INSERT: + case VK_DELETE: + case VK_HOME: + case VK_END: + return false; + } + } + else // Shift is pressed + { + if ( vkey == VK_INSERT || vkey == VK_DELETE ) + return false; + } + break; + + case 2: + break; + } + } + } + + return true; +} + #endif // wxUSE_TEXTCTRL || wxUSE_COMBOBOX