From 8a83a6fef56abc20e79b2ea4c1e307c5f9528a8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Fri, 5 Aug 2016 14:35:33 +0200 Subject: [PATCH] [libinput] Add support for gesture events Summary: Gesture events are swipe or pinch events on a touch pad. This change implements basic support by: * wrapping them in LibInput::Event * processing them in LibInput::Connection and emitting dedicated signals * Forwarding them in InputRedirection to PointerInputRedirection * Support them in the internal input event filter * Printing debug information in DebugConsole Further handling is not yet done. In future the following should be implemented: * activating e.g. zoom and present windows on pinch/swipe gesture * forwarding non global gestures to KWayland Note that forwarding to KWayland is not yet useful as QtWayland does not yet have support for the unstable protocol. No Qt application could make use of it yet. So for the moment just global gestures is the best we can get. Test Plan: Looked at output of DebugConsole when triggering gestures Reviewers: #kwin, #plasma_on_wayland Subscribers: plasma-devel, kwin Tags: #plasma_on_wayland, #kwin Differential Revision: https://phabricator.kde.org/D2359 --- autotests/libinput/CMakeLists.txt | 14 ++ autotests/libinput/gesture_event_test.cpp | 214 ++++++++++++++++++++++ autotests/libinput/mock_libinput.cpp | 68 +++++++ autotests/libinput/mock_libinput.h | 8 + debug_console.cpp | 112 +++++++++++ debug_console.h | 10 + input.cpp | 62 +++++++ input.h | 10 + libinput/connection.cpp | 38 ++++ libinput/connection.h | 8 + libinput/events.cpp | 61 ++++++ libinput/events.h | 41 +++++ pointer_input.cpp | 120 ++++++++++++ pointer_input.h | 32 ++++ 14 files changed, 798 insertions(+) create mode 100644 autotests/libinput/gesture_event_test.cpp diff --git a/autotests/libinput/CMakeLists.txt b/autotests/libinput/CMakeLists.txt index bd92fdf0a7..dc7a1b2901 100644 --- a/autotests/libinput/CMakeLists.txt +++ b/autotests/libinput/CMakeLists.txt @@ -51,6 +51,20 @@ target_link_libraries( testLibinputTouchEvent Qt5::Test Qt5::Widgets KF5::Config add_test(kwin-testLibinputTouchEvent testLibinputTouchEvent) ecm_mark_as_test(testLibinputTouchEvent) +######################################################## +# Test Gesture Event +######################################################## +set( testLibinputGestureEvent_SRCS + gesture_event_test.cpp + mock_libinput.cpp + ../../libinput/device.cpp + ../../libinput/events.cpp + ) +add_executable(testLibinputGestureEvent ${testLibinputGestureEvent_SRCS}) +target_link_libraries( testLibinputGestureEvent Qt5::Test Qt5::Widgets KF5::ConfigCore) +add_test(kwin-testLibinputGestureEvent testLibinputGestureEvent) +ecm_mark_as_test(testLibinputGestureEvent) + ######################################################## # Test Context ######################################################## diff --git a/autotests/libinput/gesture_event_test.cpp b/autotests/libinput/gesture_event_test.cpp new file mode 100644 index 0000000000..fe7e511537 --- /dev/null +++ b/autotests/libinput/gesture_event_test.cpp @@ -0,0 +1,214 @@ +/******************************************************************** +KWin - the KDE window manager +This file is part of the KDE project. + +Copyright (C) 2016 Martin Gräßlin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#include "mock_libinput.h" +#include "../../libinput/device.h" +#include "../../libinput/events.h" + +#include + +#include + +Q_DECLARE_METATYPE(libinput_event_type) + +using namespace KWin::LibInput; + +class TestLibinputGestureEvent : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void init(); + void cleanup(); + + void testType_data(); + void testType(); + + void testStart_data(); + void testStart(); + + void testSwipeUpdate(); + void testPinchUpdate(); + + void testEnd_data(); + void testEnd(); + +private: + libinput_device *m_nativeDevice = nullptr; + Device *m_device = nullptr; +}; + +void TestLibinputGestureEvent::init() +{ + m_nativeDevice = new libinput_device; + m_nativeDevice->pointer = true; + m_nativeDevice->gestureSupported = true; + m_nativeDevice->deviceSize = QSizeF(12.5, 13.8); + m_device = new Device(m_nativeDevice); +} + +void TestLibinputGestureEvent::cleanup() +{ + delete m_device; + m_device = nullptr; + + delete m_nativeDevice; + m_nativeDevice = nullptr; +} + +void TestLibinputGestureEvent::testType_data() +{ + QTest::addColumn("type"); + + QTest::newRow("pinch-start") << LIBINPUT_EVENT_GESTURE_PINCH_BEGIN; + QTest::newRow("pinch-update") << LIBINPUT_EVENT_GESTURE_PINCH_UPDATE; + QTest::newRow("pinch-end") << LIBINPUT_EVENT_GESTURE_PINCH_END; + QTest::newRow("swipe-start") << LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN; + QTest::newRow("swipe-update") << LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE; + QTest::newRow("swipe-end") << LIBINPUT_EVENT_GESTURE_SWIPE_END; +} + +void TestLibinputGestureEvent::testType() +{ + // this test verifies the initialization of a PointerEvent and the parent Event class + libinput_event_gesture *gestureEvent = new libinput_event_gesture; + QFETCH(libinput_event_type, type); + gestureEvent->type = type; + gestureEvent->device = m_nativeDevice; + + QScopedPointer event(Event::create(gestureEvent)); + // API of event + QCOMPARE(event->type(), type); + QCOMPARE(event->device(), m_device); + QCOMPARE(event->nativeDevice(), m_nativeDevice); + QCOMPARE((libinput_event*)(*event.data()), gestureEvent); + // verify it's a pointer event + QVERIFY(dynamic_cast(event.data())); + QCOMPARE((libinput_event_gesture*)(*dynamic_cast(event.data())), gestureEvent); +} + +void TestLibinputGestureEvent::testStart_data() +{ + QTest::addColumn("type"); + + QTest::newRow("pinch") << LIBINPUT_EVENT_GESTURE_PINCH_BEGIN; + QTest::newRow("swipe") << LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN; +} + +void TestLibinputGestureEvent::testStart() +{ + libinput_event_gesture *gestureEvent = new libinput_event_gesture; + gestureEvent->device = m_nativeDevice; + QFETCH(libinput_event_type, type); + gestureEvent->type = type; + gestureEvent->fingerCount = 3; + gestureEvent->time = 100u; + + QScopedPointer event(Event::create(gestureEvent)); + auto ge = dynamic_cast(event.data()); + QVERIFY(ge); + QCOMPARE(ge->fingerCount(), gestureEvent->fingerCount); + QVERIFY(!ge->isCancelled()); + QCOMPARE(ge->time(), gestureEvent->time); + QCOMPARE(ge->delta(), QSizeF(0, 0)); + if (ge->type() == LIBINPUT_EVENT_GESTURE_PINCH_BEGIN) { + auto pe = dynamic_cast(event.data()); + QCOMPARE(pe->scale(), 1.0); + QCOMPARE(pe->angleDelta(), 0.0); + } +} + +void TestLibinputGestureEvent::testSwipeUpdate() +{ + libinput_event_gesture *gestureEvent = new libinput_event_gesture; + gestureEvent->device = m_nativeDevice; + gestureEvent->type = LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE; + gestureEvent->fingerCount = 2; + gestureEvent->time = 200u; + gestureEvent->delta = QSizeF(2, 3); + + QScopedPointer event(Event::create(gestureEvent)); + auto se = dynamic_cast(event.data()); + QVERIFY(se); + QCOMPARE(se->fingerCount(), gestureEvent->fingerCount); + QVERIFY(!se->isCancelled()); + QCOMPARE(se->time(), gestureEvent->time); + QCOMPARE(se->delta(), QSizeF(2, 3)); +} + +void TestLibinputGestureEvent::testPinchUpdate() +{ + libinput_event_gesture *gestureEvent = new libinput_event_gesture; + gestureEvent->device = m_nativeDevice; + gestureEvent->type = LIBINPUT_EVENT_GESTURE_PINCH_UPDATE; + gestureEvent->fingerCount = 4; + gestureEvent->time = 600u; + gestureEvent->delta = QSizeF(5, 4); + gestureEvent->scale = 2; + gestureEvent->angleDelta = -30; + + QScopedPointer event(Event::create(gestureEvent)); + auto pe = dynamic_cast(event.data()); + QVERIFY(pe); + QCOMPARE(pe->fingerCount(), gestureEvent->fingerCount); + QVERIFY(!pe->isCancelled()); + QCOMPARE(pe->time(), gestureEvent->time); + QCOMPARE(pe->delta(), QSizeF(5, 4)); + QCOMPARE(pe->scale(), gestureEvent->scale); + QCOMPARE(pe->angleDelta(), gestureEvent->angleDelta); +} + +void TestLibinputGestureEvent::testEnd_data() +{ + QTest::addColumn("type"); + QTest::addColumn("cancelled"); + + QTest::newRow("pinch/not cancelled") << LIBINPUT_EVENT_GESTURE_PINCH_END << false; + QTest::newRow("pinch/cancelled") << LIBINPUT_EVENT_GESTURE_PINCH_END << true; + QTest::newRow("swipe/not cancelled") << LIBINPUT_EVENT_GESTURE_SWIPE_END << false; + QTest::newRow("swipe/cancelled") << LIBINPUT_EVENT_GESTURE_SWIPE_END << true; +} + +void TestLibinputGestureEvent::testEnd() +{ + libinput_event_gesture *gestureEvent = new libinput_event_gesture; + gestureEvent->device = m_nativeDevice; + QFETCH(libinput_event_type, type); + gestureEvent->type = type; + gestureEvent->fingerCount = 4; + QFETCH(bool, cancelled); + gestureEvent->cancelled = cancelled; + gestureEvent->time = 300u; + gestureEvent->scale = 3; + + QScopedPointer event(Event::create(gestureEvent)); + auto ge = dynamic_cast(event.data()); + QVERIFY(ge); + QCOMPARE(ge->fingerCount(), gestureEvent->fingerCount); + QCOMPARE(ge->isCancelled(), cancelled); + QCOMPARE(ge->time(), gestureEvent->time); + QCOMPARE(ge->delta(), QSizeF(0, 0)); + if (ge->type() == LIBINPUT_EVENT_GESTURE_PINCH_END) { + auto pe = dynamic_cast(event.data()); + QCOMPARE(pe->scale(), gestureEvent->scale); + QCOMPARE(pe->angleDelta(), 0.0); + } +} + +QTEST_GUILESS_MAIN(TestLibinputGestureEvent) +#include "gesture_event_test.moc" diff --git a/autotests/libinput/mock_libinput.cpp b/autotests/libinput/mock_libinput.cpp index 93a4870219..6ecb6342f9 100644 --- a/autotests/libinput/mock_libinput.cpp +++ b/autotests/libinput/mock_libinput.cpp @@ -267,6 +267,74 @@ struct libinput_event_touch *libinput_event_get_touch_event(struct libinput_even return nullptr; } +struct libinput_event_gesture *libinput_event_get_gesture_event(struct libinput_event *event) +{ + if (event->type == LIBINPUT_EVENT_GESTURE_PINCH_BEGIN || + event->type == LIBINPUT_EVENT_GESTURE_PINCH_UPDATE || + event->type == LIBINPUT_EVENT_GESTURE_PINCH_END || + event->type == LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN || + event->type == LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE || + event->type == LIBINPUT_EVENT_GESTURE_SWIPE_END) { + return reinterpret_cast(event); + } + return nullptr; +} + +int libinput_event_gesture_get_cancelled(struct libinput_event_gesture *event) +{ + if (event->type == LIBINPUT_EVENT_GESTURE_PINCH_END || event->type == LIBINPUT_EVENT_GESTURE_SWIPE_END) { + return event->cancelled; + } + return 0; +} + +uint32_t libinput_event_gesture_get_time(struct libinput_event_gesture *event) +{ + return event->time; +} + +int libinput_event_gesture_get_finger_count(struct libinput_event_gesture *event) +{ + return event->fingerCount; +} + +double libinput_event_gesture_get_dx(struct libinput_event_gesture *event) +{ + if (event->type == LIBINPUT_EVENT_GESTURE_PINCH_UPDATE || event->type == LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE) { + return event->delta.width(); + } + return 0.0; +} + +double libinput_event_gesture_get_dy(struct libinput_event_gesture *event) +{ + if (event->type == LIBINPUT_EVENT_GESTURE_PINCH_UPDATE || event->type == LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE) { + return event->delta.height(); + } + return 0.0; +} + +double libinput_event_gesture_get_scale(struct libinput_event_gesture *event) +{ + switch (event->type) { + case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN: + return 1.0; + case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE: + case LIBINPUT_EVENT_GESTURE_PINCH_END: + return event->scale; + default: + return 0.0; + } +} + +double libinput_event_gesture_get_angle_delta(struct libinput_event_gesture *event) +{ + if (event->type == LIBINPUT_EVENT_GESTURE_PINCH_UPDATE) { + return event->angleDelta; + } + return 0.0; +} + uint32_t libinput_event_keyboard_get_key(struct libinput_event_keyboard *event) { return event->key; diff --git a/autotests/libinput/mock_libinput.h b/autotests/libinput/mock_libinput.h index 6779dc535f..e57082fb27 100644 --- a/autotests/libinput/mock_libinput.h +++ b/autotests/libinput/mock_libinput.h @@ -87,6 +87,14 @@ struct libinput_event_touch : libinput_event { QPointF absolutePos; }; +struct libinput_event_gesture : libinput_event { + int fingerCount = 0; + bool cancelled = false; + QSizeF delta = QSizeF(0, 0); + qreal scale = 0.0; + qreal angleDelta = 0.0; +}; + struct libinput { int refCount = 1; QByteArray seat; diff --git a/debug_console.cpp b/debug_console.cpp index 53d90c45bb..5d00cf003d 100644 --- a/debug_console.cpp +++ b/debug_console.cpp @@ -334,6 +334,118 @@ bool DebugConsoleFilter::touchUp(quint32 id, quint32 time) return false; } +bool DebugConsoleFilter::pinchGestureBegin(int fingerCount, quint32 time) +{ + QString text = s_hr; + text.append(s_tableStart); + text.append(tableHeaderRow(i18nc("A pinch gesture is started", "Pinch start"))); + text.append(timestampRow(time)); + text.append(tableRow(i18nc("Number of fingers in this pinch gesture", "Finger count"), fingerCount)); + text.append(s_tableEnd); + + m_textEdit->insertHtml(text); + m_textEdit->ensureCursorVisible(); + return false; +} + +bool DebugConsoleFilter::pinchGestureUpdate(qreal scale, qreal angleDelta, const QSizeF &delta, quint32 time) +{ + QString text = s_hr; + text.append(s_tableStart); + text.append(tableHeaderRow(i18nc("A pinch gesture is updated", "Pinch update"))); + text.append(timestampRow(time)); + text.append(tableRow(i18nc("Current scale in pinch gesture", "Scale"), scale)); + text.append(tableRow(i18nc("Current angle in pinch gesture", "Angle delta"), angleDelta)); + text.append(tableRow(i18nc("Current delta in pinch gesture", "Delta x"), delta.width())); + text.append(tableRow(i18nc("Current delta in pinch gesture", "Delta y"), delta.height())); + text.append(s_tableEnd); + + m_textEdit->insertHtml(text); + m_textEdit->ensureCursorVisible(); + return false; +} + +bool DebugConsoleFilter::pinchGestureEnd(quint32 time) +{ + QString text = s_hr; + text.append(s_tableStart); + text.append(tableHeaderRow(i18nc("A pinch gesture ended", "Pinch end"))); + text.append(timestampRow(time)); + text.append(s_tableEnd); + + m_textEdit->insertHtml(text); + m_textEdit->ensureCursorVisible(); + return false; +} + +bool DebugConsoleFilter::pinchGestureCancelled(quint32 time) +{ + QString text = s_hr; + text.append(s_tableStart); + text.append(tableHeaderRow(i18nc("A pinch gesture got cancelled", "Pinch cancelled"))); + text.append(timestampRow(time)); + text.append(s_tableEnd); + + m_textEdit->insertHtml(text); + m_textEdit->ensureCursorVisible(); + return false; +} + +bool DebugConsoleFilter::swipeGestureBegin(int fingerCount, quint32 time) +{ + QString text = s_hr; + text.append(s_tableStart); + text.append(tableHeaderRow(i18nc("A swipe gesture is started", "Swipe start"))); + text.append(timestampRow(time)); + text.append(tableRow(i18nc("Number of fingers in this swipe gesture", "Finger count"), fingerCount)); + text.append(s_tableEnd); + + m_textEdit->insertHtml(text); + m_textEdit->ensureCursorVisible(); + return false; +} + +bool DebugConsoleFilter::swipeGestureUpdate(const QSizeF &delta, quint32 time) +{ + QString text = s_hr; + text.append(s_tableStart); + text.append(tableHeaderRow(i18nc("A swipe gesture is updated", "Swipe update"))); + text.append(timestampRow(time)); + text.append(tableRow(i18nc("Current delta in swipe gesture", "Delta x"), delta.width())); + text.append(tableRow(i18nc("Current delta in swipe gesture", "Delta y"), delta.height())); + text.append(s_tableEnd); + + m_textEdit->insertHtml(text); + m_textEdit->ensureCursorVisible(); + return false; +} + +bool DebugConsoleFilter::swipeGestureEnd(quint32 time) +{ + QString text = s_hr; + text.append(s_tableStart); + text.append(tableHeaderRow(i18nc("A swipe gesture ended", "Swipe end"))); + text.append(timestampRow(time)); + text.append(s_tableEnd); + + m_textEdit->insertHtml(text); + m_textEdit->ensureCursorVisible(); + return false; +} + +bool DebugConsoleFilter::swipeGestureCancelled(quint32 time) +{ + QString text = s_hr; + text.append(s_tableStart); + text.append(tableHeaderRow(i18nc("A swipe gesture got cancelled", "Swipe cancelled"))); + text.append(timestampRow(time)); + text.append(s_tableEnd); + + m_textEdit->insertHtml(text); + m_textEdit->ensureCursorVisible(); + return false; +} + DebugConsole::DebugConsole() : QWidget() , m_ui(new Ui::DebugConsole) diff --git a/debug_console.h b/debug_console.h index f76699a215..1cf9910c3e 100644 --- a/debug_console.h +++ b/debug_console.h @@ -133,6 +133,16 @@ public: bool touchMotion(quint32 id, const QPointF &pos, quint32 time) override; bool touchUp(quint32 id, quint32 time) override; + bool pinchGestureBegin(int fingerCount, quint32 time) override; + bool pinchGestureUpdate(qreal scale, qreal angleDelta, const QSizeF &delta, quint32 time) override; + bool pinchGestureEnd(quint32 time) override; + bool pinchGestureCancelled(quint32 time) override; + + bool swipeGestureBegin(int fingerCount, quint32 time) override; + bool swipeGestureUpdate(const QSizeF &delta, quint32 time) override; + bool swipeGestureEnd(quint32 time) override; + bool swipeGestureCancelled(quint32 time) override; + private: QTextEdit *m_textEdit; }; diff --git a/input.cpp b/input.cpp index 17312c595a..37ab081145 100644 --- a/input.cpp +++ b/input.cpp @@ -106,6 +106,60 @@ bool InputEventFilter::touchUp(quint32 id, quint32 time) return false; } +bool InputEventFilter::pinchGestureBegin(int fingerCount, quint32 time) +{ + Q_UNUSED(fingerCount) + Q_UNUSED(time) + return false; +} + +bool InputEventFilter::pinchGestureUpdate(qreal scale, qreal angleDelta, const QSizeF &delta, quint32 time) +{ + Q_UNUSED(scale) + Q_UNUSED(angleDelta) + Q_UNUSED(delta) + Q_UNUSED(time) + return false; +} + +bool InputEventFilter::pinchGestureEnd(quint32 time) +{ + Q_UNUSED(time) + return false; +} + +bool InputEventFilter::pinchGestureCancelled(quint32 time) +{ + Q_UNUSED(time) + return false; +} + +bool InputEventFilter::swipeGestureBegin(int fingerCount, quint32 time) +{ + Q_UNUSED(fingerCount) + Q_UNUSED(time) + return false; +} + +bool InputEventFilter::swipeGestureUpdate(const QSizeF &delta, quint32 time) +{ + Q_UNUSED(delta) + Q_UNUSED(time) + return false; +} + +bool InputEventFilter::swipeGestureEnd(quint32 time) +{ + Q_UNUSED(time) + return false; +} + +bool InputEventFilter::swipeGestureCancelled(quint32 time) +{ + Q_UNUSED(time) + return false; +} + #if HAVE_INPUT class VirtualTerminalFilter : public InputEventFilter { public: @@ -1134,6 +1188,14 @@ void InputRedirection::setupLibInput() ); connect(conn, &LibInput::Connection::pointerButtonChanged, m_pointer, &PointerInputRedirection::processButton); connect(conn, &LibInput::Connection::pointerAxisChanged, m_pointer, &PointerInputRedirection::processAxis); + connect(conn, &LibInput::Connection::pinchGestureBegin, m_pointer, &PointerInputRedirection::processPinchGestureBegin); + connect(conn, &LibInput::Connection::pinchGestureUpdate, m_pointer, &PointerInputRedirection::processPinchGestureUpdate); + connect(conn, &LibInput::Connection::pinchGestureEnd, m_pointer, &PointerInputRedirection::processPinchGestureEnd); + connect(conn, &LibInput::Connection::pinchGestureCancelled, m_pointer, &PointerInputRedirection::processPinchGestureCancelled); + connect(conn, &LibInput::Connection::swipeGestureBegin, m_pointer, &PointerInputRedirection::processSwipeGestureBegin); + connect(conn, &LibInput::Connection::swipeGestureUpdate, m_pointer, &PointerInputRedirection::processSwipeGestureUpdate); + connect(conn, &LibInput::Connection::swipeGestureEnd, m_pointer, &PointerInputRedirection::processSwipeGestureEnd); + 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) { diff --git a/input.h b/input.h index 2829344a12..f8863a65dd 100644 --- a/input.h +++ b/input.h @@ -288,6 +288,16 @@ public: virtual bool touchDown(quint32 id, const QPointF &pos, quint32 time); virtual bool touchMotion(quint32 id, const QPointF &pos, quint32 time); virtual bool touchUp(quint32 id, quint32 time); + + virtual bool pinchGestureBegin(int fingerCount, quint32 time); + virtual bool pinchGestureUpdate(qreal scale, qreal angleDelta, const QSizeF &delta, quint32 time); + virtual bool pinchGestureEnd(quint32 time); + virtual bool pinchGestureCancelled(quint32 time); + + virtual bool swipeGestureBegin(int fingerCount, quint32 time); + virtual bool swipeGestureUpdate(const QSizeF &delta, quint32 time); + virtual bool swipeGestureEnd(quint32 time); + virtual bool swipeGestureCancelled(quint32 time); }; class InputDeviceHandler : public QObject diff --git a/libinput/connection.cpp b/libinput/connection.cpp index c14b4066ee..08e39aa2b4 100644 --- a/libinput/connection.cpp +++ b/libinput/connection.cpp @@ -369,6 +369,44 @@ void Connection::processEvents() emit touchFrame(event->device()); break; } + case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN: { + PinchGestureEvent *pe = static_cast(event.data()); + emit pinchGestureBegin(pe->fingerCount(), pe->time(), pe->device()); + break; + } + case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE: { + PinchGestureEvent *pe = static_cast(event.data()); + emit pinchGestureUpdate(pe->scale(), pe->angleDelta(), pe->delta(), pe->time(), pe->device()); + break; + } + case LIBINPUT_EVENT_GESTURE_PINCH_END: { + PinchGestureEvent *pe = static_cast(event.data()); + if (pe->isCancelled()) { + emit pinchGestureCancelled(pe->time(), pe->device()); + } else { + emit pinchGestureEnd(pe->time(), pe->device()); + } + break; + } + case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN: { + SwipeGestureEvent *se = static_cast(event.data()); + emit swipeGestureBegin(se->fingerCount(), se->time(), se->device()); + break; + } + case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE: { + SwipeGestureEvent *se = static_cast(event.data()); + emit swipeGestureUpdate(se->delta(), se->time(), se->device()); + break; + } + case LIBINPUT_EVENT_GESTURE_SWIPE_END: { + SwipeGestureEvent *se = static_cast(event.data()); + if (se->isCancelled()) { + emit swipeGestureCancelled(se->time(), se->device()); + } else { + emit swipeGestureEnd(se->time(), se->device()); + } + break; + } default: // nothing break; diff --git a/libinput/connection.h b/libinput/connection.h index f6b3676da8..03996d3fbf 100644 --- a/libinput/connection.h +++ b/libinput/connection.h @@ -99,6 +99,14 @@ Q_SIGNALS: void hasTouchChanged(bool); void deviceAdded(KWin::LibInput::Device *); void deviceRemoved(KWin::LibInput::Device *); + void swipeGestureBegin(int fingerCount, quint32 time, KWin::LibInput::Device *device); + void swipeGestureUpdate(const QSizeF &delta, quint32 time, KWin::LibInput::Device *device); + void swipeGestureEnd(quint32 time, KWin::LibInput::Device *device); + void swipeGestureCancelled(quint32 time, KWin::LibInput::Device *device); + void pinchGestureBegin(int fingerCount, quint32 time, KWin::LibInput::Device *device); + void pinchGestureUpdate(qreal scale, qreal angleDelta, const QSizeF &delta, quint32 time, KWin::LibInput::Device *device); + void pinchGestureEnd(quint32 time, KWin::LibInput::Device *device); + void pinchGestureCancelled(quint32 time, KWin::LibInput::Device *device); void eventsRead(); diff --git a/libinput/events.cpp b/libinput/events.cpp index a9dff4814e..1ebb20359e 100644 --- a/libinput/events.cpp +++ b/libinput/events.cpp @@ -49,6 +49,14 @@ Event *Event::create(libinput_event *event) case LIBINPUT_EVENT_TOUCH_CANCEL: case LIBINPUT_EVENT_TOUCH_FRAME: return new TouchEvent(event, t); + case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN: + case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE: + case LIBINPUT_EVENT_GESTURE_SWIPE_END: + return new SwipeGestureEvent(event, t); + case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN: + case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE: + case LIBINPUT_EVENT_GESTURE_PINCH_END: + return new PinchGestureEvent(event, t); default: return new Event(event, t); } @@ -209,5 +217,58 @@ qint32 TouchEvent::id() const return libinput_event_touch_get_slot(m_touchEvent); } +GestureEvent::GestureEvent(libinput_event *event, libinput_event_type type) + : Event(event, type) + , m_gestureEvent(libinput_event_get_gesture_event(event)) +{ +} + +GestureEvent::~GestureEvent() = default; + +quint32 GestureEvent::time() const +{ + return libinput_event_gesture_get_time(m_gestureEvent); +} + +int GestureEvent::fingerCount() const +{ + return libinput_event_gesture_get_finger_count(m_gestureEvent); +} + +QSizeF GestureEvent::delta() const +{ + return QSizeF(libinput_event_gesture_get_dx(m_gestureEvent), + libinput_event_gesture_get_dy(m_gestureEvent)); +} + +bool GestureEvent::isCancelled() const +{ + return libinput_event_gesture_get_cancelled(m_gestureEvent) != 0; +} + +PinchGestureEvent::PinchGestureEvent(libinput_event *event, libinput_event_type type) + : GestureEvent(event, type) +{ +} + +PinchGestureEvent::~PinchGestureEvent() = default; + +qreal PinchGestureEvent::scale() const +{ + return libinput_event_gesture_get_scale(m_gestureEvent); +} + +qreal PinchGestureEvent::angleDelta() const +{ + return libinput_event_gesture_get_angle_delta(m_gestureEvent); +} + +SwipeGestureEvent::SwipeGestureEvent(libinput_event *event, libinput_event_type type) + : GestureEvent(event, type) +{ +} + +SwipeGestureEvent::~SwipeGestureEvent() = default; + } } diff --git a/libinput/events.h b/libinput/events.h index a20b11da64..bc8baaa7a1 100644 --- a/libinput/events.h +++ b/libinput/events.h @@ -129,6 +129,47 @@ private: libinput_event_touch *m_touchEvent; }; +class GestureEvent : public Event +{ +public: + virtual ~GestureEvent(); + + quint32 time() const; + int fingerCount() const; + + QSizeF delta() const; + + bool isCancelled() const; + + operator libinput_event_gesture*() { + return m_gestureEvent; + } + operator libinput_event_gesture*() const { + return m_gestureEvent; + } + +protected: + GestureEvent(libinput_event *event, libinput_event_type type); + libinput_event_gesture *m_gestureEvent; +}; + +class PinchGestureEvent : public GestureEvent +{ +public: + PinchGestureEvent(libinput_event *event, libinput_event_type type); + virtual ~PinchGestureEvent(); + + qreal scale() const; + qreal angleDelta() const; +}; + +class SwipeGestureEvent : public GestureEvent +{ +public: + SwipeGestureEvent(libinput_event *event, libinput_event_type type); + virtual ~SwipeGestureEvent(); +}; + inline libinput_event_type Event::type() const { diff --git a/pointer_input.cpp b/pointer_input.cpp index ee33624130..3b5df18aee 100644 --- a/pointer_input.cpp +++ b/pointer_input.cpp @@ -231,6 +231,126 @@ void PointerInputRedirection::processAxis(InputRedirection::PointerAxis axis, qr } } +void PointerInputRedirection::processSwipeGestureBegin(int fingerCount, quint32 time, KWin::LibInput::Device *device) +{ + Q_UNUSED(device) + if (!m_inited) { + return; + } + + const auto &filters = m_input->filters(); + for (auto it = filters.begin(), end = filters.end(); it != end; it++) { + if ((*it)->swipeGestureBegin(fingerCount, time)) { + return; + } + } +} + +void PointerInputRedirection::processSwipeGestureUpdate(const QSizeF &delta, quint32 time, KWin::LibInput::Device *device) +{ + Q_UNUSED(device) + if (!m_inited) { + return; + } + + const auto &filters = m_input->filters(); + for (auto it = filters.begin(), end = filters.end(); it != end; it++) { + if ((*it)->swipeGestureUpdate(delta, time)) { + return; + } + } +} + +void PointerInputRedirection::processSwipeGestureEnd(quint32 time, KWin::LibInput::Device *device) +{ + Q_UNUSED(device) + if (!m_inited) { + return; + } + + const auto &filters = m_input->filters(); + for (auto it = filters.begin(), end = filters.end(); it != end; it++) { + if ((*it)->swipeGestureEnd(time)) { + return; + } + } +} + +void PointerInputRedirection::processSwipeGestureCancelled(quint32 time, KWin::LibInput::Device *device) +{ + Q_UNUSED(device) + if (!m_inited) { + return; + } + + const auto &filters = m_input->filters(); + for (auto it = filters.begin(), end = filters.end(); it != end; it++) { + if ((*it)->swipeGestureCancelled(time)) { + return; + } + } +} + +void PointerInputRedirection::processPinchGestureBegin(int fingerCount, quint32 time, KWin::LibInput::Device *device) +{ + Q_UNUSED(device) + if (!m_inited) { + return; + } + + const auto &filters = m_input->filters(); + for (auto it = filters.begin(), end = filters.end(); it != end; it++) { + if ((*it)->pinchGestureBegin(fingerCount, time)) { + return; + } + } +} + +void PointerInputRedirection::processPinchGestureUpdate(qreal scale, qreal angleDelta, const QSizeF &delta, quint32 time, KWin::LibInput::Device *device) +{ + Q_UNUSED(device) + if (!m_inited) { + return; + } + + const auto &filters = m_input->filters(); + for (auto it = filters.begin(), end = filters.end(); it != end; it++) { + if ((*it)->pinchGestureUpdate(scale, angleDelta, delta, time)) { + return; + } + } +} + +void PointerInputRedirection::processPinchGestureEnd(quint32 time, KWin::LibInput::Device *device) +{ + Q_UNUSED(device) + if (!m_inited) { + return; + } + + const auto &filters = m_input->filters(); + for (auto it = filters.begin(), end = filters.end(); it != end; it++) { + if ((*it)->pinchGestureEnd(time)) { + return; + } + } +} + +void PointerInputRedirection::processPinchGestureCancelled(quint32 time, KWin::LibInput::Device *device) +{ + Q_UNUSED(device) + if (!m_inited) { + return; + } + + const auto &filters = m_input->filters(); + for (auto it = filters.begin(), end = filters.end(); it != end; it++) { + if ((*it)->pinchGestureCancelled(time)) { + return; + } + } +} + void PointerInputRedirection::update() { if (!m_inited) { diff --git a/pointer_input.h b/pointer_input.h index fa16c3fb93..e018d56522 100644 --- a/pointer_input.h +++ b/pointer_input.h @@ -86,6 +86,38 @@ public: * @internal */ void processAxis(InputRedirection::PointerAxis axis, qreal delta, uint32_t time, LibInput::Device *device = nullptr); + /** + * @internal + */ + void processSwipeGestureBegin(int fingerCount, quint32 time, KWin::LibInput::Device *device = nullptr); + /** + * @internal + */ + void processSwipeGestureUpdate(const QSizeF &delta, quint32 time, KWin::LibInput::Device *device = nullptr); + /** + * @internal + */ + void processSwipeGestureEnd(quint32 time, KWin::LibInput::Device *device = nullptr); + /** + * @internal + */ + void processSwipeGestureCancelled(quint32 time, KWin::LibInput::Device *device = nullptr); + /** + * @internal + */ + void processPinchGestureBegin(int fingerCount, quint32 time, KWin::LibInput::Device *device = nullptr); + /** + * @internal + */ + void processPinchGestureUpdate(qreal scale, qreal angleDelta, const QSizeF &delta, quint32 time, KWin::LibInput::Device *device = nullptr); + /** + * @internal + */ + void processPinchGestureEnd(quint32 time, KWin::LibInput::Device *device = nullptr); + /** + * @internal + */ + void processPinchGestureCancelled(quint32 time, KWin::LibInput::Device *device = nullptr); private: void updatePosition(const QPointF &pos);