Windows QPA: Fix multiple mouse button presses detection

The detection of multiple mouse button presses was broken in the new
WM_POINTER-based implementation. The bug was due to the incorrect
assumption that the press/release of a second mouse button (while
another one is held) would also send WM_POINTERDOWN/WM_POINTERUP, while
in fact it sends a WM_POINTERUPDATE with the actual event type given
by pointerInfo->ButtonChangeType.

Task-number: QTBUG-70787
Change-Id: Ib6776ab7f3d0b8eb5e832a0c863a15bde456e0dd
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
This commit is contained in:
Andre de la Rocha 2018-10-02 09:19:19 +02:00
parent 18be2337ea
commit 4840668994

View File

@ -61,6 +61,8 @@
#include <QtCore/qloggingcategory.h> #include <QtCore/qloggingcategory.h>
#include <QtCore/qoperatingsystemversion.h> #include <QtCore/qoperatingsystemversion.h>
#include <algorithm>
#include <windowsx.h> #include <windowsx.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -184,41 +186,65 @@ static void getMouseEventInfo(UINT message, POINTER_BUTTON_CHANGE_TYPE changeTyp
{POINTER_CHANGE_FIFTHBUTTON_UP, Qt::XButton2}, {POINTER_CHANGE_FIFTHBUTTON_UP, Qt::XButton2},
}; };
static const QHash<UINT, QEvent::Type> eventMapping { static const POINTER_BUTTON_CHANGE_TYPE downChanges[] = {
{WM_POINTERUPDATE, QEvent::MouseMove}, POINTER_CHANGE_FIRSTBUTTON_DOWN,
{WM_POINTERDOWN, QEvent::MouseButtonPress}, POINTER_CHANGE_SECONDBUTTON_DOWN,
{WM_POINTERUP, QEvent::MouseButtonRelease}, POINTER_CHANGE_THIRDBUTTON_DOWN,
{WM_NCPOINTERUPDATE, QEvent::NonClientAreaMouseMove}, POINTER_CHANGE_FOURTHBUTTON_DOWN,
{WM_NCPOINTERDOWN, QEvent::NonClientAreaMouseButtonPress}, POINTER_CHANGE_FIFTHBUTTON_DOWN,
{WM_NCPOINTERUP, QEvent::NonClientAreaMouseButtonRelease}, };
{WM_POINTERWHEEL, QEvent::Wheel},
{WM_POINTERHWHEEL, QEvent::Wheel}, static const POINTER_BUTTON_CHANGE_TYPE upChanges[] = {
POINTER_CHANGE_FIRSTBUTTON_UP,
POINTER_CHANGE_SECONDBUTTON_UP,
POINTER_CHANGE_THIRDBUTTON_UP,
POINTER_CHANGE_FOURTHBUTTON_UP,
POINTER_CHANGE_FIFTHBUTTON_UP,
}; };
if (!eventType || !mouseButton) if (!eventType || !mouseButton)
return; return;
if (message == WM_POINTERDOWN || message == WM_POINTERUP || message == WM_NCPOINTERDOWN || message == WM_NCPOINTERUP) const bool nonClient = message == WM_NCPOINTERUPDATE ||
*mouseButton = buttonMapping.value(changeType, Qt::NoButton); message == WM_NCPOINTERDOWN ||
else message == WM_NCPOINTERUP;
*mouseButton = Qt::NoButton;
*eventType = eventMapping.value(message, QEvent::None); if (std::find(std::begin(downChanges),
std::end(downChanges), changeType) < std::end(downChanges)) {
*eventType = nonClient ? QEvent::NonClientAreaMouseButtonPress :
QEvent::MouseButtonPress;
} else if (std::find(std::begin(upChanges),
std::end(upChanges), changeType) < std::end(upChanges)) {
*eventType = nonClient ? QEvent::NonClientAreaMouseButtonRelease :
QEvent::MouseButtonRelease;
} else if (message == WM_POINTERWHEEL || message == WM_POINTERHWHEEL) {
*eventType = QEvent::Wheel;
} else {
*eventType = nonClient ? QEvent::NonClientAreaMouseMove :
QEvent::MouseMove;
}
*mouseButton = buttonMapping.value(changeType, Qt::NoButton);
// Pointer messages lack a double click indicator. Check if this is the case here. // Pointer messages lack a double click indicator. Check if this is the case here.
if (message == WM_POINTERDOWN) { if (*eventType == QEvent::MouseButtonPress ||
*eventType == QEvent::NonClientAreaMouseButtonPress) {
static LONG lastTime = 0; static LONG lastTime = 0;
static Qt::MouseButton lastButton = Qt::NoButton; static Qt::MouseButton lastButton = Qt::NoButton;
static QEvent::Type lastEvent = QEvent::None;
static QPoint lastPos; static QPoint lastPos;
LONG messageTime = GetMessageTime(); LONG messageTime = GetMessageTime();
if (*mouseButton == lastButton if (*mouseButton == lastButton
&& *eventType == lastEvent
&& messageTime - lastTime < (LONG)GetDoubleClickTime() && messageTime - lastTime < (LONG)GetDoubleClickTime()
&& qAbs(globalPos.x() - lastPos.x()) < GetSystemMetrics(SM_CXDOUBLECLK) && qAbs(globalPos.x() - lastPos.x()) < GetSystemMetrics(SM_CXDOUBLECLK)
&& qAbs(globalPos.y() - lastPos.y()) < GetSystemMetrics(SM_CYDOUBLECLK)) { && qAbs(globalPos.y() - lastPos.y()) < GetSystemMetrics(SM_CYDOUBLECLK)) {
*eventType = QEvent::MouseButtonDblClick; *eventType = nonClient ? QEvent::NonClientAreaMouseButtonDblClick :
QEvent::MouseButtonDblClick;
} }
lastTime = messageTime; lastTime = messageTime;
lastButton = *mouseButton; lastButton = *mouseButton;
lastEvent = *eventType;
lastPos = globalPos; lastPos = globalPos;
} }
} }