evdevtablet plugin
authorLaszlo Agocs <laszlo.p.agocs@nokia.com>
Fri, 1 Jun 2012 07:36:51 +0000 (10:36 +0300)
committerQt by Nokia <qt-info@nokia.com>
Mon, 4 Jun 2012 20:29:10 +0000 (22:29 +0200)
Change-Id: Ie8fbaac929180e6d4c626253c4c20d1b3a9083f5
Reviewed-by: Paul Olav Tvete <paul.tvete@nokia.com>
Reviewed-by: Girish Ramakrishnan <girish.1.ramakrishnan@nokia.com>
12 files changed:
src/platformsupport/devicediscovery/qdevicediscovery_p.h
src/platformsupport/devicediscovery/qdevicediscovery_static.cpp
src/platformsupport/devicediscovery/qdevicediscovery_udev.cpp
src/platformsupport/input/evdevtablet/evdevtablet.pri [new file with mode: 0644]
src/platformsupport/input/evdevtablet/qevdevtablet.cpp [new file with mode: 0644]
src/platformsupport/input/evdevtablet/qevdevtablet_p.h [new file with mode: 0644]
src/platformsupport/input/input.pri
src/plugins/generic/evdevtablet/README [new file with mode: 0644]
src/plugins/generic/evdevtablet/evdevtablet.json [new file with mode: 0644]
src/plugins/generic/evdevtablet/evdevtablet.pro [new file with mode: 0644]
src/plugins/generic/evdevtablet/main.cpp [new file with mode: 0644]
src/plugins/generic/generic.pro

index 3bec692..c4b9124 100644 (file)
@@ -72,7 +72,8 @@ public:
         Device_Touchscreen = 0x04,
         Device_Keyboard = 0x08,
         Device_DRM = 0x10,
-        Device_InputMask = Device_Mouse | Device_Touchpad | Device_Touchscreen | Device_Keyboard,
+        Device_Tablet = 0x20,
+        Device_InputMask = Device_Mouse | Device_Touchpad | Device_Touchscreen | Device_Keyboard | Device_Tablet,
         Device_VideoMask = Device_DRM
     };
     Q_DECLARE_FLAGS(QDeviceTypes, QDeviceType)
index 3b6b6f4..2d89493 100644 (file)
@@ -162,6 +162,11 @@ bool QDeviceDiscovery::checkDeviceType(const QString &device)
                         qWarning() << "DeviceDiscovery found touchscreen at" << device;
 #endif
                         ret = true;
+                    } else if ((m_types & Device_Tablet) && (testBit(BTN_STYLUS, bitsKey) || testBit(BTN_TOOL_PEN, bitsKey))) {
+#ifdef QT_QPA_DEVICE_DISCOVERY_DEBUG
+                        qWarning() << "DeviceDiscovery found tablet at" << device;
+#endif
+                        ret = true;
                     }
                 }
             }
index f7fe7cb..eed1221 100644 (file)
@@ -132,6 +132,8 @@ QStringList QDeviceDiscovery::scanConnectedDevices()
         udev_enumerate_add_match_property(ue, "ID_INPUT_TOUCHSCREEN", "1");
     if (m_types & Device_Keyboard)
         udev_enumerate_add_match_property(ue, "ID_INPUT_KEYBOARD", "1");
+    if (m_types & Device_Tablet)
+        udev_enumerate_add_match_property(ue, "ID_INPUT_TABLET", "1");
 
     if (udev_enumerate_scan_devices(ue) != 0) {
 #ifdef QT_QPA_DEVICE_DISCOVERY_DEBUG
@@ -241,6 +243,9 @@ bool QDeviceDiscovery::checkDeviceType(udev_device *dev)
     if ((m_types & Device_Touchscreen) && (qstrcmp(udev_device_get_property_value(dev, "ID_INPUT_TOUCHSCREEN"), "1") == 0))
         return true;
 
+    if ((m_types & Device_Tablet) && (qstrcmp(udev_device_get_property_value(dev, "ID_INPUT_TABLET"), "1") == 0))
+        return true;
+
     if ((m_types & Device_DRM) && (qstrcmp(udev_device_get_subsystem(dev), "drm") == 0))
         return true;
 
diff --git a/src/platformsupport/input/evdevtablet/evdevtablet.pri b/src/platformsupport/input/evdevtablet/evdevtablet.pri
new file mode 100644 (file)
index 0000000..02b04d2
--- /dev/null
@@ -0,0 +1,9 @@
+HEADERS += \
+    $$PWD/qevdevtablet_p.h
+
+SOURCES += \
+    $$PWD/qevdevtablet.cpp
+
+contains(QT_CONFIG, libudev) {
+    LIBS += $$QMAKE_LIBS_LIBUDEV
+}
diff --git a/src/platformsupport/input/evdevtablet/qevdevtablet.cpp b/src/platformsupport/input/evdevtablet/qevdevtablet.cpp
new file mode 100644 (file)
index 0000000..bd513e4
--- /dev/null
@@ -0,0 +1,306 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the plugins module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qevdevtablet_p.h"
+#include <QWindowSystemInterface>
+#include <QStringList>
+#include <QSocketNotifier>
+#include <QGuiApplication>
+#include <QDebug>
+#include <QtCore/private/qcore_unix_p.h>
+#include <QtPlatformSupport/private/qdevicediscovery_p.h>
+#include <linux/input.h>
+
+QT_BEGIN_NAMESPACE
+
+class QEvdevTabletData
+{
+public:
+    QEvdevTabletData(QEvdevTabletHandler *q_ptr);
+    bool queryLimits();
+    void processInputEvent(input_event *ev);
+    void reportProximityEnter();
+    void reportProximityLeave();
+    void report();
+
+    QEvdevTabletHandler *q;
+    QSocketNotifier *notifier;
+    int fd;
+    int lastEventType;
+    QString devName;
+    struct {
+        int x, y, p, d;
+    } minValues, maxValues;
+    struct {
+        int x, y, p, d;
+        bool down, lastReportDown;
+        int tool, lastReportTool;
+        QPointF lastReportPos;
+    } state;
+};
+
+QEvdevTabletData::QEvdevTabletData(QEvdevTabletHandler *q_ptr)
+    : q(q_ptr), notifier(0), fd(-1), lastEventType(0)
+{
+    memset(&minValues, 0, sizeof(minValues));
+    memset(&maxValues, 0, sizeof(maxValues));
+    memset(&state, 0, sizeof(state));
+}
+
+bool QEvdevTabletData::queryLimits()
+{
+    bool ok = true;
+    input_absinfo absInfo;
+    memset(&absInfo, 0, sizeof(input_absinfo));
+    ok &= ioctl(fd, EVIOCGABS(ABS_X), &absInfo) >= 0;
+    if (ok) {
+        minValues.x = absInfo.minimum;
+        maxValues.x = absInfo.maximum;
+        qDebug("evdevtablet: min X: %d max X: %d", minValues.x, maxValues.x);
+    }
+    ok &= ioctl(fd, EVIOCGABS(ABS_Y), &absInfo) >= 0;
+    if (ok) {
+        minValues.y = absInfo.minimum;
+        maxValues.y = absInfo.maximum;
+        qDebug("evdevtablet: min Y: %d max Y: %d", minValues.y, maxValues.y);
+    }
+    if (ioctl(fd, EVIOCGABS(ABS_PRESSURE), &absInfo) >= 0) {
+        minValues.p = absInfo.minimum;
+        maxValues.p = absInfo.maximum;
+        qDebug("evdevtablet: min pressure: %d max pressure: %d", minValues.p, maxValues.p);
+    }
+    if (ioctl(fd, EVIOCGABS(ABS_DISTANCE), &absInfo) >= 0) {
+        minValues.d = absInfo.minimum;
+        maxValues.d = absInfo.maximum;
+        qDebug("evdevtablet: min distance: %d max distance: %d", minValues.d, maxValues.d);
+    }
+    char name[128];
+    if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), name) >= 0) {
+        devName = QString::fromLocal8Bit(name);
+        qDebug("evdevtablet: device name: %s", name);
+    }
+    return ok;
+}
+
+void QEvdevTabletData::processInputEvent(input_event *ev)
+{
+    if (ev->type == EV_ABS) {
+        switch (ev->code) {
+        case ABS_X:
+            state.x = ev->value;
+            break;
+        case ABS_Y:
+            state.y = ev->value;
+            break;
+        case ABS_PRESSURE:
+            state.p = ev->value;
+            break;
+        case ABS_DISTANCE:
+            state.d = ev->value;
+            break;
+        default:
+            break;
+        }
+    } else if (ev->type == EV_KEY) {
+        // code BTN_TOOL_* value 1 -> proximity enter
+        // code BTN_TOOL_* value 0 -> proximity leave
+        // code BTN_TOUCH value 1 -> contact with screen
+        // code BTN_TOUCH value 0 -> no contact
+        switch (ev->code) {
+        case BTN_TOUCH:
+            state.down = ev->value != 0;
+            break;
+        case BTN_TOOL_PEN:
+            state.tool = ev->value ? QTabletEvent::Pen : 0;
+            break;
+        case BTN_TOOL_RUBBER:
+            state.tool = ev->value ? QTabletEvent::Eraser : 0;
+            break;
+        default:
+            break;
+        }
+    } else if (ev->type == EV_SYN && ev->code == SYN_REPORT && lastEventType != ev->type) {
+        report();
+    }
+    lastEventType = ev->type;
+}
+
+void QEvdevTabletData::reportProximityEnter()
+{
+    QWindowSystemInterface::handleTabletEnterProximityEvent(QTabletEvent::Stylus, state.tool, 1);
+}
+
+void QEvdevTabletData::reportProximityLeave()
+{
+    QWindowSystemInterface::handleTabletLeaveProximityEvent(QTabletEvent::Stylus, state.tool, 1);
+}
+
+void QEvdevTabletData::report()
+{
+    if (!state.lastReportTool && state.tool)
+        reportProximityEnter();
+
+    qreal nx = (state.x - minValues.x) / qreal(maxValues.x - minValues.x);
+    qreal ny = (state.y - minValues.y) / qreal(maxValues.y - minValues.y);
+
+    QRect winRect = QGuiApplication::primaryScreen()->geometry();
+    QPointF globalPos(nx * winRect.width(), ny * winRect.height());
+    int pointer = state.tool;
+    // Prevent sending confusing values of 0 when moving the pen outside the active area.
+    if (!state.down && state.lastReportDown) {
+        globalPos = state.lastReportPos;
+        pointer = state.lastReportTool;
+    }
+
+    qreal pressure = (state.p - minValues.p) / qreal(maxValues.p - minValues.p);
+
+    if (state.down || state.lastReportDown) {
+        QWindowSystemInterface::handleTabletEvent(0, state.down, QPointF(), globalPos,
+                                                  QTabletEvent::Stylus, pointer,
+                                                  pressure, 0, 0, 0, 0, 0, 1, qGuiApp->keyboardModifiers());
+    }
+
+    if (state.lastReportTool && !state.tool)
+        reportProximityLeave();
+
+    state.lastReportDown = state.down;
+    state.lastReportTool = state.tool;
+    state.lastReportPos = globalPos;
+}
+
+
+QEvdevTabletHandler::QEvdevTabletHandler(const QString &spec, QObject *parent)
+    : QObject(parent), d(0)
+{
+    setObjectName(QLatin1String("Evdev Tablet Handler"));
+    d = new QEvdevTabletData(this);
+    QString dev;
+    QStringList args = spec.split(QLatin1Char(':'));
+    for (int i = 0; i < args.count(); ++i) {
+        if (args.at(i).startsWith(QLatin1String("/dev/"))) {
+            dev = args.at(i);
+            break;
+        }
+    }
+    if (dev.isEmpty()) {
+        QScopedPointer<QDeviceDiscovery> deviceDiscovery(
+                    QDeviceDiscovery::create(QDeviceDiscovery::Device_Tablet, this));
+        if (deviceDiscovery) {
+            QStringList devices = deviceDiscovery->scanConnectedDevices();
+            if (!devices.isEmpty())
+                dev = devices.at(0);
+        }
+    }
+    if (!dev.isEmpty()) {
+        qDebug("evdevtablet: using %s", qPrintable(dev));
+        d->fd = QT_OPEN(dev.toLocal8Bit().constData(), O_RDONLY | O_NDELAY, 0);
+        if (d->fd >= 0 && d->queryLimits()) {
+            d->notifier = new QSocketNotifier(d->fd, QSocketNotifier::Read, this);
+            connect(d->notifier, SIGNAL(activated(int)), this, SLOT(readData()));
+        }
+    }
+}
+
+QEvdevTabletHandler::~QEvdevTabletHandler()
+{
+    delete d->notifier;
+    if (d->fd >= 0)
+        QT_CLOSE(d->fd);
+
+    delete d;
+}
+
+void QEvdevTabletHandler::readData()
+{
+    static input_event buffer[32];
+    int n = 0;
+    for (; ;) {
+        int result = QT_READ(d->fd, reinterpret_cast<char*>(buffer) + n, sizeof(buffer) - n);
+        if (!result) {
+            qWarning("evdevtablet: Got EOF from input device");
+            return;
+        } else if (result < 0) {
+            if (errno != EINTR && errno != EAGAIN) {
+                qErrnoWarning(errno, "evdevtablet: Could not read from input device");
+                if (errno == ENODEV) { // device got disconnected -> stop reading
+                    delete d->notifier;
+                    d->notifier = 0;
+                    QT_CLOSE(d->fd);
+                    d->fd = -1;
+                }
+                return;
+            }
+        } else {
+            n += result;
+            if (n % sizeof(input_event) == 0)
+                break;
+        }
+    }
+
+    n /= sizeof(input_event);
+
+    for (int i = 0; i < n; ++i)
+        d->processInputEvent(&buffer[i]);
+}
+
+
+QEvdevTabletHandlerThread::QEvdevTabletHandlerThread(const QString &spec, QObject *parent)
+    : QThread(parent), m_spec(spec), m_handler(0)
+{
+    start();
+}
+
+QEvdevTabletHandlerThread::~QEvdevTabletHandlerThread()
+{
+    quit();
+    wait();
+}
+
+void QEvdevTabletHandlerThread::run()
+{
+    m_handler = new QEvdevTabletHandler(m_spec);
+    exec();
+    delete m_handler;
+    m_handler = 0;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/platformsupport/input/evdevtablet/qevdevtablet_p.h b/src/platformsupport/input/evdevtablet/qevdevtablet_p.h
new file mode 100644 (file)
index 0000000..146394d
--- /dev/null
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the plugins module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QEVDEVTABLET_P_H
+#define QEVDEVTABLET_P_H
+
+#include <QObject>
+#include <QString>
+#include <QThread>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QEvdevTabletData;
+
+class QEvdevTabletHandler : public QObject
+{
+    Q_OBJECT
+
+public:
+    QEvdevTabletHandler(const QString &spec = QString(), QObject *parent = 0);
+    ~QEvdevTabletHandler();
+
+private slots:
+    void readData();
+
+private:
+    QEvdevTabletData *d;
+};
+
+class QEvdevTabletHandlerThread : public QThread
+{
+public:
+    QEvdevTabletHandlerThread(const QString &spec, QObject *parent = 0);
+    ~QEvdevTabletHandlerThread();
+    void run();
+    QEvdevTabletHandler *handler() { return m_handler; }
+
+private:
+    QString m_spec;
+    QEvdevTabletHandler *m_handler;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QEVDEVTABLET_P_H
index f377aea..1524eb4 100644 (file)
@@ -2,5 +2,5 @@ contains(QT_CONFIG, evdev) {
     include($$PWD/evdevmouse/evdevmouse.pri)
     include($$PWD/evdevkeyboard/evdevkeyboard.pri)
     include($$PWD/evdevtouch/evdevtouch.pri)
+    include($$PWD/evdevtablet/evdevtablet.pri)
 }
-
diff --git a/src/plugins/generic/evdevtablet/README b/src/plugins/generic/evdevtablet/README
new file mode 100644 (file)
index 0000000..a7bb481
--- /dev/null
@@ -0,0 +1,44 @@
+Generic plug-in for accessing pen-based tablets via evdev
+
+To test, run the demo app from examples/widgets/tablet with the
+command-line argument -plugin EvdevTablet
+
+Known to work with 3rd generation Wacom Bamboo Pen & Touch. Recent
+tablets like this one may need an updated wacom kernel driver for
+kernels 3.2 and older.
+
+Supports x, y, pressure, pen & eraser pointer types, proximity enter,
+proximity leave. The additional advanced fields of QTabletEvent will
+not be utilized.
+
+Connecting the tablet will result in two input devices: one for finger
+touch and the tablet buttons, and another for pen input including the
+stylus buttons. This plugin cares about the latter only. For touch,
+try the evdevtouch plugin.
+
+The plugin generates QTabletEvents only. For compatibility with Qt 4,
+TabletPress, Move and Release are only sent when the stylus is
+touching the screen.
+
+TabletEnterProximity and TabletLeaveProximity are always sent to the
+QGuiApplication instance. Use an event filter (or subclass) to handle
+these. In proximity events most of the data (incl. position) will be
+left unspecified as these are mere indication of the fact that the
+stylus entered the range of the tablet.
+
+When running under X, it is likely that no events are received due to
+the input device being grabbed. A temporary workaround is to disable
+the device from X via
+xinput set-prop <device> <device enabled property> 0.
+
+
+TODO #1: Indicate motion when lifted but still in proximity. Needs new
+event types.
+
+TODO #1.1: Where to report ABS_DISTANCE? Needs a new QTabletEvent member
+(unless we hijack z).
+
+TODO #2: QKeyEvent from the stylus buttons (BTN_STYLUS, BTN_STYLUS2,
+but there are no suitable Qt::Key_* constants?)
+
+TODO #3: QKeyEvent in evdevtouch (or this plugin?) from tablet buttons
diff --git a/src/plugins/generic/evdevtablet/evdevtablet.json b/src/plugins/generic/evdevtablet/evdevtablet.json
new file mode 100644 (file)
index 0000000..7190668
--- /dev/null
@@ -0,0 +1,3 @@
+{
+    "Keys": [ "EvdevTablet" ]
+}
diff --git a/src/plugins/generic/evdevtablet/evdevtablet.pro b/src/plugins/generic/evdevtablet/evdevtablet.pro
new file mode 100644 (file)
index 0000000..5b5edc2
--- /dev/null
@@ -0,0 +1,13 @@
+TARGET = qevdevtabletplugin
+load(qt_plugin)
+
+DESTDIR = $$QT.gui.plugins/generic
+target.path = $$[QT_INSTALL_PLUGINS]/generic
+INSTALLS += target
+
+SOURCES = main.cpp
+
+QT += core-private platformsupport-private
+
+OTHER_FILES += \
+    evdevtablet.json
diff --git a/src/plugins/generic/evdevtablet/main.cpp b/src/plugins/generic/evdevtablet/main.cpp
new file mode 100644 (file)
index 0000000..9863def
--- /dev/null
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qgenericplugin_qpa.h>
+#include <QtPlatformSupport/private/qevdevtablet_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QEvdevTabletPlugin : public QGenericPlugin
+{
+    Q_OBJECT
+    Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QGenericPluginFactoryInterface" FILE "evdevtablet.json")
+
+public:
+    QEvdevTabletPlugin();
+
+    QStringList keys() const;
+    QObject* create(const QString &key, const QString &specification);
+};
+
+QEvdevTabletPlugin::QEvdevTabletPlugin()
+{
+}
+
+QStringList QEvdevTabletPlugin::keys() const
+{
+    return QStringList() << "EvdevTablet";
+}
+
+QObject *QEvdevTabletPlugin::create(const QString &key,
+                                    const QString &spec)
+{
+    if (!key.compare(QLatin1String("EvdevTablet"), Qt::CaseInsensitive))
+        return new QEvdevTabletHandlerThread(spec);
+
+    return 0;
+}
+
+QT_END_NAMESPACE
+
+#include "main.moc"
index 86b529b..f2e3bd3 100644 (file)
@@ -3,5 +3,5 @@ TEMPLATE = subdirs
 linux-g++-maemo: SUBDIRS += meego
 
 contains(QT_CONFIG, evdev) {
-    SUBDIRS += evdevmouse evdevtouch evdevkeyboard
+    SUBDIRS += evdevmouse evdevtouch evdevkeyboard evdevtablet
 }