Accept concurrent input from multiple tablet devices in QGuiApplication

As a follow-up to 352c357e6f enabling
support for multiple evdevtablet plugins at runtime (one per device),
we also need to adjust the way QGuiApplication handles the events
received from those plugins, in particular when multiple devices
are sending tablet events concurrently.

Replace the static members in QGuiApplication by a vector storing
the same data per-device, so tablet press/release events can be
recognized independently.

Change-Id: Ie0975cdb03a8f6d05903e2e2e57ceb9de73a74a4
Reviewed-by: Jake Petroules <jake.petroules@theqtcompany.com>
This commit is contained in:
Romain Pokrzywka 2015-09-17 13:33:46 -07:00 committed by Romain Pokrzywka
parent 50cd0daf29
commit 8d6fe1a371
4 changed files with 44 additions and 18 deletions

View File

@ -124,8 +124,6 @@ Qt::KeyboardModifiers QGuiApplicationPrivate::modifier_buttons = Qt::NoModifier;
QPointF QGuiApplicationPrivate::lastCursorPosition(qInf(), qInf()); QPointF QGuiApplicationPrivate::lastCursorPosition(qInf(), qInf());
Qt::MouseButtons QGuiApplicationPrivate::tabletState = Qt::NoButton;
QWindow *QGuiApplicationPrivate::tabletPressTarget = 0;
QWindow *QGuiApplicationPrivate::currentMouseWindow = 0; QWindow *QGuiApplicationPrivate::currentMouseWindow = 0;
QString QGuiApplicationPrivate::styleOverride; QString QGuiApplicationPrivate::styleOverride;
@ -134,6 +132,8 @@ Qt::ApplicationState QGuiApplicationPrivate::applicationState = Qt::ApplicationI
bool QGuiApplicationPrivate::highDpiScalingUpdated = false; bool QGuiApplicationPrivate::highDpiScalingUpdated = false;
QVector<QGuiApplicationPrivate::TabletPointData> QGuiApplicationPrivate::tabletDevicePoints;
QPlatformIntegration *QGuiApplicationPrivate::platform_integration = 0; QPlatformIntegration *QGuiApplicationPrivate::platform_integration = 0;
QPlatformTheme *QGuiApplicationPrivate::platform_theme = 0; QPlatformTheme *QGuiApplicationPrivate::platform_theme = 0;
@ -2198,12 +2198,26 @@ void QGuiApplicationPrivate::processFileOpenEvent(QWindowSystemInterfacePrivate:
QGuiApplication::sendSpontaneousEvent(qApp, &event); QGuiApplication::sendSpontaneousEvent(qApp, &event);
} }
QGuiApplicationPrivate::TabletPointData &QGuiApplicationPrivate::tabletDevicePoint(qint64 deviceId)
{
for (int i = 0; i < tabletDevicePoints.size(); ++i) {
TabletPointData &pointData = tabletDevicePoints[i];
if (pointData.deviceId == deviceId)
return pointData;
}
tabletDevicePoints.append(TabletPointData(deviceId));
return tabletDevicePoints.last();
}
void QGuiApplicationPrivate::processTabletEvent(QWindowSystemInterfacePrivate::TabletEvent *e) void QGuiApplicationPrivate::processTabletEvent(QWindowSystemInterfacePrivate::TabletEvent *e)
{ {
#ifndef QT_NO_TABLETEVENT #ifndef QT_NO_TABLETEVENT
TabletPointData &pointData = tabletDevicePoint(e->uid);
QEvent::Type type = QEvent::TabletMove; QEvent::Type type = QEvent::TabletMove;
if (e->buttons != tabletState) if (e->buttons != pointData.state)
type = (e->buttons > tabletState) ? QEvent::TabletPress : QEvent::TabletRelease; type = (e->buttons > pointData.state) ? QEvent::TabletPress : QEvent::TabletRelease;
QWindow *window = e->window.data(); QWindow *window = e->window.data();
modifier_buttons = e->modifiers; modifier_buttons = e->modifiers;
@ -2219,14 +2233,14 @@ void QGuiApplicationPrivate::processTabletEvent(QWindowSystemInterfacePrivate::T
} }
if (!window) if (!window)
return; return;
tabletPressTarget = window; pointData.target = window;
} else { } else {
if (e->nullWindow()) { if (e->nullWindow()) {
window = tabletPressTarget; window = pointData.target;
localValid = false; localValid = false;
} }
if (type == QEvent::TabletRelease) if (type == QEvent::TabletRelease)
tabletPressTarget = 0; pointData.target = Q_NULLPTR;
if (!window) if (!window)
return; return;
} }
@ -2235,7 +2249,7 @@ void QGuiApplicationPrivate::processTabletEvent(QWindowSystemInterfacePrivate::T
QPointF delta = e->global - e->global.toPoint(); QPointF delta = e->global - e->global.toPoint();
local = window->mapFromGlobal(e->global.toPoint()) + delta; local = window->mapFromGlobal(e->global.toPoint()) + delta;
} }
Qt::MouseButtons stateChange = e->buttons ^ tabletState; Qt::MouseButtons stateChange = e->buttons ^ pointData.state;
Qt::MouseButton button = Qt::NoButton; Qt::MouseButton button = Qt::NoButton;
for (int check = Qt::LeftButton; check <= int(Qt::MaxMouseButton); check = check << 1) { for (int check = Qt::LeftButton; check <= int(Qt::MaxMouseButton); check = check << 1) {
if (check & stateChange) { if (check & stateChange) {
@ -2249,7 +2263,7 @@ void QGuiApplicationPrivate::processTabletEvent(QWindowSystemInterfacePrivate::T
e->modifiers, e->uid, button, e->buttons); e->modifiers, e->uid, button, e->buttons);
ev.setTimestamp(e->timestamp); ev.setTimestamp(e->timestamp);
QGuiApplication::sendSpontaneousEvent(window, &ev); QGuiApplication::sendSpontaneousEvent(window, &ev);
tabletState = e->buttons; pointData.state = e->buttons;
#else #else
Q_UNUSED(e) Q_UNUSED(e)
#endif #endif
@ -2261,7 +2275,7 @@ void QGuiApplicationPrivate::processTabletEnterProximityEvent(QWindowSystemInter
QTabletEvent ev(QEvent::TabletEnterProximity, QPointF(), QPointF(), QTabletEvent ev(QEvent::TabletEnterProximity, QPointF(), QPointF(),
e->device, e->pointerType, 0, 0, 0, e->device, e->pointerType, 0, 0, 0,
0, 0, 0, 0, 0, 0,
Qt::NoModifier, e->uid, Qt::NoButton, tabletState); Qt::NoModifier, e->uid, Qt::NoButton, tabletDevicePoint(e->uid).state);
ev.setTimestamp(e->timestamp); ev.setTimestamp(e->timestamp);
QGuiApplication::sendSpontaneousEvent(qGuiApp, &ev); QGuiApplication::sendSpontaneousEvent(qGuiApp, &ev);
#else #else
@ -2275,7 +2289,7 @@ void QGuiApplicationPrivate::processTabletLeaveProximityEvent(QWindowSystemInter
QTabletEvent ev(QEvent::TabletLeaveProximity, QPointF(), QPointF(), QTabletEvent ev(QEvent::TabletLeaveProximity, QPointF(), QPointF(),
e->device, e->pointerType, 0, 0, 0, e->device, e->pointerType, 0, 0, 0,
0, 0, 0, 0, 0, 0,
Qt::NoModifier, e->uid, Qt::NoButton, tabletState); Qt::NoModifier, e->uid, Qt::NoButton, tabletDevicePoint(e->uid).state);
ev.setTimestamp(e->timestamp); ev.setTimestamp(e->timestamp);
QGuiApplication::sendSpontaneousEvent(qGuiApp, &ev); QGuiApplication::sendSpontaneousEvent(qGuiApp, &ev);
#else #else

View File

@ -198,13 +198,20 @@ public:
static int mousePressY; static int mousePressY;
static int mouse_double_click_distance; static int mouse_double_click_distance;
static QPointF lastCursorPosition; static QPointF lastCursorPosition;
static Qt::MouseButtons tabletState;
static QWindow *tabletPressTarget;
static QWindow *currentMouseWindow; static QWindow *currentMouseWindow;
static QWindow *currentMousePressWindow; static QWindow *currentMousePressWindow;
static Qt::ApplicationState applicationState; static Qt::ApplicationState applicationState;
static bool highDpiScalingUpdated; static bool highDpiScalingUpdated;
struct TabletPointData {
TabletPointData(qint64 devId = 0) : deviceId(devId), state(Qt::NoButton), target(Q_NULLPTR) {}
qint64 deviceId;
Qt::MouseButtons state;
QWindow *target;
};
static QVector<TabletPointData> tabletDevicePoints;
static TabletPointData &tabletDevicePoint(qint64 deviceId);
#ifndef QT_NO_CLIPBOARD #ifndef QT_NO_CLIPBOARD
static QClipboard *qt_clipboard; static QClipboard *qt_clipboard;
#endif #endif

View File

@ -1680,8 +1680,12 @@ void QWindow::destroy()
QGuiApplicationPrivate::currentMouseWindow = parent(); QGuiApplicationPrivate::currentMouseWindow = parent();
if (QGuiApplicationPrivate::currentMousePressWindow == this) if (QGuiApplicationPrivate::currentMousePressWindow == this)
QGuiApplicationPrivate::currentMousePressWindow = parent(); QGuiApplicationPrivate::currentMousePressWindow = parent();
if (QGuiApplicationPrivate::tabletPressTarget == this)
QGuiApplicationPrivate::tabletPressTarget = parent(); for (int i = 0; i < QGuiApplicationPrivate::tabletDevicePoints.size(); ++i) {
QGuiApplicationPrivate::TabletPointData &pointData = QGuiApplicationPrivate::tabletDevicePoints[i];
if (pointData.target == this)
pointData.target = parent();
}
bool wasVisible = isVisible(); bool wasVisible = isVisible();
d->visibilityOnDestroy = wasVisible && d->platformWindow; d->visibilityOnDestroy = wasVisible && d->platformWindow;

View File

@ -391,6 +391,7 @@ bool QWindowsTabletSupport::translateTabletPacketEvent()
const int currentDevice = m_devices.at(m_currentDevice).currentDevice; const int currentDevice = m_devices.at(m_currentDevice).currentDevice;
const int currentPointer = m_devices.at(m_currentDevice).currentPointerType; const int currentPointer = m_devices.at(m_currentDevice).currentPointerType;
const qint64 uniqueId = m_devices.at(m_currentDevice).uniqueId;
// The tablet can be used in 2 different modes, depending on it settings: // The tablet can be used in 2 different modes, depending on it settings:
// 1) Absolute (pen) mode: // 1) Absolute (pen) mode:
@ -407,7 +408,7 @@ bool QWindowsTabletSupport::translateTabletPacketEvent()
const QRect virtualDesktopArea = QGuiApplication::primaryScreen()->virtualGeometry(); const QRect virtualDesktopArea = QGuiApplication::primaryScreen()->virtualGeometry();
qCDebug(lcQpaTablet) << __FUNCTION__ << "processing " << packetCount qCDebug(lcQpaTablet) << __FUNCTION__ << "processing " << packetCount
<< "target:" << QGuiApplicationPrivate::tabletPressTarget; << "target:" << QGuiApplicationPrivate::tabletDevicePoint(uniqueId).target;
const Qt::KeyboardModifiers keyboardModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); const Qt::KeyboardModifiers keyboardModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
@ -420,7 +421,7 @@ bool QWindowsTabletSupport::translateTabletPacketEvent()
QPointF globalPosF = m_oldGlobalPosF; QPointF globalPosF = m_oldGlobalPosF;
m_oldGlobalPosF = m_devices.at(m_currentDevice).scaleCoordinates(packet.pkX, packet.pkY, virtualDesktopArea); m_oldGlobalPosF = m_devices.at(m_currentDevice).scaleCoordinates(packet.pkX, packet.pkY, virtualDesktopArea);
QWindow *target = QGuiApplicationPrivate::tabletPressTarget; // Pass to window that grabbed it. QWindow *target = QGuiApplicationPrivate::tabletDevicePoint(uniqueId).target; // Pass to window that grabbed it.
QPoint globalPos = globalPosF.toPoint(); QPoint globalPos = globalPosF.toPoint();
// Get Mouse Position and compare to tablet info // Get Mouse Position and compare to tablet info
@ -484,7 +485,7 @@ bool QWindowsTabletSupport::translateTabletPacketEvent()
static_cast<Qt::MouseButtons>(packet.pkButtons), static_cast<Qt::MouseButtons>(packet.pkButtons),
pressureNew, tiltX, tiltY, pressureNew, tiltX, tiltY,
tangentialPressure, rotation, z, tangentialPressure, rotation, z,
m_devices.at(m_currentDevice).uniqueId, uniqueId,
keyboardModifiers); keyboardModifiers);
} }
return true; return true;