summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2016-08-09 15:48:12 +0200
committerLaszlo Agocs <laszlo.agocs@qt.io>2016-08-11 21:11:43 +0000
commitdfae6a7593a6bb4ad6accc30d6aaf01a98bc2a6f (patch)
tree612de4a8c99bb1a9cfe49e8daf9e6712e1622dbb
parent2afead0211302799519abee5c164ae0602a7e13b (diff)
evdevtouch: Enable touch in multi-screen eglfs environments
Parse the touchDevice property from the KMS/DRM config file. When all outputs have an explicitly specified index in the virtual desktop, we can set up a mapping between the device node and the screen index. It is somewhat fragile (device nodes may change, requires explicit virtualIndex properties for all outputs, etc.) but better than nothing. For example, having the screen on DisplayPort as primary and the touchscreen on HDMI as the secondary screen breaks by default because touching the second screen generates touch (and synthesized mouse) events for the first screen. Assuming the touchscreen is /dev/input/event5, the issue can now be fixed by setting QT_QPA_EGLFS_KMS_CONFIG with a configuration like the following: { "device": "drm-nvdc", "outputs": [ { "name": "HDMI1", "touchDevice": "/dev/input/event5", "virtualIndex": 1 }, { "name": "DP1", "virtualIndex": 0 } ] } Task-number: QTBUG-54151 Change-Id: If97fa18a65599ccfe64ce408ea43086ec3863682 Reviewed-by: Andy Nichols <andy.nichols@qt.io>
-rw-r--r--src/platformsupport/input/evdevtouch/evdevtouch.pri3
-rw-r--r--src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp40
-rw-r--r--src/platformsupport/input/input.pri4
-rw-r--r--src/platformsupport/input/libinput/libinput.pri2
-rw-r--r--src/platformsupport/input/libinput/qlibinputtouch.cpp11
-rw-r--r--src/platformsupport/input/shared/qtouchoutputmapping.cpp91
-rw-r--r--src/platformsupport/input/shared/qtouchoutputmapping_p.h71
-rw-r--r--src/platformsupport/input/shared/shared.pri5
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp3
9 files changed, 221 insertions, 9 deletions
diff --git a/src/platformsupport/input/evdevtouch/evdevtouch.pri b/src/platformsupport/input/evdevtouch/evdevtouch.pri
index c2edc13143..44eb9da113 100644
--- a/src/platformsupport/input/evdevtouch/evdevtouch.pri
+++ b/src/platformsupport/input/evdevtouch/evdevtouch.pri
@@ -6,6 +6,8 @@ SOURCES += \
$$PWD/qevdevtouchhandler.cpp \
$$PWD/qevdevtouchmanager.cpp
+INCLUDEPATH += $$PWD/../shared
+
contains(QT_CONFIG, libudev) {
LIBS_PRIVATE += $$QMAKE_LIBS_LIBUDEV
}
@@ -14,4 +16,3 @@ contains(QT_CONFIG, mtdev) {
CONFIG += link_pkgconfig
PKGCONFIG_PRIVATE += mtdev
}
-
diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp
index 6b98ed30a9..5f9455559d 100644
--- a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp
+++ b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qevdevtouchhandler_p.h"
+#include "qtouchoutputmapping_p.h"
#include <QStringList>
#include <QHash>
#include <QSocketNotifier>
@@ -116,6 +117,7 @@ public:
int findClosestContact(const QHash<int, Contact> &contacts, int x, int y, int *dist);
void addTouchPoint(const Contact &contact, Qt::TouchPointStates *combinedStates);
void reportPoints();
+ void loadMultiScreenMappings();
int hw_range_x_min;
int hw_range_x_max;
@@ -124,10 +126,12 @@ public:
int hw_pressure_min;
int hw_pressure_max;
QString hw_name;
+ QString deviceNode;
bool m_forceToActiveWindow;
bool m_typeB;
QTransform m_rotate;
bool m_singleTouch;
+ int m_screenIndex;
};
QEvdevTouchScreenData::QEvdevTouchScreenData(QEvdevTouchScreenHandler *q_ptr, const QStringList &args)
@@ -137,7 +141,8 @@ QEvdevTouchScreenData::QEvdevTouchScreenData(QEvdevTouchScreenHandler *q_ptr, co
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),
- m_typeB(false), m_singleTouch(false)
+ m_typeB(false), m_singleTouch(false),
+ m_screenIndex(-1)
{
m_forceToActiveWindow = args.contains(QLatin1String("force_window"));
}
@@ -222,7 +227,9 @@ QEvdevTouchScreenHandler::QEvdevTouchScreenHandler(const QString &device, const
}
#endif
- qCDebug(qLcEvdevTouch, "evdevtouch: %s: Protocol type %c %s (%s)", qPrintable(device),
+ d->deviceNode = device;
+
+ qCDebug(qLcEvdevTouch, "evdevtouch: %s: Protocol type %c %s (%s)", qPrintable(d->deviceNode),
d->m_typeB ? 'B' : 'A', mtdevStr, d->m_singleTouch ? "single" : "multi");
input_absinfo absInfo;
@@ -292,6 +299,14 @@ QEvdevTouchScreenHandler::QEvdevTouchScreenHandler(const QString &device, const
if (inverty)
d->m_rotate *= QTransform::fromTranslate(0.5, 0.5).scale(1.0, -1.0).translate(-0.5, -0.5);
+ QTouchOutputMapping mapping;
+ if (mapping.load()) {
+ d->m_screenIndex = mapping.screenIndexForDeviceNode(d->deviceNode);
+ if (d->m_screenIndex >= 0)
+ qCDebug(qLcEvdevTouch, "evdevtouch: Mapping device %s to screen index %d",
+ qPrintable(d->deviceNode), d->m_screenIndex);
+ }
+
registerTouchDevice();
}
@@ -643,8 +658,23 @@ void QEvdevTouchScreenData::reportPoints()
return;
winRect = QHighDpi::toNativePixels(win->geometry(), win);
} else {
- QScreen *primary = QGuiApplication::primaryScreen();
- winRect = QHighDpi::toNativePixels(primary->geometry(), primary);
+ // Now it becomes tricky. Traditionally we picked the primaryScreen()
+ // and were done with it. But then, enter multiple screens, and
+ // suddenly it was all broken.
+ //
+ // For now we only support the display configuration of the KMS/DRM
+ // backends of eglfs. See QTouchOutputMapping.
+ //
+ // The good news it that once winRect refers to the correct screen
+ // geometry in the full virtual desktop space, there is nothing else
+ // left to do since qguiapp will handle the rest.
+ QScreen *screen = QGuiApplication::primaryScreen();
+ if (m_screenIndex >= 0) {
+ const QList<QScreen *> screens = QGuiApplication::screens();
+ if (m_screenIndex < screens.count())
+ screen = screens.at(m_screenIndex);
+ }
+ winRect = QHighDpi::toNativePixels(screen->geometry(), screen);
}
const int hw_w = hw_range_x_max - hw_range_x_min;
@@ -675,10 +705,12 @@ void QEvdevTouchScreenData::reportPoints()
tp.pressure = (tp.pressure - hw_pressure_min) / qreal(hw_pressure_max - hw_pressure_min);
}
+ // Let qguiapp pick the target window.
QWindowSystemInterface::handleTouchEvent(Q_NULLPTR, q->touchDevice(), m_touchPoints);
}
+
QEvdevTouchScreenHandlerThread::QEvdevTouchScreenHandlerThread(const QString &device, const QString &spec, QObject *parent)
: QDaemonThread(parent), m_device(device), m_spec(spec), m_handler(Q_NULLPTR), m_touchDeviceRegistered(false)
{
diff --git a/src/platformsupport/input/input.pri b/src/platformsupport/input/input.pri
index 3b9593eb31..5ce9e6844f 100644
--- a/src/platformsupport/input/input.pri
+++ b/src/platformsupport/input/input.pri
@@ -12,3 +12,7 @@ contains(QT_CONFIG, tslib) {
contains(QT_CONFIG, libinput) {
include($$PWD/libinput/libinput.pri)
}
+
+contains(QT_CONFIG, evdev)|contains(QT_CONFIG, libinput) {
+ include($$PWD/shared/shared.pri)
+}
diff --git a/src/platformsupport/input/libinput/libinput.pri b/src/platformsupport/input/libinput/libinput.pri
index 35d962ff3c..aeba6c725a 100644
--- a/src/platformsupport/input/libinput/libinput.pri
+++ b/src/platformsupport/input/libinput/libinput.pri
@@ -13,6 +13,8 @@ SOURCES += \
INCLUDEPATH += $$QMAKE_INCDIR_LIBUDEV $$QMAKE_INCDIR_LIBINPUT
LIBS_PRIVATE += $$QMAKE_LIBS_LIBUDEV $$QMAKE_LIBS_LIBINPUT
+INCLUDEPATH += $$PWD/../shared
+
contains(QT_CONFIG, xkbcommon-evdev) {
INCLUDEPATH += $$QMAKE_INCDIR_XKBCOMMON_EVDEV
LIBS_PRIVATE += $$QMAKE_LIBS_XKBCOMMON_EVDEV
diff --git a/src/platformsupport/input/libinput/qlibinputtouch.cpp b/src/platformsupport/input/libinput/qlibinputtouch.cpp
index 1e82ce5c91..42925a18e1 100644
--- a/src/platformsupport/input/libinput/qlibinputtouch.cpp
+++ b/src/platformsupport/input/libinput/qlibinputtouch.cpp
@@ -64,11 +64,14 @@ QLibInputTouch::DeviceState *QLibInputTouch::deviceState(libinput_event_touch *e
static inline QPointF getPos(libinput_event_touch *e)
{
+ // TODO Map to correct screen using QTouchOutputMapping.
+ // Perhaps investigate libinput_device_get_output_name as well.
+ // For now just use the primary screen.
QScreen *screen = QGuiApplication::primaryScreen();
- const QSize screenSize = QHighDpi::toNativePixels(screen->geometry().size(), screen);
- const double x = libinput_event_touch_get_x_transformed(e, screenSize.width());
- const double y = libinput_event_touch_get_y_transformed(e, screenSize.height());
- return QPointF(x, y);
+ const QRect geom = QHighDpi::toNativePixels(screen->geometry(), screen);
+ const double x = libinput_event_touch_get_x_transformed(e, geom.width());
+ const double y = libinput_event_touch_get_y_transformed(e, geom.height());
+ return geom.topLeft() + QPointF(x, y);
}
void QLibInputTouch::registerDevice(libinput_device *dev)
diff --git a/src/platformsupport/input/shared/qtouchoutputmapping.cpp b/src/platformsupport/input/shared/qtouchoutputmapping.cpp
new file mode 100644
index 0000000000..55c1dc34f4
--- /dev/null
+++ b/src/platformsupport/input/shared/qtouchoutputmapping.cpp
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtouchoutputmapping_p.h"
+#include <QFile>
+#include <QVariantMap>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QJsonArray>
+
+QT_BEGIN_NAMESPACE
+
+bool QTouchOutputMapping::load()
+{
+ static QByteArray configFile = qgetenv("QT_QPA_EGLFS_KMS_CONFIG");
+ if (configFile.isEmpty())
+ return false;
+
+ QFile file(QString::fromUtf8(configFile));
+ if (!file.open(QFile::ReadOnly)) {
+ qWarning("touch input support: Failed to open %s", configFile.constData());
+ return false;
+ }
+
+ const QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
+ if (!doc.isObject()) {
+ qWarning("touch input support: Failed to parse %s", configFile.constData());
+ return false;
+ }
+
+ // What we are interested is the virtualIndex and touchDevice properties for
+ // each element in the outputs array.
+ const QJsonArray outputs = doc.object().value(QLatin1String("outputs")).toArray();
+ for (int i = 0; i < outputs.size(); ++i) {
+ const QVariantMap output = outputs.at(i).toObject().toVariantMap();
+ if (!output.contains(QStringLiteral("touchDevice")))
+ continue;
+ if (!output.contains(QStringLiteral("virtualIndex"))) {
+ qWarning("evdevtouch: Output %d specifies touchDevice but not virtualIndex, this is wrong", i);
+ continue;
+ }
+ const QString &deviceNode = output.value(QStringLiteral("touchDevice")).toString();
+ const int screenIndex = output.value(QStringLiteral("virtualIndex")).toInt();
+ m_screenIndexTable.insert(deviceNode, screenIndex);
+ }
+
+ return true;
+}
+
+int QTouchOutputMapping::screenIndexForDeviceNode(const QString &deviceNode)
+{
+ return m_screenIndexTable.value(deviceNode, -1);
+}
+
+QT_END_NAMESPACE
diff --git a/src/platformsupport/input/shared/qtouchoutputmapping_p.h b/src/platformsupport/input/shared/qtouchoutputmapping_p.h
new file mode 100644
index 0000000000..74999d93ce
--- /dev/null
+++ b/src/platformsupport/input/shared/qtouchoutputmapping_p.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTOUCHOUTPUTMAPPING_P_H
+#define QTOUCHOUTPUTMAPPING_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QString>
+#include <QHash>
+
+QT_BEGIN_NAMESPACE
+
+class QTouchOutputMapping
+{
+public:
+ bool load();
+ int screenIndexForDeviceNode(const QString &deviceNode);
+
+private:
+ QHash<QString, int> m_screenIndexTable;
+};
+
+QT_END_NAMESPACE
+
+#endif // QTOUCHOUTPUTMAPPING_P_H
diff --git a/src/platformsupport/input/shared/shared.pri b/src/platformsupport/input/shared/shared.pri
new file mode 100644
index 0000000000..1443235244
--- /dev/null
+++ b/src/platformsupport/input/shared/shared.pri
@@ -0,0 +1,5 @@
+HEADERS += \
+ $$PWD/qtouchoutputmapping_p.h
+
+SOURCES += \
+ $$PWD/qtouchoutputmapping.cpp
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp
index 842896bbad..5944e8d51f 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp
@@ -417,6 +417,9 @@ void QEglFSKmsDevice::createScreens()
else
pos.rx() += s->geometry().width();
qCDebug(qLcEglfsKmsDebug) << "Adding screen" << s << "to QPA with geometry" << s->geometry();
+ // The order in qguiapp's screens list will match the order set by
+ // virtualIndex. This is not only handy but also required since for instance
+ // evdevtouch relies on it when performing touch device - screen mapping.
qpaIntegration->addScreen(s);
siblings << s;
}