webOS: Support mapping evdev keyboard and touchscreen to specific window

First we refactor QTouchOutputMapping into a QOutputMapping base class and
a QDefaultOutputMapping subclass, because it will be used to map more kinds
of devices, not only touchscreens.

On WebOS, the plan is to have a custom subclass that overrides an
additional windowForDeviceNode() virtual function, so that events from
specific devices can be sent to specific windows.  But in the future,
Qt may have a more generic mechanism for mapping devices to screens,
and of course windows are displayed on screens; so this direct
device->window mapping is likely to be temporary.

In the QT_QPA_EGLFS_KMS_CONFIG JSON configuration, symlinked device
nodes are now supported.

Task-number: QTBUG-85268
Change-Id: Id1f0bb59f4a439abaec6bd35016c95de1cbdb26a
Reviewed-by: Elvis Lee <kwangwoong.lee@lge.com>
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
Elvis Lee 2020-09-24 16:54:50 +09:00 committed by Shawn Rutledge
parent fd8e6a203e
commit 4b899a29fa
8 changed files with 104 additions and 31 deletions

View File

@ -91,7 +91,7 @@ qt_internal_extend_target(InputSupport CONDITION QT_FEATURE_evdev OR QT_FEATURE_
SOURCES
shared/devicehandlerlist_p.h
shared/qevdevutil.cpp shared/qevdevutil_p.h
shared/qtouchoutputmapping.cpp shared/qtouchoutputmapping_p.h
shared/qoutputmapping.cpp shared/qoutputmapping_p.h
)
qt_internal_extend_target(InputSupport CONDITION QT_FEATURE_integrityhid

View File

@ -38,6 +38,7 @@
****************************************************************************/
#include "qevdevkeyboardhandler_p.h"
#include "qoutputmapping_p.h"
#include <qplatformdefs.h>
@ -240,7 +241,11 @@ void QEvdevKeyboardHandler::processKeyEvent(int nativecode, int unicode, int qtc
if (!autoRepeat)
QGuiApplicationPrivate::inputDeviceManager()->setKeyboardModifiers(QEvdevKeyboardHandler::toQtModifiers(m_modifiers));
QWindowSystemInterface::handleExtendedKeyEvent(0, (isPress ? QEvent::KeyPress : QEvent::KeyRelease),
QWindow *window = nullptr;
#ifdef Q_OS_WEBOS
window = QOutputMapping::get()->windowForDeviceNode(m_device);
#endif
QWindowSystemInterface::handleExtendedKeyEvent(window, (isPress ? QEvent::KeyPress : QEvent::KeyRelease),
qtcode, modifiers, nativecode + 8, 0, int(modifiers),
(unicode != 0xffff ) ? QString(QChar(unicode)) : QString(), autoRepeat);
}

View File

@ -39,7 +39,7 @@
****************************************************************************/
#include "qevdevtouchhandler_p.h"
#include "qtouchoutputmapping_p.h"
#include "qoutputmapping_p.h"
#include <QStringList>
#include <QHash>
#include <QSocketNotifier>
@ -350,9 +350,9 @@ 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_screenName = mapping.screenNameForDeviceNode(d->deviceNode);
QOutputMapping *mapping = QOutputMapping::get();
d->m_screenName = mapping->screenNameForDeviceNode(d->deviceNode);
if (mapping->load()) {
if (!d->m_screenName.isEmpty())
qCDebug(qLcEvdevTouch, "evdevtouch: Mapping device %ls to screen %ls",
qUtf16Printable(d->deviceNode), qUtf16Printable(d->m_screenName));
@ -728,7 +728,7 @@ QRect QEvdevTouchScreenData::screenGeometry() const
// suddenly it was all broken.
//
// For now we only support the display configuration of the KMS/DRM
// backends of eglfs. See QTouchOutputMapping.
// backends of eglfs. See QOutputMapping.
//
// The good news it that once winRect refers to the correct screen
// geometry in the full virtual desktop space, there is nothing else

View File

@ -38,7 +38,7 @@
****************************************************************************/
#include "qlibinputtouch_p.h"
#include "qtouchoutputmapping_p.h"
#include "qoutputmapping_p.h"
#include <libinput.h>
#include <QtGui/QGuiApplication>
#include <QtGui/QPointingDevice>
@ -68,9 +68,8 @@ QLibInputTouch::DeviceState *QLibInputTouch::deviceState(libinput_event_touch *e
return &m_devState[dev];
}
QPointF QLibInputTouch::getPos(libinput_event_touch *e)
QRect QLibInputTouch::screenGeometry(DeviceState *state)
{
DeviceState *state = deviceState(e);
QScreen *screen = QGuiApplication::primaryScreen();
if (!state->m_screenName.isEmpty()) {
if (!m_screen) {
@ -85,7 +84,13 @@ QPointF QLibInputTouch::getPos(libinput_event_touch *e)
if (m_screen)
screen = m_screen;
}
const QRect geom = QHighDpi::toNativePixels(screen->geometry(), screen);
return QHighDpi::toNativePixels(screen->geometry(), screen);
}
QPointF QLibInputTouch::getPos(libinput_event_touch *e)
{
DeviceState *state = deviceState(e);
QRect geom = screenGeometry(state);
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);
@ -101,19 +106,26 @@ void QLibInputTouch::registerDevice(libinput_device *dev)
qCDebug(qLcLibInput, "libinput: registerDevice %s - %s",
qPrintable(devNode), qPrintable(devName));
QTouchOutputMapping mapping;
if (mapping.load()) {
m_devState[dev].m_screenName = mapping.screenNameForDeviceNode(devNode);
if (!m_devState[dev].m_screenName.isEmpty())
qCDebug(qLcLibInput, "libinput: Mapping device %s to screen %s",
qPrintable(devNode), qPrintable(m_devState[dev].m_screenName));
QOutputMapping *mapping = QOutputMapping::get();
QRect geom;
if (mapping->load()) {
m_devState[dev].m_screenName = mapping->screenNameForDeviceNode(devNode);
if (!m_devState[dev].m_screenName.isEmpty()) {
geom = screenGeometry(&m_devState[dev]);
qCDebug(qLcLibInput) << "libinput: Mapping device" << devNode
<< "to screen" << m_devState[dev].m_screenName
<< "with geometry" << geom;
}
}
QPointingDevice *&td = m_devState[dev].m_touchDevice;
td = new QPointingDevice(devName, udev_device_get_devnum(udev_device),
QInputDevice::DeviceType::TouchScreen, QPointingDevice::PointerType::Finger,
QPointingDevice::Capability::Position | QPointingDevice::Capability::Area, 16, 0);
QPointingDevicePrivate::get(td)->busId = QString::fromLocal8Bit(udev_device_get_syspath(udev_device)); // TODO is that the best to choose?
auto devPriv = QPointingDevicePrivate::get(td);
devPriv->busId = QString::fromLocal8Bit(udev_device_get_syspath(udev_device)); // TODO is that the best to choose?
if (!geom.isNull())
devPriv->setAvailableVirtualGeometry(geom);
QWindowSystemInterface::registerInputDevice(td);
}

View File

@ -83,6 +83,7 @@ private:
};
DeviceState *deviceState(libinput_event_touch *e);
QRect screenGeometry(DeviceState *state);
QPointF getPos(libinput_event_touch *e);
QHash<libinput_device *, DeviceState> m_devState;

View File

@ -37,8 +37,9 @@
**
****************************************************************************/
#include "qtouchoutputmapping_p.h"
#include "qoutputmapping_p.h"
#include <QFile>
#include <QFileInfo>
#include <QVariantMap>
#include <QJsonDocument>
#include <QJsonObject>
@ -46,7 +47,44 @@
QT_BEGIN_NAMESPACE
bool QTouchOutputMapping::load()
static QOutputMapping *s_outputMapping = nullptr;
QOutputMapping *QOutputMapping::get()
{
if (!s_outputMapping)
s_outputMapping = new QDefaultOutputMapping;
return s_outputMapping;
}
bool QOutputMapping::load()
{
return false;
}
QString QOutputMapping::screenNameForDeviceNode(const QString &deviceNode)
{
Q_UNUSED(deviceNode);
return QString();
}
#ifdef Q_OS_WEBOS
QWindow *QOutputMapping::windowForDeviceNode(const QString &deviceNode)
{
Q_UNUSED(deviceNode);
return nullptr;
}
void QOutputMapping::set(QOutputMapping *mapping)
{
if (s_outputMapping)
delete s_outputMapping;
s_outputMapping = mapping;
}
#endif // Q_OS_WEBOS
bool QDefaultOutputMapping::load()
{
static QByteArray configFile = qgetenv("QT_QPA_EGLFS_KMS_CONFIG");
if (configFile.isEmpty())
@ -75,15 +113,15 @@ bool QTouchOutputMapping::load()
qWarning("evdevtouch: Output %d specifies touchDevice but not name, this is wrong", i);
continue;
}
const QString &deviceNode = output.value(QStringLiteral("touchDevice")).toString();
QFileInfo deviceNode(output.value(QStringLiteral("touchDevice")).toString());
const QString &screenName = output.value(QStringLiteral("name")).toString();
m_screenTable.insert(deviceNode, screenName);
m_screenTable.insert(deviceNode.canonicalFilePath(), screenName);
}
return true;
}
QString QTouchOutputMapping::screenNameForDeviceNode(const QString &deviceNode)
QString QDefaultOutputMapping::screenNameForDeviceNode(const QString &deviceNode)
{
return m_screenTable.value(deviceNode);
}

View File

@ -37,8 +37,8 @@
**
****************************************************************************/
#ifndef QTOUCHOUTPUTMAPPING_P_H
#define QTOUCHOUTPUTMAPPING_P_H
#ifndef QOUTPUTMAPPING_P_H
#define QOUTPUTMAPPING_P_H
//
// W A R N I N G
@ -56,11 +56,28 @@
QT_BEGIN_NAMESPACE
class QTouchOutputMapping
class QWindow;
class QOutputMapping
{
public:
bool load();
QString screenNameForDeviceNode(const QString &deviceNode);
virtual ~QOutputMapping() {}
static QOutputMapping *get();
virtual bool load();
virtual QString screenNameForDeviceNode(const QString &deviceNode);
#ifdef Q_OS_WEBOS
virtual QWindow *windowForDeviceNode(const QString &deviceNode);
static void set(QOutputMapping *mapping);
#endif
};
class QDefaultOutputMapping : public QOutputMapping
{
public:
bool load() override;
QString screenNameForDeviceNode(const QString &deviceNode) override;
private:
QHash<QString, QString> m_screenTable;
@ -68,4 +85,4 @@ private:
QT_END_NAMESPACE
#endif // QTOUCHOUTPUTMAPPING_P_H
#endif // QOUTPUTMAPPING_P_H

View File

@ -1,8 +1,8 @@
HEADERS += \
$$PWD/devicehandlerlist_p.h \
$$PWD/qevdevutil_p.h \
$$PWD/qtouchoutputmapping_p.h
$$PWD/qoutputmapping_p.h
SOURCES += \
$$PWD/qevdevutil.cpp \
$$PWD/qtouchoutputmapping.cpp
$$PWD/qoutputmapping.cpp