Add protocol type B support to the evdevtouch plugin
authorLaszlo Agocs <laszlo.p.agocs@nokia.com>
Thu, 1 Mar 2012 07:59:33 +0000 (09:59 +0200)
committerQt by Nokia <qt-info@nokia.com>
Fri, 2 Mar 2012 00:06:22 +0000 (01:06 +0100)
Also adds optional support for libmtdev (a helper library which
translates transparently from type A to B when using type A kernel
drivers).

Change-Id: Ic9c065b2fd130e9db2dd07e7dc103e9d45c08c99
Reviewed-by: Samuel Rødal <samuel.rodal@nokia.com>
src/plugins/generic/evdevtouch/README
src/plugins/generic/evdevtouch/evdevtouch.pro
src/plugins/generic/evdevtouch/qevdevtouch.cpp
src/plugins/generic/evdevtouch/qevdevtouch.h

index 4764ef8..119f2a2 100644 (file)
@@ -1,8 +1,14 @@
-Generic plug-in for evdev touch events. (protocol type A)
+Generic plug-in for evdev touch (ABS_MT) events.
+Supports protocol type A & B.
+Type B is supported both directly and via libmtdev.
 
-Tested with the following drivers: bcm5974, hid_magicmouse.
+The protocol type will be detected automatically.
+To enable libmtdev support uncomment the USE_MTDEV define in
+evdevtouch.pro.
 
-To use it, pass -plugin EvdevTouch on the command line.
+Tested with the following kernel drivers: bcm5974, hid_magicmouse.
+
+To use this "driver", pass -plugin EvdevTouch on the command line.
 
 If automatic detection does not work, use -plugin
 EvdevTouch:/dev/input/eventN to explicitly set the device file
index 284f1d1..f9fb4a6 100644 (file)
@@ -15,3 +15,7 @@ QT += core-private platformsupport-private
 
 OTHER_FILES += \
     evdevtouch.json
+
+# DEFINES += USE_MTDEV
+
+contains(DEFINES, USE_MTDEV): LIBS += -lmtdev
index d508c4a..73f253a 100644 (file)
 #include <QtPlatformSupport/private/qudevhelper_p.h>
 #include <linux/input.h>
 
+#ifdef USE_MTDEV
+extern "C" {
+#include <mtdev.h>
+}
+#endif
+
 QT_BEGIN_NAMESPACE
 
+#ifndef ABS_MT_SLOT
+#define ABS_MT_SLOT 0x2f
+#endif
+
 class QTouchScreenData
 {
 public:
@@ -75,8 +85,10 @@ public:
             x(0), y(0), maj(1), pressure(0),
             state(Qt::TouchPointPressed), flags(0) { }
     };
-    QHash<int, Contact> m_contacts, m_lastContacts;
+    QHash<int, Contact> m_contacts; // The key is a tracking id for type A, slot number for type B.
+    QHash<int, Contact> m_lastContacts;
     Contact m_currentData;
+    int m_currentSlot;
 
     int findClosestContact(const QHash<int, Contact> &contacts, int x, int y, int *dist);
     void reportPoints();
@@ -91,11 +103,13 @@ public:
     QString hw_name;
     bool m_forceToActiveWindow;
     QTouchDevice *m_device;
+    bool m_typeB;
 };
 
 QTouchScreenData::QTouchScreenData(QTouchScreenHandler *q_ptr, const QStringList &args)
     : q(q_ptr),
       m_lastEventType(-1),
+      m_currentSlot(0),
       hw_range_x_min(0), hw_range_x_max(0),
       hw_range_y_min(0), hw_range_y_max(0),
       hw_pressure_min(0), hw_pressure_max(0)
@@ -115,8 +129,19 @@ void QTouchScreenData::registerDevice()
     QWindowSystemInterface::registerTouchDevice(m_device);
 }
 
+#define LONG_BITS (sizeof(long) << 3)
+#define NUM_LONGS(bits) (((bits) + LONG_BITS - 1) / LONG_BITS)
+
+static inline bool testBit(long bit, const long *array)
+{
+    return array[bit / LONG_BITS] & (1 << (bit & (LONG_BITS - 1)));
+}
+
 QTouchScreenHandler::QTouchScreenHandler(const QString &spec)
     : m_notify(0), m_fd(-1), d(0)
+#ifdef USE_MTDEV
+      , m_mtdev(0)
+#endif
 {
     setObjectName(QLatin1String("Evdev Touch Handler"));
 
@@ -141,6 +166,16 @@ QTouchScreenHandler::QTouchScreenHandler(const QString &spec)
         return;
     }
 
+#ifdef USE_MTDEV
+    m_mtdev = static_cast<mtdev *>(calloc(1, sizeof(mtdev)));
+    int mtdeverr = mtdev_open(m_mtdev, m_fd);
+    if (mtdeverr) {
+        qWarning("mtdev_open failed: %d", mtdeverr);
+        QT_CLOSE(m_fd);
+        return;
+    }
+#endif
+
     d = new QTouchScreenData(this, args);
 
     input_absinfo absInfo;
@@ -168,11 +203,30 @@ QTouchScreenHandler::QTouchScreenHandler(const QString &spec)
         qDebug("device name: %s", name);
     }
 
+#ifdef USE_MTDEV
+    const char *mtdevStr = "(mtdev)";
+    d->m_typeB = true;
+#else
+    const char *mtdevStr = "";
+    d->m_typeB = false;
+    long absbits[NUM_LONGS(ABS_CNT)];
+    if (ioctl(m_fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits) >= 0)
+        d->m_typeB = testBit(ABS_MT_SLOT, absbits);
+#endif
+    qDebug("Protocol type %c %s", d->m_typeB ? 'B' : 'A', mtdevStr);
+
     d->registerDevice();
 }
 
 QTouchScreenHandler::~QTouchScreenHandler()
 {
+#ifdef USE_MTDEV
+    if (m_mtdev) {
+        mtdev_close(m_mtdev);
+        free(m_mtdev);
+    }
+#endif
+
     if (m_fd >= 0)
         QT_CLOSE(m_fd);
 
@@ -184,8 +238,13 @@ void QTouchScreenHandler::readData()
     ::input_event buffer[32];
     int n = 0;
     for (; ;) {
+#ifdef USE_MTDEV
+        n = mtdev_get(m_mtdev, m_fd, buffer, sizeof(buffer) / sizeof(::input_event));
+        if (n > 0)
+            n *= sizeof(::input_event);
+#else
         n = QT_READ(m_fd, reinterpret_cast<char*>(buffer) + n, sizeof(buffer) - n);
-
+#endif
         if (!n) {
             qWarning("Got EOF from input device");
             return;
@@ -215,16 +274,32 @@ void QTouchScreenData::processInputEvent(input_event *data)
 
         if (data->code == ABS_MT_POSITION_X) {
             m_currentData.x = qBound(hw_range_x_min, data->value, hw_range_x_max);
+            if (m_typeB)
+                m_contacts[m_currentSlot].x = m_currentData.x;
         } else if (data->code == ABS_MT_POSITION_Y) {
             m_currentData.y = qBound(hw_range_y_min, data->value, hw_range_y_max);
+            if (m_typeB)
+                m_contacts[m_currentSlot].y = m_currentData.y;
         } else if (data->code == ABS_MT_TRACKING_ID) {
             m_currentData.trackingId = data->value;
+            if (m_typeB) {
+                if (m_currentData.trackingId == -1)
+                    m_contacts[m_currentSlot].state = Qt::TouchPointReleased;
+                else
+                    m_contacts[m_currentSlot].trackingId = m_currentData.trackingId;
+            }
         } else if (data->code == ABS_MT_TOUCH_MAJOR) {
             m_currentData.maj = data->value;
             if (data->value == 0)
                 m_currentData.state = Qt::TouchPointReleased;
+            if (m_typeB)
+                m_contacts[m_currentSlot].maj = m_currentData.maj;
         } else if (data->code == ABS_PRESSURE) {
             m_currentData.pressure = qBound(hw_pressure_min, data->value, hw_pressure_max);
+            if (m_typeB)
+                m_contacts[m_currentSlot].pressure = m_currentData.pressure;
+        } else if (data->code == ABS_MT_SLOT) {
+            m_currentSlot = data->value;
         }
 
     } else if (data->type == EV_SYN && data->code == SYN_MT_REPORT && m_lastEventType != EV_SYN) {
@@ -254,8 +329,9 @@ void QTouchScreenData::processInputEvent(input_event *data)
             tp.id = contact.trackingId;
             tp.flags = contact.flags;
 
-            if (m_lastContacts.contains(contact.trackingId)) {
-                const Contact &prev(m_lastContacts.value(contact.trackingId));
+            int key = m_typeB ? it.key() : contact.trackingId;
+            if (m_lastContacts.contains(key)) {
+                const Contact &prev(m_lastContacts.value(key));
                 if (contact.state == Qt::TouchPointReleased) {
                     // Copy over the previous values for released points, just in case.
                     contact.x = prev.x;
@@ -269,7 +345,7 @@ void QTouchScreenData::processInputEvent(input_event *data)
 
             // Avoid reporting a contact in released state more than once.
             if (contact.state == Qt::TouchPointReleased
-                    && !m_lastContacts.contains(contact.trackingId)) {
+                    && !m_lastContacts.contains(key)) {
                 it.remove();
                 continue;
             }
@@ -293,7 +369,8 @@ void QTouchScreenData::processInputEvent(input_event *data)
         }
 
         m_lastContacts = m_contacts;
-        m_contacts.clear();
+        if (!m_typeB)
+            m_contacts.clear();
 
         if (!m_touchPoints.isEmpty() && combinedStates != Qt::TouchPointStationary)
             reportPoints();
index 343f638..28a3b21 100644 (file)
@@ -54,6 +54,9 @@ QT_BEGIN_NAMESPACE
 
 class QSocketNotifier;
 class QTouchScreenData;
+#ifdef USE_MTDEV
+struct mtdev;
+#endif
 
 class QTouchScreenHandler : public QObject
 {
@@ -67,11 +70,12 @@ private slots:
     void readData();
 
 private:
-    void pathFromUdev(QString *path);
-
     QSocketNotifier *m_notify;
     int m_fd;
     QTouchScreenData *d;
+#ifdef USE_MTDEV
+    mtdev *m_mtdev;
+#endif
 };
 
 class QTouchScreenHandlerThread : public QThread