diff options
Diffstat (limited to 'src/gui/kernel/qapplication_win.cpp')
-rw-r--r-- | src/gui/kernel/qapplication_win.cpp | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 6237657..91c24da 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -75,6 +75,7 @@ extern void qt_wince_hide_taskbar(HWND hwnd); //defined in qguifunctions_wince.c #include "qcolormap.h" #include "qlayout.h" #include "qtooltip.h" +#include "qset.h" #include "qt_windows.h" #if defined(QT_NON_COMMERCIAL) #include "qnc_win.h" @@ -88,6 +89,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 +114,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 +888,8 @@ void qt_init(QApplicationPrivate *priv, int) if (ptrUpdateLayeredWindow && !ptrUpdateLayeredWindowIndirect) ptrUpdateLayeredWindowIndirect = qt_updateLayeredWindowIndirect; #endif + + priv->initializeMultitouch(); } /***************************************************************************** @@ -1716,6 +1753,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 +3998,219 @@ 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")); + + touchInputIDToTouchPointID.clear(); + appAllTouchPoints.clear(); +} + +QTouchEvent::TouchPoint *QApplicationPrivate::findClosestTouchPoint(const QList<QTouchEvent::TouchPoint *> &appActiveTouchPoints, + const QPointF &pos) +{ + QTouchEvent::TouchPoint *closestTouchPoint = 0; + qreal closestDistance; + for (int i = 0; i < appActiveTouchPoints.count(); ++i) { + QTouchEvent::TouchPoint *touchPoint = appActiveTouchPoints.at(i); + qreal distance = QLineF(pos, touchPoint->d->globalPos).length(); + if (!closestTouchPoint || distance < closestDistance) { + closestTouchPoint = touchPoint; + closestDistance = distance; + } + } + return closestTouchPoint; +} + +QEvent::Type QApplicationPrivate::appendTouchPoint(QTouchEvent::TouchPoint *touchPoint) +{ + QWidget *widget = touchPoint->d->widget; + QEvent::Type eventType = widget->d_func()->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 < widget->d_func()->currentTouchPoints.count(); ++at) { + if (widget->d_func()->currentTouchPoints.at(at)->id() > touchPoint->id()) + break; + } + widget->d_func()->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) +{ + QWidget *widget = touchPoint->d->widget; + + // 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(widget->d_func()->currentTouchPoints.count() - 1, touchPoint->id()); i >= 0; --i) { + if (widget->d_func()->currentTouchPoints.at(i) == touchPoint) { + widget->d_func()->currentTouchPoints.removeAt(i); + break; + } + } + + return widget->d_func()->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; + + QSet<QWidget *> 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 + bool down = touchPoint->d->state != Qt::TouchPointReleased; + QPointF globalPos(qreal(touchInput.x) / qreal(100.), qreal(touchInput.y) / qreal(100.)); + if (!down && (touchInput.dwFlags & TOUCHEVENTF_DOWN)) { + // determine which widget this event will go to + QWidget *w = widgetForHwnd->childAt(widgetForHwnd->mapFromGlobal(globalPos.toPoint())); + if (!w) + w = widgetForHwnd; + + QTouchEvent::TouchPoint *closestTouchPoint = findClosestTouchPoint(appActiveTouchPoints, globalPos); + if (closestTouchPoint + && (w->isAncestorOf(closestTouchPoint->d->widget) + || closestTouchPoint->d->widget->isAncestorOf(w))) { + w = closestTouchPoint->d->widget; + } + touchPoint->d->widget = w; + + w->d_func()->touchEventType = appendTouchPoint(touchPoint); + // make sure new points are added to activeTouchPoints as well + appActiveTouchPoints = appCurrentTouchPoints; + w->d_func()->activeTouchPoints = w->d_func()->currentTouchPoints; + + touchPoint->d->state = Qt::TouchPointPressed; + touchPoint->d->globalPos + = touchPoint->d->startGlobalPos + = touchPoint->d->lastGlobalPos + = globalPos; + touchPoint->d->pressure = qreal(1.); + } else if (down && (touchInput.dwFlags & TOUCHEVENTF_UP)) { + QWidget *w = touchPoint->d->widget; + appActiveTouchPoints = appCurrentTouchPoints; + w->d_func()->activeTouchPoints = w->d_func()->currentTouchPoints; + w->d_func()->touchEventType = removeTouchPoint(touchPoint); + + touchPoint->d->state = Qt::TouchPointReleased; + touchPoint->d->lastGlobalPos = touchPoint->d->globalPos; + touchPoint->d->globalPos = globalPos; + touchPoint->d->pressure = qreal(0.); + } else if (down) { + QWidget *w = touchPoint->d->widget; + appActiveTouchPoints = appCurrentTouchPoints; + w->d_func()->activeTouchPoints = w->d_func()->currentTouchPoints; + w->d_func()->touchEventType = QEvent::TouchUpdate; + touchPoint->d->state = globalPos == touchPoint->d->globalPos + ? Qt::TouchPointStationary + : Qt::TouchPointMoved; + touchPoint->d->lastGlobalPos = touchPoint->d->globalPos; + touchPoint->d->globalPos = globalPos; + // pressure should still be 1. + } + + if (touchPoint->d->state != Qt::TouchPointStationary) + widgetsNeedingEvents.insert(touchPoint->d->widget); + } + QApplicationPrivate::CloseTouchInputHandle((HANDLE) msg.lParam); + + if (widgetsNeedingEvents.isEmpty()) + return false; + + bool returnValue = false; + + QSet<QWidget *>::ConstIterator it = widgetsNeedingEvents.constBegin(); + const QSet<QWidget *>::ConstIterator end = widgetsNeedingEvents.constEnd(); + for (; it != end; ++it) { + QWidget *widget = *it; + if (!QApplicationPrivate::tryModalHelper(widget, 0)) + continue; + + QTouchEvent touchEvent(widget->d_func()->touchEventType, q->keyboardModifiers(), widget->d_func()->activeTouchPoints); + updateTouchPointsForWidget(widget, &touchEvent); + + switch (widget->d_func()->touchEventType) { + 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 = res); + break; + } + case QEvent::TouchEnd: + if (!widget->d_func()->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; + } else { + qt_tabletChokeMouse = false; + } + returnValue = returnValue || qt_tabletChokeMouse; + break; + } + } + + return returnValue; +} + QT_END_NAMESPACE |