summaryrefslogtreecommitdiffstats
path: root/src/gui/kernel/qapplication_win.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/kernel/qapplication_win.cpp')
-rw-r--r--src/gui/kernel/qapplication_win.cpp257
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