Touch event support for QWindow.

Change-Id: I83ddc48a9093856d975b25f0426db96264afeeef
Reviewed-on: http://codereview.qt.nokia.com/3920
Reviewed-by: Gunnar Sletta <gunnar.sletta@nokia.com>
This commit is contained in:
Laszlo Agocs 2011-08-31 11:30:45 +03:00 committed by Gunnar Sletta
parent 012ba8c0e5
commit 0e3ac5dea6
5 changed files with 159 additions and 2 deletions

View File

@ -738,6 +738,8 @@ public:
private:
QTouchEventTouchPointPrivate *d;
friend class QGuiApplication;
friend class QGuiApplicationPrivate;
friend class QApplication;
friend class QApplicationPrivate;
};
@ -771,6 +773,8 @@ protected:
Qt::TouchPointStates _touchPointStates;
QList<QTouchEvent::TouchPoint> _touchPoints;
friend class QGuiApplication;
friend class QGuiApplicationPrivate;
friend class QApplication;
friend class QApplicationPrivate;
};

View File

@ -738,9 +738,147 @@ void QGuiApplicationPrivate::processCloseEvent(QWindowSystemInterfacePrivate::Cl
QGuiApplication::sendSpontaneousEvent(e->window.data(), &event);
}
void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::TouchEvent *)
void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::TouchEvent *e)
{
// translateRawTouchEvent(e->widget.data(), e->devType, e->points);
QWindow *window = e->window.data();
QGuiApplicationPrivate *d = self;
typedef QPair<Qt::TouchPointStates, QList<QTouchEvent::TouchPoint> > StatesAndTouchPoints;
QHash<QWindow *, StatesAndTouchPoints> windowsNeedingEvents;
for (int i = 0; i < e->points.count(); ++i) {
QTouchEvent::TouchPoint touchPoint = e->points.at(i);
// explicitly detach from the original touch point that we got, so even
// if the touchpoint structs are reused, we will make a copy that we'll
// deliver to the user (which might want to store the struct for later use).
touchPoint.d = touchPoint.d->detach();
// update state
QWeakPointer<QWindow> w;
QTouchEvent::TouchPoint previousTouchPoint;
switch (touchPoint.state()) {
case Qt::TouchPointPressed:
if (e->devType == QTouchEvent::TouchPad) {
// on touch-pads, send all touch points to the same widget
w = d->windowForTouchPointId.isEmpty()
? QWeakPointer<QWindow>()
: d->windowForTouchPointId.constBegin().value();
}
if (!w) {
// determine which window this event will go to
if (!window)
window = QGuiApplication::topLevelAt(touchPoint.screenPos().toPoint());
if (!window)
continue;
w = window;
}
d->windowForTouchPointId[touchPoint.id()] = w;
touchPoint.d->startScreenPos = touchPoint.screenPos();
touchPoint.d->lastScreenPos = touchPoint.screenPos();
touchPoint.d->startNormalizedPos = touchPoint.normalizedPos();
touchPoint.d->lastNormalizedPos = touchPoint.normalizedPos();
if (touchPoint.pressure() < qreal(0.))
touchPoint.d->pressure = qreal(1.);
d->appCurrentTouchPoints.insert(touchPoint.id(), touchPoint);
break;
case Qt::TouchPointReleased:
w = d->windowForTouchPointId.take(touchPoint.id());
if (!w)
continue;
previousTouchPoint = d->appCurrentTouchPoints.take(touchPoint.id());
touchPoint.d->startScreenPos = previousTouchPoint.startScreenPos();
touchPoint.d->lastScreenPos = previousTouchPoint.screenPos();
touchPoint.d->startPos = previousTouchPoint.startPos();
touchPoint.d->lastPos = previousTouchPoint.pos();
touchPoint.d->startNormalizedPos = previousTouchPoint.startNormalizedPos();
touchPoint.d->lastNormalizedPos = previousTouchPoint.normalizedPos();
if (touchPoint.pressure() < qreal(0.))
touchPoint.d->pressure = qreal(0.);
break;
default:
w = d->windowForTouchPointId.value(touchPoint.id());
if (!w)
continue;
Q_ASSERT(d->appCurrentTouchPoints.contains(touchPoint.id()));
previousTouchPoint = d->appCurrentTouchPoints.value(touchPoint.id());
touchPoint.d->startScreenPos = previousTouchPoint.startScreenPos();
touchPoint.d->lastScreenPos = previousTouchPoint.screenPos();
touchPoint.d->startPos = previousTouchPoint.startPos();
touchPoint.d->lastPos = previousTouchPoint.pos();
touchPoint.d->startNormalizedPos = previousTouchPoint.startNormalizedPos();
touchPoint.d->lastNormalizedPos = previousTouchPoint.normalizedPos();
if (touchPoint.pressure() < qreal(0.))
touchPoint.d->pressure = qreal(1.);
d->appCurrentTouchPoints[touchPoint.id()] = touchPoint;
break;
}
Q_ASSERT(w.data() != 0);
// make the *scene* functions return the same as the *screen* functions
touchPoint.d->sceneRect = touchPoint.screenRect();
touchPoint.d->startScenePos = touchPoint.startScreenPos();
touchPoint.d->lastScenePos = touchPoint.lastScreenPos();
StatesAndTouchPoints &maskAndPoints = windowsNeedingEvents[w.data()];
maskAndPoints.first |= touchPoint.state();
if (touchPoint.isPrimary())
maskAndPoints.first |= Qt::TouchPointPrimary;
maskAndPoints.second.append(touchPoint);
}
if (windowsNeedingEvents.isEmpty())
return;
QHash<QWindow *, StatesAndTouchPoints>::ConstIterator it = windowsNeedingEvents.constBegin();
const QHash<QWindow *, StatesAndTouchPoints>::ConstIterator end = windowsNeedingEvents.constEnd();
for (; it != end; ++it) {
QWindow *w = it.key();
QEvent::Type eventType;
switch (it.value().first & Qt::TouchPointStateMask) {
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,
e->devType,
QGuiApplication::keyboardModifiers(),
it.value().first,
it.value().second);
for (int i = 0; i < touchEvent.touchPoints().count(); ++i) {
QTouchEvent::TouchPoint &touchPoint = touchEvent._touchPoints[i];
// preserve the sub-pixel resolution
QRectF rect = touchPoint.screenRect();
const QPointF screenPos = rect.center();
const QPointF delta = screenPos - screenPos.toPoint();
rect.moveCenter(w->mapFromGlobal(screenPos.toPoint()) + delta);
touchPoint.d->rect = rect;
if (touchPoint.state() == Qt::TouchPointPressed) {
touchPoint.d->startPos = w->mapFromGlobal(touchPoint.startScreenPos().toPoint()) + delta;
touchPoint.d->lastPos = w->mapFromGlobal(touchPoint.lastScreenPos().toPoint()) + delta;
}
}
QGuiApplication::sendSpontaneousEvent(w, &touchEvent);
}
}
void QGuiApplicationPrivate::reportScreenCount(QWindowSystemInterfacePrivate::ScreenCountEvent *)

View File

@ -180,6 +180,9 @@ private:
void init();
static QGuiApplicationPrivate *self;
QMap<int, QWeakPointer<QWindow> > windowForTouchPointId;
QMap<int, QTouchEvent::TouchPoint> appCurrentTouchPoints;
};
QT_END_NAMESPACE

View File

@ -83,6 +83,12 @@ bool QWidgetWindow::event(QEvent *event)
handleMouseEvent(static_cast<QMouseEvent *>(event));
return true;
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
handleTouchEvent(static_cast<QTouchEvent *>(event));
return true;
case QEvent::Move:
handleMoveEvent(static_cast<QMoveEvent *>(event));
return true;
@ -257,6 +263,11 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
}
}
void QWidgetWindow::handleTouchEvent(QTouchEvent *event)
{
QApplicationPrivate::translateRawTouchEvent(m_widget, event->deviceType(), event->touchPoints());
}
void QWidgetWindow::handleKeyEvent(QKeyEvent *event)
{
if (QApplicationPrivate::instance()->modalState() && !qt_try_modal(m_widget, event->type()))

View File

@ -71,6 +71,7 @@ protected:
void handleEnterLeaveEvent(QEvent *);
void handleKeyEvent(QKeyEvent *);
void handleMouseEvent(QMouseEvent *);
void handleTouchEvent(QTouchEvent *);
void handleMoveEvent(QMoveEvent *);
void handleResizeEvent(QResizeEvent *);
void handleWheelEvent(QWheelEvent *);