Implement todos in touchscreen generic plug-in.

The patch implements periodic clearing of the point states when no
activity occurs (i.e. no ev_syn is coming at all, meaning that most
probably all the fingers are already up) and also moves the entire
functionality into a separate thread even when used as a plug-in.

Change-Id: Ib1daa738085b61af9b07eb8a284416e5a3fcabe8
Reviewed-on: http://codereview.qt.nokia.com/1744
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Jørgen Lind <jorgen.lind@nokia.com>
This commit is contained in:
Laszlo Agocs 2011-07-18 13:44:47 +03:00 committed by Qt by Nokia
parent 9581c90395
commit ba1b6f16ae
6 changed files with 62 additions and 28 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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<QWindowSystemInterface::TouchPoint> &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<QWindowSystemInterface::TouchPoint> touchPoints = points;

View File

@ -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<QWindowSystemInterface::TouchPoint> &points);
private:
bool m_forceToActiveWindow;
int hw_range_x_min;
int hw_range_x_max;
int hw_range_y_min;

View File

@ -43,6 +43,7 @@
#include <QStringList>
#include <QSocketNotifier>
#include <QtCore/private/qcore_unix_p.h>
#include <QTimer>
#include <QDebug>
#include <libudev.h>
@ -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<int, Slot> m_slots;
QMap<int, QPoint> 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<QTouchScreenObserver *> 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<QWindowSystemInterface::TouchPoint>());
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<int> 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();
}
}

View File

@ -75,6 +75,7 @@ public:
private slots:
void readData();
void onTimeout();
private:
void try_udev(QString *path);