From ec8654a61e574539f1b948b82a19371b160f4f4e Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Thu, 28 May 2009 12:25:32 +0200 Subject: Refactor the touch event dispatching code in preparation for allowing external event generators This introduces QEvent::RawTouch event type, which should be used by the low-level translator. This raw QTouchEvent can be sent to either QApplication or to a window, and Qt will do the rest to dispatch the touch points to the correct place. --- src/corelib/kernel/qcoreevent.cpp | 1 + src/corelib/kernel/qcoreevent.h | 20 ++-- src/gui/kernel/qapplication.cpp | 179 ++++++++++++++++++++++++++++++++++++ src/gui/kernel/qapplication_mac.mm | 5 + src/gui/kernel/qapplication_p.h | 15 +-- src/gui/kernel/qapplication_qws.cpp | 5 + src/gui/kernel/qapplication_win.cpp | 145 +++-------------------------- src/gui/kernel/qapplication_x11.cpp | 5 + 8 files changed, 230 insertions(+), 145 deletions(-) diff --git a/src/corelib/kernel/qcoreevent.cpp b/src/corelib/kernel/qcoreevent.cpp index 77679dc..d28d34e 100644 --- a/src/corelib/kernel/qcoreevent.cpp +++ b/src/corelib/kernel/qcoreevent.cpp @@ -222,6 +222,7 @@ QT_BEGIN_NAMESPACE \value ZOrderChange The widget's z-order has changed. This event is never sent to top level windows. \value KeyboardLayoutChange The keyboard layout has changed. \value DynamicPropertyChange A dynamic property was added, changed or removed from the object. + \value RawTouch A raw event from a touch-screen or track-pad device (QTouchEvent) \value TouchBegin Beginning of a sequence of touch-screen and/or track-pad events (QTouchEvent) \value TouchUpdate Touch-screen event (QTouchEvent) \value TouchEnd End of touch-event sequence (QTouchEvent) diff --git a/src/corelib/kernel/qcoreevent.h b/src/corelib/kernel/qcoreevent.h index feefd08..3381a31 100644 --- a/src/corelib/kernel/qcoreevent.h +++ b/src/corelib/kernel/qcoreevent.h @@ -272,15 +272,17 @@ public: Signal = 192, Wrapped = 193, - TouchBegin = 194, - TouchUpdate = 195, - TouchEnd = 196, - GraphicsSceneTouchBegin = 197, - GraphicsSceneTouchUpdate = 198, - GraphicsSceneTouchEnd = 199, - - Gesture = 200, - GraphicsSceneGesture = 201, + RawTouch = 194, + + TouchBegin = 195, + TouchUpdate = 196, + TouchEnd = 197, + GraphicsSceneTouchBegin = 198, + GraphicsSceneTouchUpdate = 199, + GraphicsSceneTouchEnd = 200, + + Gesture = 201, + GraphicsSceneGesture = 202, // 512 reserved for Qt Jambi's MetaCall event // 513 reserved for Qt Jambi's DeleteOnMainThread event diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 01c7c4a..3c7b808 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -4027,6 +4027,10 @@ bool QApplication::notify(QObject *receiver, QEvent *e) } break; #endif + case QEvent::RawTouch: + res = d->translateRawTouchEvent(qobject_cast(receiver), + static_cast(e)); + break; case QEvent::TouchBegin: // Note: TouchUpdate and TouchEnd events are sent to d->currentMultitouchWidget and never propagated { @@ -5256,6 +5260,181 @@ void QApplicationPrivate::updateTouchPointsForWidget(QWidget *widget, QTouchEven } } +void QApplicationPrivate::initializeMultitouch() +{ + widgetForTouchPointId.clear(); + appCurrentTouchPoints.clear(); + + initializeMultitouch_sys(); +} + +void QApplicationPrivate::cleanupMultitouch() +{ + cleanupMultitouch_sys(); + + widgetForTouchPointId.clear(); + appCurrentTouchPoints.clear(); +} + +QTouchEvent::TouchPoint *QApplicationPrivate::findClosestTouchPoint(const QPointF &screenPos) +{ + QTouchEvent::TouchPoint *closestTouchPoint = 0; + qreal closestDistance; + for (int i = 0; i < appCurrentTouchPoints.count(); ++i) { + QTouchEvent::TouchPoint *touchPoint = appCurrentTouchPoints.at(i); + qreal distance = QLineF(screenPos, touchPoint->screenPos()).length(); + if (!closestTouchPoint || distance < closestDistance) { + closestTouchPoint = touchPoint; + closestDistance = distance; + } + } + return closestTouchPoint; +} + +void QApplicationPrivate::appendTouchPoint(QTouchEvent::TouchPoint *touchPoint) +{ + // insort touch point + int at = 0; + for (; at < appCurrentTouchPoints.count(); ++at) { + if (appCurrentTouchPoints.at(at)->id() > touchPoint->id()) + break; + } + appCurrentTouchPoints.insert(at, touchPoint); + + if (appCurrentTouchPoints.count() > appAllTouchPoints.count()) { + qFatal("Qt: INTERNAL ERROR: appCurrentTouchPoints.count() (%d) > appAllTouchPoints.count() (%d)", + appCurrentTouchPoints.count(), + appAllTouchPoints.count()); + } +} + +void QApplicationPrivate::removeTouchPoint(QTouchEvent::TouchPoint *touchPoint) +{ + // remove touch point from all known touch points + for (int i = qMin(appCurrentTouchPoints.count() - 1, touchPoint->id()); i >= 0; --i) { + if (appCurrentTouchPoints.at(i) == touchPoint) { + appCurrentTouchPoints.removeAt(i); + break; + } + } +} + +bool QApplicationPrivate::translateRawTouchEvent(QWidget *window, QTouchEvent *rawTouchEvent) +{ + Q_Q(QApplication); + + typedef QPair > StatesAndTouchPoints; + QHash widgetsNeedingEvents; + + for (int i = 0; i < rawTouchEvent->touchPoints().count(); ++i) { + QTouchEvent::TouchPoint *touchPoint = rawTouchEvent->touchPoints().at(i); + + // update state + QWidget *widget = 0; + switch (touchPoint->state()) { + case Qt::TouchPointPressed: + { + // determine which widget this event will go to + if (!window) + window = q->topLevelAt(touchPoint->screenPos().toPoint()); + if (!window) + continue; + widget = window->childAt(window->mapFromGlobal(touchPoint->screenPos().toPoint())); + if (!widget) + widget = window; + + QTouchEvent::TouchPoint *closestTouchPoint = findClosestTouchPoint(touchPoint->screenPos()); + if (closestTouchPoint) { + QWidget *closestWidget = widgetForTouchPointId.value(closestTouchPoint->id()); + if (closestWidget + && (widget->isAncestorOf(closestWidget) + || closestWidget->isAncestorOf(widget))) + widget = closestWidget; + } + widgetForTouchPointId[touchPoint->id()] = widget; + + appendTouchPoint(touchPoint); + break; + } + case Qt::TouchPointReleased: + widget = widgetForTouchPointId.take(touchPoint->id()); + if (!widget) + continue; + + removeTouchPoint(touchPoint); + break; + default: + widget = widgetForTouchPointId.value(touchPoint->id()); + if (!widget) + continue; + break; + } + Q_ASSERT(widget != 0); + + StatesAndTouchPoints &maskAndPoints = widgetsNeedingEvents[widget]; + maskAndPoints.first |= touchPoint->state(); + maskAndPoints.second.append(touchPoint); + } + + if (widgetsNeedingEvents.isEmpty()) + return false; + + bool returnValue = false; + + QHash::ConstIterator it = widgetsNeedingEvents.constBegin(); + const QHash::ConstIterator end = widgetsNeedingEvents.constEnd(); + for (; it != end; ++it) { + QWidget *widget = it.key(); + if (!QApplicationPrivate::tryModalHelper(widget, 0)) + continue; + + QEvent::Type eventType; + switch(it.value().first) { + case Qt::TouchPointPressed: + eventType = QEvent::TouchBegin; + break; + case Qt::TouchPointReleased: + eventType = QEvent::TouchEnd; + break; + case Qt::TouchPointStationary: + // don't send the event if nothing changed + continue; + default: + eventType = QEvent::TouchUpdate; + break; + } + + QTouchEvent touchEvent(eventType, + q->keyboardModifiers(), + it.value().first, + it.value().second); + updateTouchPointsForWidget(widget, &touchEvent); + + bool res = false; + switch (touchEvent.type()) { + case QEvent::TouchBegin: + { + // if the TouchBegin handler recurses, we assume that means the event + // has been implicitly accepted and continue to send touch events + widget->setAttribute(Qt::WA_AcceptedTouchBeginEvent); + res = QApplication::sendSpontaneousEvent(widget, &touchEvent) + && touchEvent.isAccepted(); + break; + } + default: + if (widget->testAttribute(Qt::WA_AcceptedTouchBeginEvent)) { + (void) QApplication::sendSpontaneousEvent(widget, &touchEvent); + res = true; + } + break; + } + returnValue = returnValue || res; + } + + rawTouchEvent->setAccepted(returnValue); + return returnValue; +} + QT_END_NAMESPACE #include "moc_qapplication.cpp" diff --git a/src/gui/kernel/qapplication_mac.mm b/src/gui/kernel/qapplication_mac.mm index d5fa9ea..82fbd7b 100644 --- a/src/gui/kernel/qapplication_mac.mm +++ b/src/gui/kernel/qapplication_mac.mm @@ -2970,4 +2970,9 @@ void onApplicationChangedActivation( bool activated ) #endif } +void QApplicationPrivate::initializeMultitouch_sys() +{ } +void QApplicationPrivate::cleanupMultitouch_sys() +{ } + QT_END_NAMESPACE diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index 1424611..55d8fc4 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -435,7 +435,16 @@ public: QMap grabbedGestures; QHash widgetForTouchPointId; + QList appCurrentTouchPoints; static void updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent); + void initializeMultitouch(); + void initializeMultitouch_sys(); + void cleanupMultitouch(); + void cleanupMultitouch_sys(); + QTouchEvent::TouchPoint *findClosestTouchPoint(const QPointF &screenPos); + void appendTouchPoint(QTouchEvent::TouchPoint *touchPoint); + void removeTouchPoint(QTouchEvent::TouchPoint *touchPoint); + bool translateRawTouchEvent(QWidget *widget, QTouchEvent *rawTouchEvent); #if defined(Q_WS_WIN) static qt_RegisterTouchWindowPtr RegisterTouchWindow; @@ -444,12 +453,6 @@ public: QHash touchInputIDToTouchPointID; QVector appAllTouchPoints; - QList appCurrentTouchPoints; - - void initializeMultitouch(); - QTouchEvent::TouchPoint *findClosestTouchPoint(const QPointF &screenPos); - void appendTouchPoint(QTouchEvent::TouchPoint *touchPoint); - void removeTouchPoint(QTouchEvent::TouchPoint *touchPoint); bool translateTouchEvent(const MSG &msg); #endif diff --git a/src/gui/kernel/qapplication_qws.cpp b/src/gui/kernel/qapplication_qws.cpp index 1125610..a366ed6 100644 --- a/src/gui/kernel/qapplication_qws.cpp +++ b/src/gui/kernel/qapplication_qws.cpp @@ -3746,4 +3746,9 @@ void QApplication::setArgs(int c, char **v) d->argv = v; } +void QApplicationPrivate::initializeMultitouch_sys() +{ } +void QApplicationPrivate::cleanupMultitouch_sys() +{ } + QT_END_NAMESPACE diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index f980f8e..a0c1184 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -3981,60 +3981,22 @@ qt_RegisterTouchWindowPtr QApplicationPrivate::RegisterTouchWindow = 0; qt_GetTouchInputInfoPtr QApplicationPrivate::GetTouchInputInfo = 0; qt_CloseTouchInputHandlePtr QApplicationPrivate::CloseTouchInputHandle = 0; -void QApplicationPrivate::initializeMultitouch() +void QApplicationPrivate::initializeMultitouch_sys() { QLibrary library(QLatin1String("user32")); RegisterTouchWindow = static_cast(library.resolve("RegisterTouchWindow")); GetTouchInputInfo = static_cast(library.resolve("GetTouchInputInfo")); CloseTouchInputHandle = static_cast(library.resolve("CloseTouchInputHandle")); - widgetForTouchPointId.clear(); touchInputIDToTouchPointID.clear(); appAllTouchPoints.clear(); - appCurrentTouchPoints.clear(); } -QTouchEvent::TouchPoint *QApplicationPrivate::findClosestTouchPoint(const QPointF &screenPos) +void QApplicationPrivate::cleanupMultitouch_sys() { - QTouchEvent::TouchPoint *closestTouchPoint = 0; - qreal closestDistance; - for (int i = 0; i < appCurrentTouchPoints.count(); ++i) { - QTouchEvent::TouchPoint *touchPoint = appCurrentTouchPoints.at(i); - qreal distance = QLineF(screenPos, touchPoint->screenPos()).length(); - if (!closestTouchPoint || distance < closestDistance) { - closestTouchPoint = touchPoint; - closestDistance = distance; - } - } - return closestTouchPoint; -} - -void QApplicationPrivate::appendTouchPoint(QTouchEvent::TouchPoint *touchPoint) -{ - // insort touch point - int at = 0; - for (; at < appCurrentTouchPoints.count(); ++at) { - if (appCurrentTouchPoints.at(at)->id() > touchPoint->id()) - break; - } - appCurrentTouchPoints.insert(at, touchPoint); - - if (appCurrentTouchPoints.count() > appAllTouchPoints.count()) { - qFatal("Qt: INTERNAL ERROR: appCurrentTouchPoints.count() (%d) > appAllTouchPoints.count() (%d)", - appCurrentTouchPoints.count(), - appAllTouchPoints.count()); - } -} - -void QApplicationPrivate::removeTouchPoint(QTouchEvent::TouchPoint *touchPoint) -{ - // remove touch point from all known touch points - for (int i = qMin(appCurrentTouchPoints.count() - 1, touchPoint->id()); i >= 0; --i) { - if (appCurrentTouchPoints.at(i) == touchPoint) { - appCurrentTouchPoints.removeAt(i); - break; - } - } + qDeleteAll(appAllTouchPoints); + appAllTouchPoints.clear(); + touchInputIDToTouchPointID.clear(); } bool QApplicationPrivate::translateTouchEvent(const MSG &msg) @@ -4045,8 +4007,8 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) if (!widgetForHwnd) return false; - typedef QPair > StatesAndTouchPoints; - QHash widgetsNeedingEvents; + Qt::TouchPointStates states = 0; + QList touchPoints; QVector winTouchInputs(msg.wParam); memset(winTouchInputs.data(), 0, sizeof(TOUCHINPUT) * winTouchInputs.count()); @@ -4068,45 +4030,21 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) touchPoint = appAllTouchPoints[touchPointID] = new QTouchEvent::TouchPoint(touchPointID); // update state - QWidget *widget = 0; bool down = touchPoint->state() != Qt::TouchPointReleased; QPointF screenPos(qreal(touchInput.x) / qreal(100.), qreal(touchInput.y) / qreal(100.)); if (!down && (touchInput.dwFlags & TOUCHEVENTF_DOWN)) { - // determine which widget this event will go to - widget = widgetForHwnd->childAt(widgetForHwnd->mapFromGlobal(screenPos.toPoint())); - if (!widget) - widget = widgetForHwnd; - - QTouchEvent::TouchPoint *closestTouchPoint = findClosestTouchPoint(screenPos); - if (closestTouchPoint) { - QWidget *closestWidget = widgetForTouchPointId.value(closestTouchPoint->id()); - if (closestWidget - && (widget->isAncestorOf(closestWidget) - || closestWidget->isAncestorOf(widget))) - widget = closestWidget; - } - widgetForTouchPointId[touchPoint->id()] = widget; - - appendTouchPoint(touchPoint); - touchPoint->setState(Qt::TouchPointPressed); touchPoint->setScreenPos(screenPos); touchPoint->setStartScreenPos(screenPos); touchPoint->setLastScreenPos(screenPos); touchPoint->setPressure(qreal(1.)); } else if (down && (touchInput.dwFlags & TOUCHEVENTF_UP)) { - widget = widgetForTouchPointId.take(touchPoint->id()); - - removeTouchPoint(touchPoint); - touchPoint->setState(Qt::TouchPointReleased); touchPoint->setLastScreenPos(touchPoint->screenPos()); touchPoint->setScreenPos(screenPos); touchPoint->setPressure(qreal(0.)); } else if (down) { - widget = widgetForTouchPointId.value(touchPoint->id()); - touchPoint->setState(screenPos == touchPoint->screenPos() ? Qt::TouchPointStationary : Qt::TouchPointMoved); @@ -4114,71 +4052,18 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) touchPoint->setScreenPos(screenPos); // pressure should still be 1. } - Q_ASSERT(widget != 0); - StatesAndTouchPoints &maskAndPoints = widgetsNeedingEvents[widget]; - maskAndPoints.first |= touchPoint->state(); - maskAndPoints.second.append(touchPoint); + states |= touchPoint->state(); + touchPoints.append(touchPoint); } QApplicationPrivate::CloseTouchInputHandle((HANDLE) msg.lParam); - if (widgetsNeedingEvents.isEmpty()) - return false; - - bool returnValue = false; - qt_tabletChokeMouse = false; - - QHash::ConstIterator it = widgetsNeedingEvents.constBegin(); - const QHash::ConstIterator end = widgetsNeedingEvents.constEnd(); - for (; it != end; ++it) { - QWidget *widget = it.key(); - if (!QApplicationPrivate::tryModalHelper(widget, 0)) - continue; - - QEvent::Type eventType; - switch(it.value().first) { - case Qt::TouchPointPressed: - eventType = QEvent::TouchBegin; - break; - case Qt::TouchPointReleased: - eventType = QEvent::TouchEnd; - break; - case Qt::TouchPointStationary: - // don't send the event if nothing changed - continue; - default: - eventType = QEvent::TouchUpdate; - break; - } - - QTouchEvent touchEvent(eventType, - q->keyboardModifiers(), - it.value().first, - it.value().second); - updateTouchPointsForWidget(widget, &touchEvent); - - switch (touchEvent.type()) { - case QEvent::TouchBegin: - { - // if the TouchBegin handler recurses, we assume that means the event - // has been implicitly accepted and continue to send touch events - widget->setAttribute(Qt::WA_AcceptedTouchBeginEvent); - bool res = QApplication::sendSpontaneousEvent(widget, &touchEvent) - && touchEvent.isAccepted(); - returnValue = returnValue || (qt_tabletChokeMouse = qt_tabletChokeMouse || res); - break; - } - default: - if (widget->testAttribute(Qt::WA_AcceptedTouchBeginEvent)) { - (void) QApplication::sendSpontaneousEvent(widget, &touchEvent); - qt_tabletChokeMouse = true; - } - returnValue = returnValue || qt_tabletChokeMouse; - break; - } - } - - return returnValue; + QTouchEvent touchEvent(QEvent::RawTouch, + q->keyboardModifiers(), + states, + touchPoints); + return qt_tabletChokeMouse = (QApplication::sendSpontaneousEvent(widgetForHwnd, &touchEvent) + && touchEvent.isAccepted()); } QT_END_NAMESPACE diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp index 060e948..e16e416 100644 --- a/src/gui/kernel/qapplication_x11.cpp +++ b/src/gui/kernel/qapplication_x11.cpp @@ -5901,4 +5901,9 @@ void QSessionManager::requestPhase2() #endif // QT_NO_SESSIONMANAGER +void QApplicationPrivate::initializeMultitouch_sys() +{ } +void QApplicationPrivate::cleanupMultitouch_sys() +{ } + QT_END_NAMESPACE -- cgit v0.12