diff options
Diffstat (limited to 'src/gui/kernel/qapplication_win.cpp')
-rw-r--r-- | src/gui/kernel/qapplication_win.cpp | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 6237657..f537805 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -88,6 +88,7 @@ extern void qt_wince_hide_taskbar(HWND hwnd); //defined in qguifunctions_wince.c #include "qdebug.h" #include <private/qkeymapper_p.h> #include <private/qlocale_p.h> +#include "qevent_p.h" //#define ALIEN_DEBUG @@ -112,6 +113,39 @@ extern void qt_wince_hide_taskbar(HWND hwnd); //defined in qguifunctions_wince.c # include <winable.h> #endif +#ifndef WM_TOUCHMOVE + +# define WM_TOUCHMOVE 0x0240 +# define WM_TOUCHDOWN 0x0241 +# define WM_TOUCHUP 0x0242 + +# define TOUCHEVENTF_MOVE 0x0001 +# define TOUCHEVENTF_DOWN 0x0002 +# define TOUCHEVENTF_UP 0x0004 +# define TOUCHEVENTF_INRANGE 0x0008 +# define TOUCHEVENTF_PRIMARY 0x0010 +# define TOUCHEVENTF_NOCOALESCE 0x0020 +# define TOUCHEVENTF_PEN 0x0040 + +# define TOUCHINPUTMASKF_TIMEFROMSYSTEM 0x0001 +# define TOUCHINPUTMASKF_EXTRAINFO 0x0002 +# define TOUCHINPUTMASKF_CONTACTAREA 0x0004 + +typedef struct tagTOUCHINPUT +{ + LONG x; + LONG y; + HANDLE hSource; + DWORD dwID; + DWORD dwFlags; + DWORD dwMask; + DWORD dwTime; + ULONG_PTR dwExtraInfo; + DWORD cxContact; + DWORD cyContact; +} TOUCHINPUT, *PTOUCHINPUT; + +#endif #ifndef FLASHW_STOP typedef struct { @@ -853,6 +887,8 @@ void qt_init(QApplicationPrivate *priv, int) if (ptrUpdateLayeredWindow && !ptrUpdateLayeredWindowIndirect) ptrUpdateLayeredWindowIndirect = qt_updateLayeredWindowIndirect; #endif + + priv->initializeMultitouch(); } /***************************************************************************** @@ -1716,6 +1752,11 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam result = widget->translateWheelEvent(msg); } else { switch (message) { + case WM_TOUCHMOVE: + case WM_TOUCHDOWN: + case WM_TOUCHUP: + result = getQApplicationPrivateInternal()->translateTouchEvent(msg); + break; case WM_KEYDOWN: // keyboard event case WM_SYSKEYDOWN: qt_keymapper_private()->updateKeyMap(msg); @@ -3956,4 +3997,234 @@ void QSessionManager::cancel() #endif //QT_NO_SESSIONMANAGER +qt_RegisterTouchWindowPtr QApplicationPrivate::RegisterTouchWindow = 0; +qt_GetTouchInputInfoPtr QApplicationPrivate::GetTouchInputInfo = 0; +qt_CloseTouchInputHandlePtr QApplicationPrivate::CloseTouchInputHandle = 0; + +void QApplicationPrivate::initializeMultitouch() +{ + QLibrary library(QLatin1String("user32")); + RegisterTouchWindow = static_cast<qt_RegisterTouchWindowPtr>(library.resolve("RegisterTouchWindow")); + GetTouchInputInfo = static_cast<qt_GetTouchInputInfoPtr>(library.resolve("GetTouchInputInfo")); + CloseTouchInputHandle = static_cast<qt_CloseTouchInputHandlePtr>(library.resolve("CloseTouchInputHandle")); + + widgetForTouchPointId.clear(); + widgetCurrentTouchPoints.clear(); + touchInputIDToTouchPointID.clear(); + appAllTouchPoints.clear(); + appCurrentTouchPoints.clear(); +} + +QTouchEvent::TouchPoint *QApplicationPrivate::findClosestTouchPoint(const QList<QTouchEvent::TouchPoint *> &appActiveTouchPoints, + const QPointF &screenPos) +{ + QTouchEvent::TouchPoint *closestTouchPoint = 0; + qreal closestDistance; + for (int i = 0; i < appActiveTouchPoints.count(); ++i) { + QTouchEvent::TouchPoint *touchPoint = appActiveTouchPoints.at(i); + qreal distance = QLineF(screenPos, touchPoint->d->screenPos).length(); + if (!closestTouchPoint || distance < closestDistance) { + closestTouchPoint = touchPoint; + closestDistance = distance; + } + } + return closestTouchPoint; +} + +QEvent::Type QApplicationPrivate::appendTouchPoint(QTouchEvent::TouchPoint *touchPoint, + QList<QTouchEvent::TouchPoint *> *currentTouchPoints) +{ + QEvent::Type eventType = currentTouchPoints->isEmpty() + ? QEvent::TouchBegin + : QEvent::TouchUpdate; + + // insort touch point (for the app) + int at = 0; + for (; at < appCurrentTouchPoints.count(); ++at) { + if (appCurrentTouchPoints.at(at)->id() > touchPoint->id()) + break; + } + appCurrentTouchPoints.insert(at, touchPoint); + // again, for the widget's currentTouchPoints + for (at = 0; at < currentTouchPoints->count(); ++at) { + if (currentTouchPoints->at(at)->id() > touchPoint->id()) + break; + } + currentTouchPoints->insert(at, touchPoint); + + if (appCurrentTouchPoints.count() > appAllTouchPoints.count()) { + qFatal("Qt: INTERNAL ERROR: appCurrentTouchPoints.count() (%d) > appAllTouchPoints.count() (%d)", + appCurrentTouchPoints.count(), + appAllTouchPoints.count()); + } + + return eventType; +} + +QEvent::Type QApplicationPrivate::removeTouchPoint(QTouchEvent::TouchPoint *touchPoint, + QList<QTouchEvent::TouchPoint *> *currentTouchPoints) +{ + // 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; + } + } + // again, for the widget's currentTouchPoints + for (int i = qMin(currentTouchPoints->count() - 1, touchPoint->id()); i >= 0; --i) { + if (currentTouchPoints->at(i) == touchPoint) { + currentTouchPoints->removeAt(i); + break; + } + } + + return currentTouchPoints->isEmpty() ? QEvent::TouchEnd : QEvent::TouchUpdate; +} + +bool QApplicationPrivate::translateTouchEvent(const MSG &msg) +{ + Q_Q(QApplication); + + QWidget *widgetForHwnd = QWidget::find(msg.hwnd); + if (!widgetForHwnd) + return false; + + QList<QTouchEvent::TouchPoint *> appActiveTouchPoints = appCurrentTouchPoints; + + QHash<QWidget *, QTouchEvent> widgetsNeedingEvents; + QVector<TOUCHINPUT> winTouchInputs(msg.wParam); + memset(winTouchInputs.data(), 0, sizeof(TOUCHINPUT) * winTouchInputs.count()); + QApplicationPrivate::GetTouchInputInfo((HANDLE) msg.lParam, msg.wParam, winTouchInputs.data(), sizeof(TOUCHINPUT)); + for (int i = 0; i < winTouchInputs.count(); ++i) { + const TOUCHINPUT &touchInput = winTouchInputs.at(i); + + int touchPointID = touchInputIDToTouchPointID.value(touchInput.dwID, -1); + if (touchPointID == -1) { + touchPointID = touchInputIDToTouchPointID.count(); + touchInputIDToTouchPointID.insert(touchInput.dwID, touchPointID); + } + + if (appAllTouchPoints.count() <= touchPointID) + appAllTouchPoints.resize(touchPointID + 1); + + QTouchEvent::TouchPoint *touchPoint = appAllTouchPoints.at(touchPointID); + if (!touchPoint) + touchPoint = appAllTouchPoints[touchPointID] = new QTouchEvent::TouchPoint(touchPointID); + + // update state + QWidget *widget = 0; + bool down = touchPoint->d->state != Qt::TouchPointReleased; + QPointF screenPos(qreal(touchInput.x) / qreal(100.), qreal(touchInput.y) / qreal(100.)); + QEvent::Type eventType = QEvent::None; + + QList<QTouchEvent::TouchPoint *> activeTouchPoints; + 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(appActiveTouchPoints, screenPos); + if (closestTouchPoint) { + QWidget *closestWidget = widgetForTouchPointId.value(closestTouchPoint->d->id); + if (closestWidget + && (widget->isAncestorOf(closestWidget) + || closestWidget->isAncestorOf(widget))) + widget = closestWidget; + } + widgetForTouchPointId[touchPoint->d->id] = widget; + + QList<QTouchEvent::TouchPoint *> ¤tTouchPoints = widgetCurrentTouchPoints[widget]; + eventType = appendTouchPoint(touchPoint, ¤tTouchPoints); + // make sure new points are added to activeTouchPoints as well + appActiveTouchPoints = appCurrentTouchPoints; + activeTouchPoints = currentTouchPoints; + + touchPoint->d->state = Qt::TouchPointPressed; + touchPoint->d->screenPos + = touchPoint->d->startScreenPos + = touchPoint->d->lastScreenPos + = screenPos; + touchPoint->d->pressure = qreal(1.); + } else if (down && (touchInput.dwFlags & TOUCHEVENTF_UP)) { + widget = widgetForTouchPointId.take(touchPoint->d->id); + QList<QTouchEvent::TouchPoint *> ¤tTouchPoints = widgetCurrentTouchPoints[widget]; + appActiveTouchPoints = appCurrentTouchPoints; + activeTouchPoints = currentTouchPoints; + eventType = removeTouchPoint(touchPoint, ¤tTouchPoints); + + touchPoint->d->state = Qt::TouchPointReleased; + touchPoint->d->lastScreenPos = touchPoint->d->screenPos; + touchPoint->d->screenPos = screenPos; + touchPoint->d->pressure = qreal(0.); + } else if (down) { + widget = widgetForTouchPointId.value(touchPoint->d->id); + appActiveTouchPoints = appCurrentTouchPoints; + activeTouchPoints = widgetCurrentTouchPoints.value(widget); + eventType = QEvent::TouchUpdate; + touchPoint->d->state = screenPos == touchPoint->d->screenPos + ? Qt::TouchPointStationary + : Qt::TouchPointMoved; + touchPoint->d->lastScreenPos = touchPoint->d->screenPos; + touchPoint->d->screenPos = screenPos; + // pressure should still be 1. + } + Q_ASSERT(widget != 0 && eventType != QEvent::None); + + if (touchPoint->d->state != Qt::TouchPointStationary) { + widgetsNeedingEvents.insert(widget, + QTouchEvent(eventType, q->keyboardModifiers(), activeTouchPoints)); + } + } + QApplicationPrivate::CloseTouchInputHandle((HANDLE) msg.lParam); + + if (widgetsNeedingEvents.isEmpty()) + return false; + + bool returnValue = false; + qt_tabletChokeMouse = false; + + QHash<QWidget *, QTouchEvent>::ConstIterator it = widgetsNeedingEvents.constBegin(); + const QHash<QWidget *, QTouchEvent>::ConstIterator end = widgetsNeedingEvents.constEnd(); + for (; it != end; ++it) { + QWidget *widget = it.key(); + if (!QApplicationPrivate::tryModalHelper(widget, 0)) + continue; + + QTouchEvent touchEvent = it.value(); + 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; + } + case QEvent::TouchEnd: + { + QList<QTouchEvent::TouchPoint *> currentTouchPoints = widgetCurrentTouchPoints.take(widget); + if (!currentTouchPoints.isEmpty()) { + qFatal("Qt: INTERNAL ERROR, the widget's currentTouchPoints should be empty!"); + } + // fall-through intended + } + default: + if (widget->testAttribute(Qt::WA_AcceptedTouchBeginEvent)) { + (void) QApplication::sendSpontaneousEvent(widget, &touchEvent); + qt_tabletChokeMouse = true; + } + returnValue = returnValue || qt_tabletChokeMouse; + break; + } + } + + return returnValue; +} + QT_END_NAMESPACE |