Windows QPA: Fix multi-touch support in some devices
Some multi-touch devices send touch information for each finger using different WM_POINTER messages/frames, instead of a single one with a list of touches, like most devices. This would result in the generation of multiple touch events, which can cause unexpected behavior in applications (the QTouchEvent documentation specifies that it should contain all simultaneous touches). This patch adds a workaround to ensure all simultaneous touches are included in the events, to comply with the expected behavior. Change-Id: I12a2f84b35a6bdd49ee53d25de580c0941a9aea6 Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io> Reviewed-by: Oliver Wolff <oliver.wolff@qt.io> (cherry picked from commit 8283df4d8cee7e80ce36e724ae0824fd1e00cb24) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
e1111f0e45
commit
52b7d0c0a2
@ -460,6 +460,8 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
|
||||
{
|
||||
Q_UNUSED(hwnd);
|
||||
|
||||
auto *touchInfo = static_cast<POINTER_TOUCH_INFO *>(vTouchInfo);
|
||||
|
||||
if (et & QtWindows::NonClientEventFlag)
|
||||
return false; // Let DefWindowProc() handle Non Client messages.
|
||||
|
||||
@ -469,10 +471,19 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
|
||||
if (msg.message == WM_POINTERCAPTURECHANGED) {
|
||||
QWindowSystemInterface::handleTouchCancelEvent(window, m_touchDevice.data(),
|
||||
QWindowsKeyMapper::queryKeyboardModifiers());
|
||||
m_lastTouchPositions.clear();
|
||||
m_lastTouchPoints.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (msg.message == WM_POINTERLEAVE) {
|
||||
for (quint32 i = 0; i < count; ++i) {
|
||||
const quint32 pointerId = touchInfo[i].pointerInfo.pointerId;
|
||||
int id = m_touchInputIDToTouchPointID.value(pointerId, -1);
|
||||
if (id != -1)
|
||||
m_lastTouchPoints.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
// Only handle down/up/update, ignore others like WM_POINTERENTER, WM_POINTERLEAVE, etc.
|
||||
if (msg.message > WM_POINTERUP)
|
||||
return false;
|
||||
@ -483,8 +494,6 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
|
||||
if (!screen)
|
||||
return false;
|
||||
|
||||
auto *touchInfo = static_cast<POINTER_TOUCH_INFO *>(vTouchInfo);
|
||||
|
||||
const QRect screenGeometry = screen->geometry();
|
||||
|
||||
QList<QWindowSystemInterface::TouchPoint> touchPoints;
|
||||
@ -496,6 +505,7 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
|
||||
<< " count=" << Qt::dec << count;
|
||||
|
||||
QEventPoint::States allStates;
|
||||
QSet<int> inputIds;
|
||||
|
||||
for (quint32 i = 0; i < count; ++i) {
|
||||
if (QWindowsContext::verbose > 1)
|
||||
@ -508,14 +518,17 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
|
||||
const quint32 pointerId = touchInfo[i].pointerInfo.pointerId;
|
||||
int id = m_touchInputIDToTouchPointID.value(pointerId, -1);
|
||||
if (id == -1) {
|
||||
// Start tracking after fingers touch the screen. Ignore bogus updates after touch is released.
|
||||
if ((touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_DOWN) == 0)
|
||||
continue;
|
||||
id = m_touchInputIDToTouchPointID.size();
|
||||
m_touchInputIDToTouchPointID.insert(pointerId, id);
|
||||
}
|
||||
touchPoint.id = id;
|
||||
touchPoint.pressure = (touchInfo[i].touchMask & TOUCH_MASK_PRESSURE) ?
|
||||
touchInfo[i].pressure / 1024.0 : 1.0;
|
||||
if (m_lastTouchPositions.contains(touchPoint.id))
|
||||
touchPoint.normalPosition = m_lastTouchPositions.value(touchPoint.id);
|
||||
if (m_lastTouchPoints.contains(touchPoint.id))
|
||||
touchPoint.normalPosition = m_lastTouchPoints.value(touchPoint.id).normalPosition;
|
||||
|
||||
const QPointF screenPos = QPointF(touchInfo[i].pointerInfo.ptPixelLocation.x,
|
||||
touchInfo[i].pointerInfo.ptPixelLocation.y);
|
||||
@ -531,22 +544,36 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
|
||||
|
||||
if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_DOWN) {
|
||||
touchPoint.state = QEventPoint::State::Pressed;
|
||||
m_lastTouchPositions.insert(touchPoint.id, touchPoint.normalPosition);
|
||||
m_lastTouchPoints.insert(touchPoint.id, touchPoint);
|
||||
} else if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_UP) {
|
||||
touchPoint.state = QEventPoint::State::Released;
|
||||
m_lastTouchPositions.remove(touchPoint.id);
|
||||
m_lastTouchPoints.remove(touchPoint.id);
|
||||
} else {
|
||||
touchPoint.state = stationaryTouchPoint ? QEventPoint::State::Stationary : QEventPoint::State::Updated;
|
||||
m_lastTouchPositions.insert(touchPoint.id, touchPoint.normalPosition);
|
||||
m_lastTouchPoints.insert(touchPoint.id, touchPoint);
|
||||
}
|
||||
allStates |= touchPoint.state;
|
||||
|
||||
touchPoints.append(touchPoint);
|
||||
inputIds.insert(touchPoint.id);
|
||||
|
||||
// Avoid getting repeated messages for this frame if there are multiple pointerIds
|
||||
QWindowsContext::user32dll.skipPointerFrameMessages(touchInfo[i].pointerInfo.pointerId);
|
||||
}
|
||||
|
||||
// Some devices send touches for each finger in a different message/frame, instead of consolidating
|
||||
// them in the same frame as we were expecting. We account for missing unreleased touches here.
|
||||
for (auto tp : qAsConst(m_lastTouchPoints)) {
|
||||
if (!inputIds.contains(tp.id)) {
|
||||
tp.state = QEventPoint::State::Stationary;
|
||||
allStates |= tp.state;
|
||||
touchPoints.append(tp);
|
||||
}
|
||||
}
|
||||
|
||||
if (touchPoints.count() == 0)
|
||||
return false;
|
||||
|
||||
// all touch points released, forget the ids we've seen.
|
||||
if (allStates == QEventPoint::State::Released)
|
||||
m_touchInputIDToTouchPointID.clear();
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include <QtCore/qsharedpointer.h>
|
||||
#include <QtCore/qhash.h>
|
||||
#include <QtGui/qevent.h>
|
||||
#include <qpa/qwindowsysteminterface.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -88,7 +89,7 @@ private:
|
||||
QList<QPointingDevicePtr> m_tabletDevices;
|
||||
QPointingDevicePtr m_activeTabletDevice;
|
||||
#endif
|
||||
QHash<int, QPointF> m_lastTouchPositions;
|
||||
QHash<int, QWindowSystemInterface::TouchPoint> m_lastTouchPoints;
|
||||
QHash<DWORD, int> m_touchInputIDToTouchPointID;
|
||||
QPointer<QWindow> m_windowUnderPointer;
|
||||
QPointer<QWindow> m_currentWindow;
|
||||
|
Loading…
x
Reference in New Issue
Block a user