From cc2f4e324051cfcfe80a282116e0a74233cbc259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Fri, 7 Oct 2016 14:47:25 +0200 Subject: [PATCH] Support for relative pointer motion events Summary: If KWin interacts with Libinput the RelativePointerManager interface gets created on the Wayland server. The ForwardInputEventFilter does forward the relative motion events in addition to the normal motion events. In order to properly support the relative motion events as they are expected by the Wayland protocol the handling of pointer motion events got slightly adjusted: * Libinput Pointer event extended by the additional data points * Libinput Pointer event carries the delta as a QSizeF instead of QPointF * PointerInputRedirection adjusted to take a pointer motion event with more arguments * Custom QMouseEvent subclass adjusted to carry the additional members The DebugConsole is adjusted to show the relative motion events in addition to the global position. Test Plan: Verified the manager object is created and verified the events in DebugConsole. Unfortunately not aware of any test application. Reviewers: #kwin, #plasma_on_wayland Subscribers: plasma-devel, kwin Tags: #plasma_on_wayland, #kwin Differential Revision: https://phabricator.kde.org/D2979 --- autotests/libinput/input_event_test.cpp | 5 ++++- autotests/libinput/mock_libinput.cpp | 15 +++++++++++++++ autotests/libinput/pointer_event_test.cpp | 3 ++- debug_console.cpp | 22 ++++++++++++++++++++-- input.cpp | 19 ++++++++++++++++--- input_event.cpp | 6 +++++- input_event.h | 19 ++++++++++++++++++- libinput/connection.cpp | 8 ++++++-- libinput/connection.h | 2 +- libinput/events.cpp | 15 +++++++++++++-- libinput/events.h | 4 +++- pointer_input.cpp | 10 ++++++++-- pointer_input.h | 4 ++++ tests/libinputtest.cpp | 4 ++-- 14 files changed, 117 insertions(+), 19 deletions(-) diff --git a/autotests/libinput/input_event_test.cpp b/autotests/libinput/input_event_test.cpp index 2b517877c5..f588016f9d 100644 --- a/autotests/libinput/input_event_test.cpp +++ b/autotests/libinput/input_event_test.cpp @@ -58,7 +58,7 @@ void InputEventsTest::testInitMouseEvent() QFETCH(QEvent::Type, type); // now create our own event MouseEvent event(type, QPointF(100, 200), Qt::LeftButton, Qt::LeftButton | Qt::RightButton, - Qt::ShiftModifier | Qt::ControlModifier, 300, &d); + Qt::ShiftModifier | Qt::ControlModifier, 300, QSizeF(1, 2), QSizeF(3, 4), quint64(-1), &d); // and verify the contract of QMouseEvent QCOMPARE(event.type(), type); QCOMPARE(event.globalPos(), QPoint(100, 200)); @@ -70,6 +70,9 @@ void InputEventsTest::testInitMouseEvent() QCOMPARE(event.timestamp(), 300ul); // and our custom argument QCOMPARE(event.device(), &d); + QCOMPARE(event.delta(), QSizeF(1, 2)); + QCOMPARE(event.deltaUnaccelerated(), QSizeF(3, 4)); + QCOMPARE(event.timestampMicroseconds(), quint64(-1)); } void InputEventsTest::testInitKeyEvent_data() diff --git a/autotests/libinput/mock_libinput.cpp b/autotests/libinput/mock_libinput.cpp index 86d3fc153d..271081b1dc 100644 --- a/autotests/libinput/mock_libinput.cpp +++ b/autotests/libinput/mock_libinput.cpp @@ -450,11 +450,26 @@ double libinput_event_pointer_get_dy(struct libinput_event_pointer *event) return event->delta.height(); } +double libinput_event_pointer_get_dx_unaccelerated(struct libinput_event_pointer *event) +{ + return event->delta.width(); +} + +double libinput_event_pointer_get_dy_unaccelerated(struct libinput_event_pointer *event) +{ + return event->delta.height(); +} + uint32_t libinput_event_pointer_get_time(struct libinput_event_pointer *event) { return event->time; } +uint64_t libinput_event_pointer_get_time_usec(struct libinput_event_pointer *event) +{ + return quint64(event->time * 1000); +} + uint32_t libinput_event_pointer_get_button(struct libinput_event_pointer *event) { return event->button; diff --git a/autotests/libinput/pointer_event_test.cpp b/autotests/libinput/pointer_event_test.cpp index b86441da49..03af54da07 100644 --- a/autotests/libinput/pointer_event_test.cpp +++ b/autotests/libinput/pointer_event_test.cpp @@ -128,6 +128,7 @@ void TestLibinputPointerEvent::testButton() QTEST(pe->buttonState(), "expectedButtonState"); QCOMPARE(pe->button(), button); QCOMPARE(pe->time(), time); + QCOMPARE(pe->timeMicroseconds(), quint64(time * 1000)); } void TestLibinputPointerEvent::testAxis_data() @@ -183,7 +184,7 @@ void TestLibinputPointerEvent::testMotion() QVERIFY(pe); QCOMPARE(pe->type(), LIBINPUT_EVENT_POINTER_MOTION); QCOMPARE(pe->time(), 500u); - QCOMPARE(pe->delta(), QPointF(2.1, 4.5)); + QCOMPARE(pe->delta(), QSizeF(2.1, 4.5)); } void TestLibinputPointerEvent::testAbsoluteMotion() diff --git a/debug_console.cpp b/debug_console.cpp index db18569fea..9656754b36 100644 --- a/debug_console.cpp +++ b/debug_console.cpp @@ -68,6 +68,11 @@ static QString timestampRow(quint32 timestamp) return tableRow(i18n("Timestamp"), timestamp); } +static QString timestampRowUsec(quint64 timestamp) +{ + return tableRow(i18n("Timestamp (µsec)"), timestamp); +} + static QString buttonToString(Qt::MouseButton button) { switch (button) { @@ -171,14 +176,27 @@ bool DebugConsoleFilter::pointerEvent(QMouseEvent *event, quint32 nativeButton) text.append(s_tableStart); switch (event->type()) { - case QEvent::MouseMove: + case QEvent::MouseMove: { text.append(tableHeaderRow(i18nc("A mouse pointer motion event", "Pointer Motion"))); + auto e = static_cast(event); #if HAVE_INPUT - text.append(deviceRow(static_cast(event)->device())); + text.append(deviceRow(e->device())); #endif text.append(timestamp); + if (e->timestampMicroseconds() != 0) { + text.append(timestampRowUsec(e->timestampMicroseconds())); + } + if (e->delta() != QSizeF()) { + text.append(tableRow(i18nc("The relative mouse movement", "Delta"), + QStringLiteral("%1/%2").arg(e->delta().width()).arg(e->delta().height()))); + } + if (e->deltaUnaccelerated() != QSizeF()) { + text.append(tableRow(i18nc("The relative mouse movement", "Delta (not accelerated)"), + QStringLiteral("%1/%2").arg(e->deltaUnaccelerated().width()).arg(e->deltaUnaccelerated().height()))); + } text.append(tableRow(i18nc("The global mouse pointer position", "Global Position"), QStringLiteral("%1/%2").arg(event->pos().x()).arg(event->pos().y()))); break; + } case QEvent::MouseButtonPress: text.append(tableHeaderRow(i18nc("A mouse pointer button press event", "Pointer Button Press"))); #if HAVE_INPUT diff --git a/input.cpp b/input.cpp index f9237b58e0..5da10dd44f 100644 --- a/input.cpp +++ b/input.cpp @@ -18,6 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ #include "input.h" +#include "input_event.h" #include "keyboard_input.h" #include "pointer_input.h" #include "touch_input.h" @@ -43,6 +44,7 @@ along with this program. If not, see . #include #include #include +#include #include #include //screenlocker @@ -892,13 +894,18 @@ public: auto seat = waylandServer()->seat(); seat->setTimestamp(event->timestamp()); switch (event->type()) { - case QEvent::MouseMove: + case QEvent::MouseMove: { if (event->buttons() == Qt::NoButton) { // update pointer window only if no button is pressed input()->pointer()->update(); } seat->setPointerPos(event->globalPos()); + MouseEvent *e = static_cast(event); + if (e->delta() != QSizeF()) { + seat->relativePointerMotion(e->delta(), e->deltaUnaccelerated(), e->timestampMicroseconds()); + } break; + } case QEvent::MouseButtonPress: seat->pointerButtonPressed(nativeButton); break; @@ -1232,6 +1239,12 @@ void InputRedirection::setupLibInput() LibInput::Connection *conn = LibInput::Connection::create(this); m_libInput = conn; if (conn) { + + if (waylandServer()) { + // create relative pointer manager + waylandServer()->display()->createRelativePointerManager(KWayland::Server::RelativePointerInterfaceVersion::UnstableV1, waylandServer()->display())->create(); + } + conn->setInputConfig(m_inputConfig); conn->setup(); connect(conn, &LibInput::Connection::eventsRead, this, @@ -1251,8 +1264,8 @@ void InputRedirection::setupLibInput() connect(conn, &LibInput::Connection::swipeGestureCancelled, m_pointer, &PointerInputRedirection::processSwipeGestureCancelled); connect(conn, &LibInput::Connection::keyChanged, m_keyboard, &KeyboardInputRedirection::processKey); connect(conn, &LibInput::Connection::pointerMotion, this, - [this] (QPointF delta, uint32_t time, LibInput::Device *device) { - m_pointer->processMotion(m_pointer->pos() + delta, time, device); + [this] (const QSizeF &delta, const QSizeF &deltaNonAccel, uint32_t time, quint64 timeMicroseconds, LibInput::Device *device) { + m_pointer->processMotion(m_pointer->pos() + QPointF(delta.width(), delta.height()), delta, deltaNonAccel, time, timeMicroseconds, device); } ); connect(conn, &LibInput::Connection::pointerMotionAbsolute, this, diff --git a/input_event.cpp b/input_event.cpp index 87fdb41a56..8de4284597 100644 --- a/input_event.cpp +++ b/input_event.cpp @@ -24,8 +24,12 @@ namespace KWin MouseEvent::MouseEvent(QEvent::Type type, const QPointF &pos, Qt::MouseButton button, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, - quint32 timestamp, LibInput::Device *device) + quint32 timestamp, const QSizeF &delta, const QSizeF &deltaNonAccelerated, + quint64 timestampMicroseconds, LibInput::Device *device) : QMouseEvent(type, pos, pos, button, buttons, modifiers) + , m_delta(delta) + , m_deltaUnccelerated(deltaNonAccelerated) + , m_timestampMicroseconds(timestampMicroseconds) , m_device(device) { setTimestamp(timestamp); diff --git a/input_event.h b/input_event.h index 1203a559aa..bbb845da8b 100644 --- a/input_event.h +++ b/input_event.h @@ -33,13 +33,30 @@ class MouseEvent : public QMouseEvent { public: explicit MouseEvent(QEvent::Type type, const QPointF &pos, Qt::MouseButton button, Qt::MouseButtons buttons, - Qt::KeyboardModifiers modifiers, quint32 timestamp, LibInput::Device *device); + Qt::KeyboardModifiers modifiers, quint32 timestamp, + const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 timestampMicroseconds, + LibInput::Device *device); + + QSizeF delta() const { + return m_delta; + } + + QSizeF deltaUnaccelerated() const { + return m_deltaUnccelerated; + } + + quint64 timestampMicroseconds() const { + return m_timestampMicroseconds; + } LibInput::Device *device() const { return m_device; } private: + QSizeF m_delta; + QSizeF m_deltaUnccelerated; + quint64 m_timestampMicroseconds; LibInput::Device *m_device; }; diff --git a/libinput/connection.cpp b/libinput/connection.cpp index 6831736b30..9cda9c1693 100644 --- a/libinput/connection.cpp +++ b/libinput/connection.cpp @@ -328,20 +328,24 @@ void Connection::processEvents() } case LIBINPUT_EVENT_POINTER_MOTION: { PointerEvent *pe = static_cast(event.data()); - QPointF delta = pe->delta(); + auto delta = pe->delta(); + auto deltaNonAccel = pe->deltaUnaccelerated(); quint32 latestTime = pe->time(); + quint64 latestTimeUsec = pe->timeMicroseconds(); auto it = m_eventQueue.begin(); while (it != m_eventQueue.end()) { if ((*it)->type() == LIBINPUT_EVENT_POINTER_MOTION) { QScopedPointer p(static_cast(*it)); delta += p->delta(); + deltaNonAccel += p->deltaUnaccelerated(); latestTime = p->time(); + latestTimeUsec = p->timeMicroseconds(); it = m_eventQueue.erase(it); } else { break; } } - emit pointerMotion(delta, latestTime, pe->device()); + emit pointerMotion(delta, deltaNonAccel, latestTime, latestTimeUsec, pe->device()); break; } case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: { diff --git a/libinput/connection.h b/libinput/connection.h index 03996d3fbf..4ad0f464e2 100644 --- a/libinput/connection.h +++ b/libinput/connection.h @@ -86,7 +86,7 @@ Q_SIGNALS: void keyChanged(quint32 key, KWin::InputRedirection::KeyboardKeyState, quint32 time, KWin::LibInput::Device *device); void pointerButtonChanged(quint32 button, KWin::InputRedirection::PointerButtonState state, quint32 time, KWin::LibInput::Device *device); void pointerMotionAbsolute(QPointF orig, QPointF screen, quint32 time, KWin::LibInput::Device *device); - void pointerMotion(QPointF delta, quint32 time, KWin::LibInput::Device *device); + void pointerMotion(const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint32 time, quint64 timeMicroseconds, KWin::LibInput::Device *device); void pointerAxisChanged(KWin::InputRedirection::PointerAxis axis, qreal delta, quint32 time, KWin::LibInput::Device *device); void touchFrame(KWin::LibInput::Device *device); void touchCanceled(KWin::LibInput::Device *device); diff --git a/libinput/events.cpp b/libinput/events.cpp index 1ebb20359e..d0539c3d2e 100644 --- a/libinput/events.cpp +++ b/libinput/events.cpp @@ -133,10 +133,16 @@ QPointF PointerEvent::absolutePos(const QSize &size) const libinput_event_pointer_get_absolute_y_transformed(m_pointerEvent, size.height())); } -QPointF PointerEvent::delta() const +QSizeF PointerEvent::delta() const { Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_MOTION); - return QPointF(libinput_event_pointer_get_dx(m_pointerEvent), libinput_event_pointer_get_dy(m_pointerEvent)); + return QSizeF(libinput_event_pointer_get_dx(m_pointerEvent), libinput_event_pointer_get_dy(m_pointerEvent)); +} + +QSizeF PointerEvent::deltaUnaccelerated() const +{ + Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_MOTION); + return QSizeF(libinput_event_pointer_get_dx_unaccelerated(m_pointerEvent), libinput_event_pointer_get_dy_unaccelerated(m_pointerEvent)); } uint32_t PointerEvent::time() const @@ -144,6 +150,11 @@ uint32_t PointerEvent::time() const return libinput_event_pointer_get_time(m_pointerEvent); } +quint64 PointerEvent::timeMicroseconds() const +{ + return libinput_event_pointer_get_time_usec(m_pointerEvent); +} + uint32_t PointerEvent::button() const { Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_BUTTON); diff --git a/libinput/events.h b/libinput/events.h index bc8baaa7a1..646844cb7c 100644 --- a/libinput/events.h +++ b/libinput/events.h @@ -89,10 +89,12 @@ public: QPointF absolutePos() const; QPointF absolutePos(const QSize &size) const; - QPointF delta() const; + QSizeF delta() const; + QSizeF deltaUnaccelerated() const; uint32_t button() const; InputRedirection::PointerButtonState buttonState() const; uint32_t time() const; + quint64 timeMicroseconds() const; QVector axis() const; qreal axisValue(InputRedirection::PointerAxis a) const; diff --git a/pointer_input.cpp b/pointer_input.cpp index 7716a4e61e..c8cd4ce2fe 100644 --- a/pointer_input.cpp +++ b/pointer_input.cpp @@ -161,13 +161,19 @@ void PointerInputRedirection::init() } void PointerInputRedirection::processMotion(const QPointF &pos, uint32_t time, LibInput::Device *device) +{ + processMotion(pos, QSizeF(), QSizeF(), time, 0, device); +} + +void PointerInputRedirection::processMotion(const QPointF &pos, const QSizeF &delta, const QSizeF &deltaNonAccelerated, uint32_t time, quint64 timeUsec, LibInput::Device *device) { if (!m_inited) { return; } updatePosition(pos); MouseEvent event(QEvent::MouseMove, m_pos, Qt::NoButton, m_qtButtons, - m_input->keyboardModifiers(), time, device); + m_input->keyboardModifiers(), time, + delta, deltaNonAccelerated, timeUsec, device); const auto &filters = m_input->filters(); for (auto it = filters.begin(), end = filters.end(); it != end; it++) { @@ -199,7 +205,7 @@ void PointerInputRedirection::processButton(uint32_t button, InputRedirection::P } MouseEvent event(type, m_pos, buttonToQtMouseButton(button), m_qtButtons, - m_input->keyboardModifiers(), time, device); + m_input->keyboardModifiers(), time, QSizeF(), QSizeF(), 0, device); const auto &filters = m_input->filters(); for (auto it = filters.begin(), end = filters.end(); it != end; it++) { diff --git a/pointer_input.h b/pointer_input.h index cd730e9acc..8e40153494 100644 --- a/pointer_input.h +++ b/pointer_input.h @@ -86,6 +86,10 @@ public: * @internal */ void processMotion(const QPointF &pos, uint32_t time, LibInput::Device *device = nullptr); + /** + * @internal + **/ + void processMotion(const QPointF &pos, const QSizeF &delta, const QSizeF &deltaNonAccelerated, uint32_t time, quint64 timeUsec, LibInput::Device *device); /** * @internal */ diff --git a/tests/libinputtest.cpp b/tests/libinputtest.cpp index 3446dc7270..349b6280be 100644 --- a/tests/libinputtest.cpp +++ b/tests/libinputtest.cpp @@ -75,8 +75,8 @@ int main(int argc, char **argv) } ); QObject::connect(conn, &Connection::pointerMotion, - [](QPointF delta) { - std::cout << "Got pointer motion: " << delta.x() << "/" << delta.y() << std::endl; + [](const QSizeF &delta) { + std::cout << "Got pointer motion: " << delta.width() << "/" << delta.height() << std::endl; } ); QObject::connect(conn, &Connection::pointerAxisChanged,