Merge branch 'msw-combo-keys'

Fix behaviour of comboboxes in presence of accelerators in wxMSW.

See https://github.com/wxWidgets/wxWidgets/pull/2443
This commit is contained in:
Vadim Zeitlin
2021-08-06 20:29:20 +01:00
5 changed files with 114 additions and 97 deletions

View File

@@ -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();

View File

@@ -121,21 +121,32 @@ bool wxChoice::Create(wxWindow *parent,
style, validator, name);
}
bool wxChoice::MSWShouldPreProcessMessage(WXMSG *pMsg)
bool wxChoice::MSWShouldPreProcessMessage(WXMSG *msg)
{
MSG *msg = (MSG *) pMsg;
// if the dropdown list is visible, don't preprocess certain keys
if ( msg->message == WM_KEYDOWN
&& (msg->wParam == VK_ESCAPE || msg->wParam == VK_RETURN) )
if ( msg->message == WM_KEYDOWN &&
!(HIWORD(msg->lParam) & KF_ALTDOWN) &&
!wxIsShiftDown() &&
!wxIsCtrlDown() )
{
if (::SendMessage(GetHwndOf(this), CB_GETDROPPEDSTATE, 0, 0))
switch ( msg->wParam )
{
return false;
case VK_ESCAPE:
case VK_RETURN:
// These keys are needed by the control itself when the
// dropdown list is visible, so don't preprocess them then.
if (::SendMessage(GetHwndOf(this), CB_GETDROPPEDSTATE, 0, 0))
{
return false;
}
break;
case VK_F4:
// This key can always be used to show the dropdown.
return false;
}
}
return wxControl::MSWShouldPreProcessMessage(pMsg);
return wxControl::MSWShouldPreProcessMessage(msg);
}
WXDWORD wxChoice::MSWGetStyle(long style, WXDWORD *exstyle) const

View File

@@ -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

View File

@@ -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)

View File

@@ -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