QPA tablet event support

Should be sufficient to allow implementing the actual functionality in
xcb/cocoa/windows to match the Qt 4 level of tablet event support.

Task-number: QTBUG-25864
Change-Id: Iebcca256dfba841d8976b58fda1b76026d3133a3
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Reviewed-by: Morten Johan Sørvig <morten.sorvig@nokia.com>
bb10
Laszlo Agocs 2012-05-23 15:07:39 +03:00 committed by Qt by Nokia
parent ce7b3c9720
commit b551d5e4f7
8 changed files with 296 additions and 1 deletions

View File

@ -102,6 +102,9 @@ Qt::KeyboardModifiers QGuiApplicationPrivate::modifier_buttons = Qt::NoModifier;
QPointF QGuiApplicationPrivate::lastCursorPosition(0.0, 0.0);
bool QGuiApplicationPrivate::tabletState = false;
QWindow *QGuiApplicationPrivate::tabletPressTarget = 0;
QPlatformIntegration *QGuiApplicationPrivate::platform_integration = 0;
QPlatformTheme *QGuiApplicationPrivate::platform_theme = 0;
@ -1113,6 +1116,18 @@ void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePriv
case QWindowSystemInterfacePrivate::Expose:
QGuiApplicationPrivate::processExposeEvent(static_cast<QWindowSystemInterfacePrivate::ExposeEvent *>(e));
break;
case QWindowSystemInterfacePrivate::Tablet:
QGuiApplicationPrivate::processTabletEvent(
static_cast<QWindowSystemInterfacePrivate::TabletEvent *>(e));
break;
case QWindowSystemInterfacePrivate::TabletEnterProximity:
QGuiApplicationPrivate::processTabletEnterProximityEvent(
static_cast<QWindowSystemInterfacePrivate::TabletEnterProximityEvent *>(e));
break;
case QWindowSystemInterfacePrivate::TabletLeaveProximity:
QGuiApplicationPrivate::processTabletLeaveProximityEvent(
static_cast<QWindowSystemInterfacePrivate::TabletLeaveProximityEvent *>(e));
break;
default:
qWarning() << "Unknown user input event type:" << e->type;
break;
@ -1439,6 +1454,81 @@ void QGuiApplicationPrivate::processFileOpenEvent(QWindowSystemInterfacePrivate:
QGuiApplication::sendSpontaneousEvent(qApp, &event);
}
void QGuiApplicationPrivate::processTabletEvent(QWindowSystemInterfacePrivate::TabletEvent *e)
{
#ifndef QT_NO_TABLETEVENT
QEvent::Type type = QEvent::TabletMove;
if (e->down != tabletState) {
type = e->down ? QEvent::TabletPress : QEvent::TabletRelease;
tabletState = e->down;
}
QWindow *window = e->window.data();
bool localValid = true;
// If window is null, pick one based on the global position and make sure all
// subsequent events up to the release are delivered to that same window.
// If window is given, just send to that.
if (type == QEvent::TabletPress) {
if (!window) {
window = QGuiApplication::topLevelAt(e->global.toPoint());
localValid = false;
}
if (!window)
return;
tabletPressTarget = window;
} else {
if (!window) {
window = tabletPressTarget;
localValid = false;
}
if (type == QEvent::TabletRelease)
tabletPressTarget = 0;
if (!window)
return;
}
QPointF local = e->local;
if (!localValid) {
QPointF delta = e->global - e->global.toPoint();
local = window->mapFromGlobal(e->global.toPoint()) + delta;
}
QTabletEvent ev(type, local, e->global,
e->device, e->pointerType, e->pressure, e->xTilt, e->yTilt,
e->tangentialPressure, e->rotation, e->z,
e->mods, e->uid);
ev.setTimestamp(e->timestamp);
QGuiApplication::sendSpontaneousEvent(window, &ev);
#else
Q_UNUSED(e)
#endif
}
void QGuiApplicationPrivate::processTabletEnterProximityEvent(QWindowSystemInterfacePrivate::TabletEnterProximityEvent *e)
{
#ifndef QT_NO_TABLETEVENT
QTabletEvent ev(QEvent::TabletEnterProximity, QPointF(), QPointF(),
e->device, e->pointerType, 0, 0, 0,
0, 0, 0,
Qt::NoModifier, e->uid);
ev.setTimestamp(e->timestamp);
QGuiApplication::sendSpontaneousEvent(qGuiApp, &ev);
#else
Q_UNUSED(e)
#endif
}
void QGuiApplicationPrivate::processTabletLeaveProximityEvent(QWindowSystemInterfacePrivate::TabletLeaveProximityEvent *e)
{
#ifndef QT_NO_TABLETEVENT
QTabletEvent ev(QEvent::TabletLeaveProximity, QPointF(), QPointF(),
e->device, e->pointerType, 0, 0, 0,
0, 0, 0,
Qt::NoModifier, e->uid);
ev.setTimestamp(e->timestamp);
QGuiApplication::sendSpontaneousEvent(qGuiApp, &ev);
#else
Q_UNUSED(e)
#endif
}
Q_GUI_EXPORT uint qHash(const QGuiApplicationPrivate::ActiveTouchPointsKey &k)
{
return qHash(k.device) + k.touchPointId;

View File

@ -124,6 +124,10 @@ public:
static void processFileOpenEvent(QWindowSystemInterfacePrivate::FileOpenEvent *e);
static void processTabletEvent(QWindowSystemInterfacePrivate::TabletEvent *e);
static void processTabletEnterProximityEvent(QWindowSystemInterfacePrivate::TabletEnterProximityEvent *e);
static void processTabletLeaveProximityEvent(QWindowSystemInterfacePrivate::TabletLeaveProximityEvent *e);
#ifndef QT_NO_DRAGANDDROP
static QPlatformDragQtResponse processDrag(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions);
static QPlatformDropQtResponse processDrop(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions);
@ -167,6 +171,8 @@ public:
static int mousePressY;
static int mouse_double_click_distance;
static QPointF lastCursorPosition;
static bool tabletState;
static QWindow *tabletPressTarget;
#ifndef QT_NO_CLIPBOARD
static QClipboard *qt_clipboard;

View File

@ -1522,6 +1522,14 @@ bool QWindow::event(QEvent *ev)
hideEvent(static_cast<QHideEvent *>(ev));
break;
#ifndef QT_NO_TABLETEVENT
case QEvent::TabletPress:
case QEvent::TabletMove:
case QEvent::TabletRelease:
tabletEvent(static_cast<QTabletEvent *>(ev));
break;
#endif
default:
return QObject::event(ev);
}
@ -1628,6 +1636,19 @@ void QWindow::touchEvent(QTouchEvent *ev)
ev->ignore();
}
#ifndef QT_NO_TABLETEVENT
/*!
Override this to handle tablet press, move, and release events.
Proximity enter and leave events are not sent to windows, they are
delivered to the application instance.
*/
void QWindow::tabletEvent(QTabletEvent *ev)
{
ev->ignore();
}
#endif
/*!
Override this to handle platform dependent events.

View File

@ -78,6 +78,9 @@ class QMouseEvent;
class QWheelEvent;
#endif
class QTouchEvent;
#ifndef QT_NO_TABLETEVENT
class QTabletEvent;
#endif
class QPlatformSurface;
class QPlatformWindow;
@ -302,6 +305,9 @@ protected:
virtual void wheelEvent(QWheelEvent *);
#endif
virtual void touchEvent(QTouchEvent *);
#ifndef QT_NO_TABLETEVENT
virtual void tabletEvent(QTabletEvent *);
#endif
virtual bool nativeEvent(const QByteArray &eventType, void *message, long *result);
QWindow(QWindowPrivate &dd, QWindow *parent);

View File

@ -528,4 +528,52 @@ void QWindowSystemInterface::handleFileOpenEvent(const QString& fileName)
QGuiApplicationPrivate::processWindowSystemEvent(&e);
}
void QWindowSystemInterface::handleTabletEvent(QWindow *w, ulong timestamp, bool down, const QPointF &local, const QPointF &global,
int device, int pointerType, qreal pressure, int xTilt, int yTilt,
qreal tangentialPressure, qreal rotation, int z, qint64 uid,
Qt::KeyboardModifiers modifiers)
{
QWindowSystemInterfacePrivate::TabletEvent *e =
new QWindowSystemInterfacePrivate::TabletEvent(w, timestamp, down, local, global, device, pointerType, pressure,
xTilt, yTilt, tangentialPressure, rotation, z, uid, modifiers);
QWindowSystemInterfacePrivate::queueWindowSystemEvent(e);
}
void QWindowSystemInterface::handleTabletEvent(QWindow *w, bool down, const QPointF &local, const QPointF &global,
int device, int pointerType, qreal pressure, int xTilt, int yTilt,
qreal tangentialPressure, qreal rotation, int z, qint64 uid,
Qt::KeyboardModifiers modifiers)
{
ulong time = QWindowSystemInterfacePrivate::eventTime.elapsed();
handleTabletEvent(w, time, down, local, global, device, pointerType, pressure,
xTilt, yTilt, tangentialPressure, rotation, z, uid, modifiers);
}
void QWindowSystemInterface::handleTabletEnterProximityEvent(ulong timestamp, int device, int pointerType, qint64 uid)
{
QWindowSystemInterfacePrivate::TabletEnterProximityEvent *e =
new QWindowSystemInterfacePrivate::TabletEnterProximityEvent(timestamp, device, pointerType, uid);
QWindowSystemInterfacePrivate::queueWindowSystemEvent(e);
}
void QWindowSystemInterface::handleTabletEnterProximityEvent(int device, int pointerType, qint64 uid)
{
ulong time = QWindowSystemInterfacePrivate::eventTime.elapsed();
handleTabletEnterProximityEvent(time, device, pointerType, uid);
}
void QWindowSystemInterface::handleTabletLeaveProximityEvent(ulong timestamp, int device, int pointerType, qint64 uid)
{
QWindowSystemInterfacePrivate::TabletLeaveProximityEvent *e =
new QWindowSystemInterfacePrivate::TabletLeaveProximityEvent(timestamp, device, pointerType, uid);
QWindowSystemInterfacePrivate::queueWindowSystemEvent(e);
}
void QWindowSystemInterface::handleTabletLeaveProximityEvent(int device, int pointerType, qint64 uid)
{
ulong time = QWindowSystemInterfacePrivate::eventTime.elapsed();
handleTabletLeaveProximityEvent(time, device, pointerType, uid);
}
QT_END_NAMESPACE

View File

@ -152,6 +152,20 @@ public:
static void handleFileOpenEvent(const QString& fileName);
static void handleTabletEvent(QWindow *w, ulong timestamp, bool down, const QPointF &local, const QPointF &global,
int device, int pointerType, qreal pressure, int xTilt, int yTilt,
qreal tangentialPressure, qreal rotation, int z, qint64 uid,
Qt::KeyboardModifiers modifiers = Qt::NoModifier);
static void handleTabletEvent(QWindow *w, bool down, const QPointF &local, const QPointF &global,
int device, int pointerType, qreal pressure, int xTilt, int yTilt,
qreal tangentialPressure, qreal rotation, int z, qint64 uid,
Qt::KeyboardModifiers modifiers = Qt::NoModifier);
static void handleTabletEnterProximityEvent(ulong timestamp, int device, int pointerType, qint64 uid);
static void handleTabletEnterProximityEvent(int device, int pointerType, qint64 uid);
static void handleTabletLeaveProximityEvent(ulong timestamp, int device, int pointerType, qint64 uid);
static void handleTabletLeaveProximityEvent(int device, int pointerType, qint64 uid);
// For event dispatcher implementations
static bool sendWindowSystemEvents(QAbstractEventDispatcher *eventDispatcher, QEventLoop::ProcessEventsFlags flags);
static int windowSystemEventsQueued();

View File

@ -69,7 +69,10 @@ public:
ScreenRefreshRate,
ThemeChange,
Expose,
FileOpen
FileOpen,
Tablet,
TabletEnterProximity,
TabletLeaveProximity
};
class WindowSystemEvent {
@ -266,6 +269,55 @@ public:
QString fileName;
};
class TabletEvent : public InputEvent {
public:
static void handleTabletEvent(QWindow *w, bool down, const QPointF &local, const QPointF &global,
int device, int pointerType, qreal pressure, int xTilt, int yTilt,
qreal tangentialPressure, qreal rotation, int z, qint64 uid,
Qt::KeyboardModifiers modifiers = Qt::NoModifier);
TabletEvent(QWindow *w, ulong time, bool down, const QPointF &local, const QPointF &global,
int device, int pointerType, qreal pressure, int xTilt, int yTilt, qreal tpressure,
qreal rotation, int z, qint64 uid, Qt::KeyboardModifiers mods)
: InputEvent(w, time, Tablet, Qt::NoModifier),
down(down), local(local), global(global), device(device), pointerType(pointerType),
pressure(pressure), xTilt(xTilt), yTilt(yTilt), tangentialPressure(tpressure),
rotation(rotation), z(z), uid(uid), mods(mods) { }
bool down;
QPointF local;
QPointF global;
int device;
int pointerType;
qreal pressure;
int xTilt;
int yTilt;
qreal tangentialPressure;
qreal rotation;
int z;
qint64 uid;
Qt::KeyboardModifiers mods;
};
class TabletEnterProximityEvent : public InputEvent {
public:
TabletEnterProximityEvent(ulong time, int device, int pointerType, qint64 uid)
: InputEvent(0, time, TabletEnterProximity, Qt::NoModifier),
device(device), pointerType(pointerType), uid(uid) { }
int device;
int pointerType;
qint64 uid;
};
class TabletLeaveProximityEvent : public InputEvent {
public:
TabletLeaveProximityEvent(ulong time, int device, int pointerType, qint64 uid)
: InputEvent(0, time, TabletLeaveProximity, Qt::NoModifier),
device(device), pointerType(pointerType), uid(uid) { }
int device;
int pointerType;
qint64 uid;
};
static QList<WindowSystemEvent *> windowSystemEventQueue;
static QMutex queueMutex;

View File

@ -71,6 +71,7 @@ private slots:
void mouseEventSequence();
void windowModality();
void inputReentrancy();
void tabletEvents();
void initTestCase()
{
@ -925,5 +926,62 @@ void tst_QWindow::inputReentrancy()
QCOMPARE(window.touchReleasedCount, 1);
}
#ifndef QT_NO_TABLETEVENT
class TabletTestWindow : public QWindow
{
public:
TabletTestWindow() : eventType(0) { }
void tabletEvent(QTabletEvent *ev) {
eventType = ev->type();
eventGlobal = ev->globalPosF();
eventLocal = ev->posF();
eventDevice = ev->device();
}
int eventType;
QPointF eventGlobal, eventLocal;
int eventDevice;
bool eventFilter(QObject *obj, QEvent *ev) {
if (ev->type() == QEvent::TabletEnterProximity
|| ev->type() == QEvent::TabletLeaveProximity) {
eventType = ev->type();
QTabletEvent *te = static_cast<QTabletEvent *>(ev);
eventDevice = te->device();
}
return QWindow::eventFilter(obj, ev);
}
};
#endif
void tst_QWindow::tabletEvents()
{
#ifndef QT_NO_TABLETEVENT
TabletTestWindow window;
window.setGeometry(10, 10, 100, 100);
qGuiApp->installEventFilter(&window);
QPoint local(10, 10);
QPoint global = window.mapToGlobal(local);
QWindowSystemInterface::handleTabletEvent(&window, true, local, global, 1, 2, 0.5, 1, 2, 0.1, 0, 0, 0);
QCoreApplication::processEvents();
QTRY_VERIFY(window.eventType == QEvent::TabletPress);
QTRY_COMPARE(window.eventGlobal.toPoint(), global);
QTRY_COMPARE(window.eventLocal.toPoint(), local);
QWindowSystemInterface::handleTabletEvent(&window, false, local, global, 1, 2, 0.5, 1, 2, 0.1, 0, 0, 0);
QCoreApplication::processEvents();
QTRY_VERIFY(window.eventType == QEvent::TabletRelease);
QWindowSystemInterface::handleTabletEnterProximityEvent(1, 2, 3);
QCoreApplication::processEvents();
QTRY_VERIFY(window.eventType == QEvent::TabletEnterProximity);
QTRY_COMPARE(window.eventDevice, 1);
QWindowSystemInterface::handleTabletLeaveProximityEvent(1, 2, 3);
QCoreApplication::processEvents();
QTRY_VERIFY(window.eventType == QEvent::TabletLeaveProximity);
QTRY_COMPARE(window.eventDevice, 1);
#endif
}
#include <tst_qwindow.moc>
QTEST_MAIN(tst_QWindow)