diff --git a/src/plugins/generic/touchscreen/README b/src/plugins/generic/touchscreen/README index 76f695371d..25e0e1abe8 100644 --- a/src/plugins/generic/touchscreen/README +++ b/src/plugins/generic/touchscreen/README @@ -14,9 +14,9 @@ LinuxTouchScreen:/dev/input/eventN to explicitly set the device file name. By default the surface of the touch device is mapped to the entire -screen. If this is not desired, define FORCE_TO_ACTIVE_WINDOW in -qtoucheventsenderqpa.cpp. This will map the touch surface to the -active window instead. +screen. If this is not desired, pass force_window in the plugin +specification. This will cause mapping the touch surface to the active +window instead. Only touch events are generated (via QWindowSystemInterface::handleTouchEvent), mouse events are not. This diff --git a/src/plugins/generic/touchscreen/main.cpp b/src/plugins/generic/touchscreen/main.cpp index 8ad756355d..ff476d1648 100644 --- a/src/plugins/generic/touchscreen/main.cpp +++ b/src/plugins/generic/touchscreen/main.cpp @@ -67,8 +67,8 @@ QObject* QTouchScreenPlugin::create(const QString &key, const QString &spec) { if (!key.compare(QLatin1String("LinuxTouchScreen"), Qt::CaseInsensitive)) { - QTouchScreenHandler *h = new QTouchScreenHandler(spec); - h->addObserver(new QTouchEventSenderQPA); + QTouchScreenObserver *obs = new QTouchEventSenderQPA(spec); + QTouchScreenHandlerThread *h = new QTouchScreenHandlerThread(spec, obs); return h; } diff --git a/src/plugins/generic/touchscreen/qtoucheventsenderqpa.cpp b/src/plugins/generic/touchscreen/qtoucheventsenderqpa.cpp index 7dff55b1bc..cd11f44bed 100644 --- a/src/plugins/generic/touchscreen/qtoucheventsenderqpa.cpp +++ b/src/plugins/generic/touchscreen/qtoucheventsenderqpa.cpp @@ -47,7 +47,11 @@ QT_BEGIN_NAMESPACE //#define POINT_DEBUG -//#define FORCE_TO_ACTIVE_WINDOW + +QTouchEventSenderQPA::QTouchEventSenderQPA(const QString &spec) +{ + m_forceToActiveWindow = spec.split(QLatin1Char(':')).contains(QLatin1String("force_window")); +} void QTouchEventSenderQPA::touch_configure(int x_min, int x_max, int y_min, int y_max) { @@ -60,21 +64,18 @@ void QTouchEventSenderQPA::touch_configure(int x_min, int x_max, int y_min, int void QTouchEventSenderQPA::touch_point(QEvent::Type state, const QList &points) { -#ifdef FORCE_TO_ACTIVE_WINDOW - QWidget *win = QApplication::activeWindow(); // ### migrate to QWindow later on - if (!win) { -#ifdef POINT_DEBUG - qDebug("sendTouchEvent: No active window"); -#endif - return; + QRect winRect; + if (m_forceToActiveWindow) { + QWidget *win = QApplication::activeWindow(); // ### migrate to QWindow later on + if (!win) + return; + winRect = win->geometry(); + } else { + winRect = QApplication::desktop()->screenGeometry(); } - const QRect winRect = win->geometry(); -#else - const QRect winRect = QApplication::desktop()->screenGeometry(); -#endif #ifdef POINT_DEBUG - qDebug() << points.size() << "points" << winRect << state; + qDebug() << "QPA: Mapping" << points.size() << "points to" << winRect << state; #endif QList touchPoints = points; diff --git a/src/plugins/generic/touchscreen/qtoucheventsenderqpa.h b/src/plugins/generic/touchscreen/qtoucheventsenderqpa.h index 68d621a4e5..91a6b4f3bb 100644 --- a/src/plugins/generic/touchscreen/qtoucheventsenderqpa.h +++ b/src/plugins/generic/touchscreen/qtoucheventsenderqpa.h @@ -51,10 +51,12 @@ QT_BEGIN_NAMESPACE class QTouchEventSenderQPA : public QTouchScreenObserver { public: + QTouchEventSenderQPA(const QString &spec = QString()); void touch_configure(int x_min, int x_max, int y_min, int y_max); void touch_point(QEvent::Type state, const QList &points); private: + bool m_forceToActiveWindow; int hw_range_x_min; int hw_range_x_max; int hw_range_y_min; diff --git a/src/plugins/generic/touchscreen/qtouchscreen.cpp b/src/plugins/generic/touchscreen/qtouchscreen.cpp index 2bbed6a62f..2a56ac3451 100644 --- a/src/plugins/generic/touchscreen/qtouchscreen.cpp +++ b/src/plugins/generic/touchscreen/qtouchscreen.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -58,9 +59,9 @@ QT_BEGIN_NAMESPACE class QTouchScreenData { public: - QTouchScreenData(QTouchScreenHandler *q_ptr); + QTouchScreenData(QTouchScreenHandler *q_ptr, const QStringList &args); - void handle(input_event *data); + void processInputEvent(input_event *data); QTouchScreenHandler *q; QEvent::Type m_state; @@ -78,6 +79,8 @@ public: QMap m_slots; QMap m_lastReport; int m_currentSlot; + QTimer m_clearTimer; + bool m_clearTimerEnabled; int hw_range_x_min; int hw_range_x_max; @@ -88,7 +91,7 @@ public: QList m_observers; }; -QTouchScreenData::QTouchScreenData(QTouchScreenHandler *q_ptr) +QTouchScreenData::QTouchScreenData(QTouchScreenHandler *q_ptr, const QStringList &args) : q(q_ptr), m_state(QEvent::TouchBegin), m_prevState(m_state), @@ -96,6 +99,15 @@ QTouchScreenData::QTouchScreenData(QTouchScreenHandler *q_ptr) hw_range_x_min(0), hw_range_x_max(0), hw_range_y_min(0), hw_range_y_max(0) { + m_clearTimerEnabled = !args.contains(QLatin1String("no_timeout")); + if (m_clearTimerEnabled) { + QObject::connect(&m_clearTimer, SIGNAL(timeout()), q, SLOT(onTimeout())); + m_clearTimer.setSingleShot(true); + m_clearTimer.setInterval(2000); // default timeout is 2 seconds + for (int i = 0; i < args.count(); ++i) + if (args.at(i).startsWith(QLatin1String("timeout="))) + m_clearTimer.setInterval(args.at(i).mid(8).toInt()); + } } QTouchScreenHandler::QTouchScreenHandler(const QString &spec) @@ -130,7 +142,7 @@ QTouchScreenHandler::QTouchScreenHandler(const QString &spec) return; } - d = new QTouchScreenData(this); + d = new QTouchScreenData(this, args); input_absinfo absInfo; memset(&absInfo, 0, sizeof(input_absinfo)); @@ -203,12 +215,25 @@ void QTouchScreenHandler::readData() } else if (n > 0) { for (int i = 0; i < n; ++i) { input_event *data = &buffer[i]; - d->handle(data); + d->processInputEvent(data); } } } -void QTouchScreenData::handle(input_event *data) +void QTouchScreenHandler::onTimeout() +{ +#ifdef POINT_DEBUG + qDebug("TIMEOUT (%d slots)", d->m_slots.count()); +#endif + d->m_slots.clear(); + if (d->m_state != QEvent::TouchEnd) + for (int i = 0; i < d->m_observers.count(); ++i) + d->m_observers.at(i)->touch_point(QEvent::TouchEnd, + QList()); + d->m_state = QEvent::TouchBegin; +} + +void QTouchScreenData::processInputEvent(input_event *data) { if (data->type == EV_ABS) { if (data->code == ABS_MT_POSITION_X) { @@ -233,6 +258,8 @@ void QTouchScreenData::handle(input_event *data) m_slots[m_currentSlot].state = Qt::TouchPointReleased; } } else if (data->type == EV_SYN && data->code == SYN_REPORT) { + if (m_clearTimerEnabled) + m_clearTimer.stop(); m_touchPoints.clear(); QList keys = m_slots.keys(); int ignoredSlotCount = 0; @@ -270,10 +297,6 @@ void QTouchScreenData::handle(input_event *data) } } - // ### TODO Add timestamps and remove points that stay unchanged for too long. - // The user's finger may fall off the touchscreen, which means there will be - // no released event sent ever for that particular point. - #ifdef POINT_DEBUG qDebug() << m_touchPoints.count() << "touchpoints, event type" << m_state; for (int i = 0; i < m_touchPoints.count(); ++i) @@ -294,6 +317,13 @@ void QTouchScreenData::handle(input_event *data) m_state = QEvent::TouchUpdate; else if (m_state == QEvent::TouchEnd) m_state = QEvent::TouchBegin; + + // The user's finger may fall off the touchscreen which in some rare + // cases may mean there will be no released event ever received for that + // particular point. Use a timer to clear all points when no activity + // occurs for a certain period of time. + if (m_clearTimerEnabled && m_state != QEvent::TouchBegin) + m_clearTimer.start(); } } diff --git a/src/plugins/generic/touchscreen/qtouchscreen.h b/src/plugins/generic/touchscreen/qtouchscreen.h index 915a213d41..80a6d3ac58 100644 --- a/src/plugins/generic/touchscreen/qtouchscreen.h +++ b/src/plugins/generic/touchscreen/qtouchscreen.h @@ -75,6 +75,7 @@ public: private slots: void readData(); + void onTimeout(); private: void try_udev(QString *path);