summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/windows/qwindowspointerhandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/windows/qwindowspointerhandler.cpp')
-rw-r--r--src/plugins/platforms/windows/qwindowspointerhandler.cpp178
1 files changed, 82 insertions, 96 deletions
diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp
index 46fbfcc8d6..71c7217671 100644
--- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp
+++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp
@@ -1,48 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#if defined(WINVER) && WINVER < 0x0603
-# undef WINVER
-#endif
-#if !defined(WINVER)
-# define WINVER 0x0603 // Enable pointer functions for MinGW
-#endif
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtCore/qt_windows.h>
#include "qwindowspointerhandler.h"
#include "qwindowsmousehandler.h"
@@ -62,7 +21,6 @@
#include <QtGui/private/qguiapplication_p.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qloggingcategory.h>
-#include <QtCore/qoperatingsystemversion.h>
#include <QtCore/qqueue.h>
#include <algorithm>
@@ -90,7 +48,7 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q
*result = 0;
const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam);
- if (!QWindowsContext::user32dll.getPointerType(pointerId, &m_pointerType)) {
+ if (!GetPointerType(pointerId, &m_pointerType)) {
qWarning() << "GetPointerType() failed:" << qt_error_string();
return false;
}
@@ -104,12 +62,12 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q
}
case QT_PT_TOUCH: {
quint32 pointerCount = 0;
- if (!QWindowsContext::user32dll.getPointerFrameTouchInfo(pointerId, &pointerCount, nullptr)) {
+ if (!GetPointerFrameTouchInfo(pointerId, &pointerCount, nullptr)) {
qWarning() << "GetPointerFrameTouchInfo() failed:" << qt_error_string();
return false;
}
QVarLengthArray<POINTER_TOUCH_INFO, 10> touchInfo(pointerCount);
- if (!QWindowsContext::user32dll.getPointerFrameTouchInfo(pointerId, &pointerCount, touchInfo.data())) {
+ if (!GetPointerFrameTouchInfo(pointerId, &pointerCount, touchInfo.data())) {
qWarning() << "GetPointerFrameTouchInfo() failed:" << qt_error_string();
return false;
}
@@ -122,10 +80,10 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q
// dispatch any skipped frames if event compression is disabled by the app
if (historyCount > 1 && !QCoreApplication::testAttribute(Qt::AA_CompressHighFrequencyEvents)) {
touchInfo.resize(pointerCount * historyCount);
- if (!QWindowsContext::user32dll.getPointerFrameTouchInfoHistory(pointerId,
- &historyCount,
- &pointerCount,
- touchInfo.data())) {
+ if (!GetPointerFrameTouchInfoHistory(pointerId,
+ &historyCount,
+ &pointerCount,
+ touchInfo.data())) {
qWarning() << "GetPointerFrameTouchInfoHistory() failed:" << qt_error_string();
return false;
}
@@ -143,7 +101,7 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q
}
case QT_PT_PEN: {
POINTER_PEN_INFO penInfo;
- if (!QWindowsContext::user32dll.getPointerPenInfo(pointerId, &penInfo)) {
+ if (!GetPointerPenInfo(pointerId, &penInfo)) {
qWarning() << "GetPointerPenInfo() failed:" << qt_error_string();
return false;
}
@@ -155,9 +113,7 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q
|| !QCoreApplication::testAttribute(Qt::AA_CompressTabletEvents))) {
QVarLengthArray<POINTER_PEN_INFO, 10> penInfoHistory(historyCount);
- if (!QWindowsContext::user32dll.getPointerPenInfoHistory(pointerId,
- &historyCount,
- penInfoHistory.data())) {
+ if (!GetPointerPenInfoHistory(pointerId, &historyCount, penInfoHistory.data())) {
qWarning() << "GetPointerPenInfoHistory() failed:" << qt_error_string();
return false;
}
@@ -463,6 +419,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.
@@ -470,12 +428,24 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
return false;
if (msg.message == WM_POINTERCAPTURECHANGED) {
- QWindowSystemInterface::handleTouchCancelEvent(window, m_touchDevice.data(),
- QWindowsKeyMapper::queryKeyboardModifiers());
- m_lastTouchPositions.clear();
+ const auto *keyMapper = QWindowsContext::instance()->keyMapper();
+ QWindowSystemInterface::handleTouchCancelEvent(window, msg.time, m_touchDevice.data(),
+ keyMapper->queryKeyboardModifiers());
+ 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);
+ }
+ // Send LeaveEvent to reset hover when the last finger leaves the touch screen (QTBUG-62912)
+ QWindowSystemInterface::handleEnterLeaveEvent(nullptr, window);
+ }
+
// Only handle down/up/update, ignore others like WM_POINTERENTER, WM_POINTERLEAVE, etc.
if (msg.message > WM_POINTERUP)
return false;
@@ -486,8 +456,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;
@@ -499,6 +467,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)
@@ -511,14 +480,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);
@@ -534,28 +506,43 @@ 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);
+ 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 : std::as_const(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();
- QWindowSystemInterface::handleTouchEvent(window, m_touchDevice.data(), touchPoints,
- QWindowsKeyMapper::queryKeyboardModifiers());
+ const auto *keyMapper = QWindowsContext::instance()->keyMapper();
+ QWindowSystemInterface::handleTouchEvent(window, msg.time, m_touchDevice.data(), touchPoints,
+ keyMapper->queryKeyboardModifiers());
return false; // Allow mouse messages to be generated.
}
@@ -580,7 +567,7 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
auto *penInfo = static_cast<POINTER_PEN_INFO *>(vPenInfo);
RECT pRect, dRect;
- if (!QWindowsContext::user32dll.getPointerDeviceRects(penInfo->pointerInfo.sourceDevice, &pRect, &dRect))
+ if (!GetPointerDeviceRects(penInfo->pointerInfo.sourceDevice, &pRect, &dRect))
return false;
const auto systemId = (qint64)penInfo->pointerInfo.sourceDevice;
@@ -652,7 +639,7 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
switch (msg.message) {
case WM_POINTERENTER: {
- QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(window, device.data(), true);
+ QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(window, msg.time, device.data(), true);
m_windowUnderPointer = window;
// The local coordinates may fall outside the window.
// Wait until the next update to send the enter event.
@@ -665,7 +652,7 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
m_windowUnderPointer = nullptr;
m_currentWindow = nullptr;
}
- QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(window, device.data(), false);
+ QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(window, msg.time, device.data(), false);
break;
case WM_POINTERDOWN:
case WM_POINTERUP:
@@ -688,9 +675,10 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
wumPlatformWindow->applyCursor();
}
}
- const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
+ const auto *keyMapper = QWindowsContext::instance()->keyMapper();
+ const Qt::KeyboardModifiers keyModifiers = keyMapper->queryKeyboardModifiers();
- QWindowSystemInterface::handleTabletEvent(target, device.data(),
+ QWindowSystemInterface::handleTabletEvent(target, msg.time, device.data(),
localPos, hiResGlobalPos, mouseButtons,
pressure, xTilt, yTilt, tangentialPressure,
rotation, z, keyModifiers);
@@ -741,7 +729,7 @@ bool QWindowsPointerHandler::translateMouseWheelEvent(QWindow *window,
QPoint localPos = QWindowsGeometryHint::mapFromGlobal(receiver, globalPos);
- QWindowSystemInterface::handleWheelEvent(receiver, localPos, globalPos, QPoint(), angleDelta, keyModifiers);
+ QWindowSystemInterface::handleWheelEvent(receiver, msg.time, localPos, globalPos, QPoint(), angleDelta, keyModifiers);
return true;
}
@@ -754,20 +742,20 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
{
*result = 0;
- QPoint eventPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
- if ((et & QtWindows::NonClientEventFlag) == 0 && QWindowsBaseWindow::isRtlLayout(hwnd)) {
- RECT clientArea;
- GetClientRect(hwnd, &clientArea);
- eventPos.setX(clientArea.right - eventPos.x());
- }
-
QPoint localPos;
QPoint globalPos;
+ QPoint eventPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
if ((et == QtWindows::MouseWheelEvent) || (et & QtWindows::NonClientEventFlag)) {
globalPos = eventPos;
localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, eventPos);
} else {
+ if (QWindowsBaseWindow::isRtlLayout(hwnd)) {
+ RECT clientArea;
+ GetClientRect(hwnd, &clientArea);
+ eventPos.setX(clientArea.right - eventPos.x());
+ }
+
globalPos = QWindowsGeometryHint::mapToGlobal(hwnd, eventPos);
auto targetHwnd = hwnd;
if (auto *pw = window->handle())
@@ -777,7 +765,8 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
: QWindowsGeometryHint::mapFromGlobal(targetHwnd, globalPos);
}
- const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
+ const auto *keyMapper = QWindowsContext::instance()->keyMapper();
+ const Qt::KeyboardModifiers keyModifiers = keyMapper->queryKeyboardModifiers();
QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos);
if (et == QtWindows::MouseWheelEvent)
@@ -789,7 +778,7 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
// X11 and macOS.
bool discardEvent = false;
if (msg.message == WM_MOUSEMOVE) {
- static QPoint lastMouseMovePos;
+ Q_CONSTINIT static QPoint lastMouseMovePos;
if (msg.wParam == 0 && (m_windowUnderPointer.isNull() || globalPos == lastMouseMovePos))
discardEvent = true;
lastMouseMovePos = globalPos;
@@ -813,8 +802,8 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
break;
case QT_PT_PEN:
#if QT_CONFIG(tabletevent)
- if (!m_activeTabletDevice.isNull())
- device = m_activeTabletDevice.data();
+ qCDebug(lcQpaTablet) << "ignoring synth-mouse event for tablet event from" << device;
+ return false;
#endif
break;
}
@@ -837,19 +826,16 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
if (m_lastEventType == QEvent::NonClientAreaMouseButtonPress
&& (mouseEvent.type == QEvent::NonClientAreaMouseMove || mouseEvent.type == QEvent::MouseMove)
&& (m_lastEventButton & mouseButtons) == 0) {
- if (mouseEvent.type == QEvent::NonClientAreaMouseMove) {
- QWindowSystemInterface::handleFrameStrutMouseEvent(window, device, localPos, globalPos, mouseButtons, m_lastEventButton,
- QEvent::NonClientAreaMouseButtonRelease, keyModifiers, source);
- } else {
- QWindowSystemInterface::handleMouseEvent(window, device, localPos, globalPos, mouseButtons, m_lastEventButton,
- QEvent::MouseButtonRelease, keyModifiers, source);
- }
+ auto releaseType = mouseEvent.type == QEvent::NonClientAreaMouseMove ?
+ QEvent::NonClientAreaMouseButtonRelease : QEvent::MouseButtonRelease;
+ QWindowSystemInterface::handleMouseEvent(window, msg.time, device, localPos, globalPos, mouseButtons, m_lastEventButton,
+ releaseType, keyModifiers, source);
}
m_lastEventType = mouseEvent.type;
m_lastEventButton = mouseEvent.button;
if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) {
- QWindowSystemInterface::handleFrameStrutMouseEvent(window, device, localPos, globalPos, mouseButtons,
+ QWindowSystemInterface::handleMouseEvent(window, msg.time, device, localPos, globalPos, mouseButtons,
mouseEvent.button, mouseEvent.type, keyModifiers, source);
return false; // Allow further event processing
}
@@ -869,7 +855,7 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
handleEnterLeave(window, currentWindowUnderPointer, globalPos);
if (!discardEvent && mouseEvent.type != QEvent::None) {
- QWindowSystemInterface::handleMouseEvent(window, device, localPos, globalPos, mouseButtons,
+ QWindowSystemInterface::handleMouseEvent(window, msg.time, device, localPos, globalPos, mouseButtons,
mouseEvent.button, mouseEvent.type, keyModifiers, source);
}