Windows QPA/WmPointer: Register tablet devices of pointer handler

Task-number: QTBUG-46412
Change-Id: Ib9b5fd6056a5474ce46c7bde53be7a12c1494611
Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
bb10
Friedemann Kleint 2020-10-16 11:26:54 +02:00
parent abb5f0d376
commit 8ba59441fc
2 changed files with 64 additions and 13 deletions

View File

@ -45,6 +45,9 @@
#endif
#include "qwindowspointerhandler.h"
#if QT_CONFIG(tabletevent)
# include "qwindowstabletsupport.h"
#endif
#include "qwindowskeymapper.h"
#include "qwindowscontext.h"
#include "qwindowswindow.h"
@ -552,6 +555,17 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
return false; // Allow mouse messages to be generated.
}
#if QT_CONFIG(tabletevent)
QWindowsPointerHandler::QPointingDevicePtr QWindowsPointerHandler::findTabletDevice(QPointingDevice::PointerType pointerType) const
{
for (const auto &d : m_tabletDevices) {
if (d->pointerType() == pointerType)
return d;
}
return {};
}
#endif
bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et,
MSG msg, PVOID vPenInfo)
{
@ -565,28 +579,31 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
if (!QWindowsContext::user32dll.getPointerDeviceRects(penInfo->pointerInfo.sourceDevice, &pRect, &dRect))
return false;
const auto sourceDevice = (qint64)penInfo->pointerInfo.sourceDevice;
const auto systemId = (qint64)penInfo->pointerInfo.sourceDevice;
const QPoint globalPos = QPoint(penInfo->pointerInfo.ptPixelLocation.x, penInfo->pointerInfo.ptPixelLocation.y);
const QPoint localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPos);
const QPointF hiResGlobalPos = QPointF(dRect.left + qreal(penInfo->pointerInfo.ptHimetricLocation.x - pRect.left)
/ (pRect.right - pRect.left) * (dRect.right - dRect.left),
dRect.top + qreal(penInfo->pointerInfo.ptHimetricLocation.y - pRect.top)
/ (pRect.bottom - pRect.top) * (dRect.bottom - dRect.top));
const qreal pressure = (penInfo->penMask & PEN_MASK_PRESSURE) ? qreal(penInfo->pressure) / 1024.0 : 0.5;
const qreal rotation = (penInfo->penMask & PEN_MASK_ROTATION) ? qreal(penInfo->rotation) : 0.0;
const bool hasPressure = (penInfo->penMask & PEN_MASK_PRESSURE) != 0;
const bool hasRotation = (penInfo->penMask & PEN_MASK_ROTATION) != 0;
const qreal pressure = hasPressure ? qreal(penInfo->pressure) / 1024.0 : 0.5;
const qreal rotation = hasRotation ? qreal(penInfo->rotation) : 0.0;
const qreal tangentialPressure = 0.0;
const int xTilt = (penInfo->penMask & PEN_MASK_TILT_X) ? penInfo->tiltX : 0;
const int yTilt = (penInfo->penMask & PEN_MASK_TILT_Y) ? penInfo->tiltY : 0;
const bool hasTiltX = (penInfo->penMask & PEN_MASK_TILT_X) != 0;
const bool hasTiltY = (penInfo->penMask & PEN_MASK_TILT_Y) != 0;
const int xTilt = hasTiltX ? penInfo->tiltX : 0;
const int yTilt = hasTiltY ? penInfo->tiltY : 0;
const int z = 0;
if (QWindowsContext::verbose > 1)
qCDebug(lcQpaEvents).noquote().nospace() << Qt::showbase
<< __FUNCTION__ << " sourceDevice=" << sourceDevice
<< __FUNCTION__ << " systemId=" << systemId
<< " globalPos=" << globalPos << " localPos=" << localPos << " hiResGlobalPos=" << hiResGlobalPos
<< " message=" << Qt::hex << msg.message
<< " flags=" << Qt::hex << penInfo->pointerInfo.pointerFlags;
const QInputDevice::DeviceType device = QInputDevice::DeviceType::Stylus;
QPointingDevice::PointerType type;
// Since it may be the middle button, so if the checks fail then it should
// be set to Middle if it was used.
@ -604,9 +621,33 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
mouseButtons = Qt::RightButton; // Either left or right, not both
}
auto device = findTabletDevice(type);
if (device.isNull()) {
QInputDevice::Capabilities caps(QInputDevice::Capability::Position
| QInputDevice::Capability::MouseEmulation
| QInputDevice::Capability::Hover);
if (hasPressure)
caps |= QInputDevice::Capability::Pressure;
if (hasRotation)
caps |= QInputDevice::Capability::Rotation;
if (hasTiltX)
caps |= QInputDevice::Capability::XTilt;
if (hasTiltY)
caps |= QInputDevice::Capability::YTilt;
const qint64 uniqueId = systemId | (qint64(type) << 32L);
device.reset(new QPointingDevice(QStringLiteral("wmpointer"),
systemId, QInputDevice::DeviceType::Stylus,
type, caps, 1, 3, QString(),
QPointingDeviceUniqueId::fromNumericId(uniqueId)));
QWindowSystemInterface::registerInputDevice(device.data());
m_tabletDevices.append(device);
}
const auto uniqueId = device->uniqueId().numericId();
switch (msg.message) {
case WM_POINTERENTER: {
QWindowSystemInterface::handleTabletEnterProximityEvent(int(device), int(type), sourceDevice);
QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(window, device.data(), true);
m_windowUnderPointer = window;
// The local coordinates may fall outside the window.
// Wait until the next update to send the enter event.
@ -619,12 +660,12 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
m_windowUnderPointer = nullptr;
m_currentWindow = nullptr;
}
QWindowSystemInterface::handleTabletLeaveProximityEvent(int(device), int(type), sourceDevice);
QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(window, device.data(), false);
break;
case WM_POINTERDOWN:
case WM_POINTERUP:
case WM_POINTERUPDATE: {
QWindow *target = QGuiApplicationPrivate::tabletDevicePoint(sourceDevice).target; // Pass to window that grabbed it.
QWindow *target = QGuiApplicationPrivate::tabletDevicePoint(uniqueId).target; // Pass to window that grabbed it.
if (!target && m_windowUnderPointer)
target = m_windowUnderPointer;
if (!target)
@ -644,9 +685,10 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
}
const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
QWindowSystemInterface::handleTabletEvent(target, localPos, hiResGlobalPos, int(device), int(type), mouseButtons,
pressure, xTilt, yTilt, tangentialPressure, rotation, z,
sourceDevice, keyModifiers);
QWindowSystemInterface::handleTabletEvent(target, device.data(),
localPos, hiResGlobalPos, mouseButtons,
pressure, xTilt, yTilt, tangentialPressure,
rotation, z, keyModifiers);
return false; // Allow mouse messages to be generated.
}
}

View File

@ -45,6 +45,7 @@
#include <QtCore/qpointer.h>
#include <QtCore/qscopedpointer.h>
#include <QtCore/qsharedpointer.h>
#include <QtCore/qhash.h>
#include <QtGui/qevent.h>
@ -57,6 +58,8 @@ class QWindowsPointerHandler
{
Q_DISABLE_COPY_MOVE(QWindowsPointerHandler)
public:
using QPointingDevicePtr = QSharedPointer<QPointingDevice>;
QWindowsPointerHandler() = default;
~QWindowsPointerHandler();
bool translatePointerEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result);
@ -76,8 +79,14 @@ private:
bool translateMouseWheelEvent(QWindow *window, QWindow *currentWindowUnderPointer, MSG msg, QPoint globalPos, Qt::KeyboardModifiers keyModifiers);
void handleCaptureRelease(QWindow *window, QWindow *currentWindowUnderPointer, HWND hwnd, QEvent::Type eventType, Qt::MouseButtons mouseButtons);
void handleEnterLeave(QWindow *window, QWindow *currentWindowUnderPointer, QPoint globalPos);
#if QT_CONFIG(tabletevent)
QPointingDevicePtr findTabletDevice(QPointingDevice::PointerType pointerType) const;
#endif
QPointingDevice *m_touchDevice = nullptr;
#if QT_CONFIG(tabletevent)
QList<QPointingDevicePtr> m_tabletDevices;
#endif
QHash<int, QPointF> m_lastTouchPositions;
QHash<DWORD, int> m_touchInputIDToTouchPointID;
QPointer<QWindow> m_windowUnderPointer;