diff --git a/autotests/client/test_fake_input.cpp b/autotests/client/test_fake_input.cpp --- a/autotests/client/test_fake_input.cpp +++ b/autotests/client/test_fake_input.cpp @@ -50,6 +50,7 @@ void testPointerButtonLinux(); void testAxis_data(); void testAxis(); + void testTouch(); private: Display *m_display = nullptr; @@ -317,5 +318,73 @@ QCOMPARE(axisSpy.first().at(1).value(), delta); } +void FakeInputTest::testTouch() +{ + QVERIFY(!m_device->isAuthenticated()); + QSignalSpy touchDownSpy(m_device, &FakeInputDevice::touchDownRequested); + QVERIFY(touchDownSpy.isValid()); + QSignalSpy touchMotionSpy(m_device, &FakeInputDevice::touchMotionRequested); + QVERIFY(touchMotionSpy.isValid()); + QSignalSpy touchUpSpy(m_device, &FakeInputDevice::touchUpRequested); + QVERIFY(touchUpSpy.isValid()); + QSignalSpy touchFrameSpy(m_device, &FakeInputDevice::touchFrameRequested); + QVERIFY(touchFrameSpy.isValid()); + QSignalSpy touchCancelSpy(m_device, &FakeInputDevice::touchCancelRequested); + QVERIFY(touchCancelSpy.isValid()); + + // without an authentication we shouldn't get the signals + m_fakeInput->requestTouchDown(0, QPointF(1, 2)); + QVERIFY(!touchDownSpy.wait(100)); + + m_fakeInput->requestTouchMotion(0, QPointF(3, 4)); + QVERIFY(!touchMotionSpy.wait(100)); + + m_fakeInput->requestTouchUp(0); + QVERIFY(!touchUpSpy.wait(100)); + + m_fakeInput->requestTouchDown(1, QPointF(5, 6)); + QVERIFY(!touchDownSpy.wait(100)); + + m_fakeInput->requestTouchFrame(); + QVERIFY(!touchFrameSpy.wait(100)); + + m_fakeInput->requestTouchCancel(); + QVERIFY(!touchCancelSpy.wait(100)); + + // now let's authenticate the interface + m_device->setAuthentication(true); + m_fakeInput->requestTouchDown(0, QPointF(1, 2)); + QVERIFY(touchDownSpy.wait()); + QCOMPARE(touchDownSpy.count(), 1); + QCOMPARE(touchDownSpy.last().at(0).value(), quint32(0)); + QCOMPARE(touchDownSpy.last().at(1).toPointF(), QPointF(1, 2)); + + m_fakeInput->requestTouchMotion(0, QPointF(3, 4)); + QVERIFY(touchMotionSpy.wait()); + QCOMPARE(touchMotionSpy.count(), 1); + QCOMPARE(touchMotionSpy.last().at(0).value(), quint32(0)); + QCOMPARE(touchMotionSpy.last().at(1).toPointF(), QPointF(3, 4)); + + m_fakeInput->requestTouchUp(0); + QVERIFY(touchUpSpy.wait()); + QCOMPARE(touchUpSpy.count(), 1); + QCOMPARE(touchUpSpy.last().at(0).value(), quint32(0)); + + m_fakeInput->requestTouchDown(1, QPointF(5, 6)); + QVERIFY(touchDownSpy.wait()); + QCOMPARE(touchDownSpy.count(), 2); + QCOMPARE(touchDownSpy.last().at(0).value(), quint32(1)); + QCOMPARE(touchDownSpy.last().at(1).toPointF(), QPointF(5, 6)); + + m_fakeInput->requestTouchFrame(); + QVERIFY(touchFrameSpy.wait()); + QCOMPARE(touchFrameSpy.count(), 1); + + m_fakeInput->requestTouchCancel(); + QVERIFY(touchCancelSpy.wait()); + QCOMPARE(touchCancelSpy.count(), 1); +} + + QTEST_GUILESS_MAIN(FakeInputTest) #include "test_fake_input.moc" diff --git a/src/client/fakeinput.h b/src/client/fakeinput.h --- a/src/client/fakeinput.h +++ b/src/client/fakeinput.h @@ -123,6 +123,26 @@ void requestPointerButtonClick(Qt::MouseButton button); void requestPointerButtonClick(quint32 linuxButton); void requestPointerAxis(Qt::Orientation axis, qreal delta); + /** + * @since 5.23 + **/ + void requestTouchDown(quint32 id, const QPointF &pos); + /** + * @since 5.23 + **/ + void requestTouchMotion(quint32 id, const QPointF &pos); + /** + * @since 5.23 + **/ + void requestTouchUp(quint32 id); + /** + * @since 5.23 + **/ + void requestTouchCancel(); + /** + * @since 5.23 + **/ + void requestTouchFrame(); operator org_kde_kwin_fake_input*(); operator org_kde_kwin_fake_input*() const; diff --git a/src/client/fakeinput.cpp b/src/client/fakeinput.cpp --- a/src/client/fakeinput.cpp +++ b/src/client/fakeinput.cpp @@ -21,7 +21,7 @@ #include "event_queue.h" #include "seat.h" #include "wayland_pointer_p.h" - +#include #include #include @@ -171,6 +171,36 @@ org_kde_kwin_fake_input_axis(d->manager, a, wl_fixed_from_double(delta)); } +void FakeInput::requestTouchDown(quint32 id, const QPointF &pos) +{ + Q_ASSERT(d->manager.isValid()); + org_kde_kwin_fake_input_touch_down(d->manager, id, wl_fixed_from_double(pos.x()), wl_fixed_from_double(pos.y())); +} + +void FakeInput::requestTouchMotion(quint32 id, const QPointF &pos) +{ + Q_ASSERT(d->manager.isValid()); + org_kde_kwin_fake_input_touch_motion(d->manager, id, wl_fixed_from_double(pos.x()), wl_fixed_from_double(pos.y())); +} + +void FakeInput::requestTouchUp(quint32 id) +{ + Q_ASSERT(d->manager.isValid()); + org_kde_kwin_fake_input_touch_up(d->manager, id); +} + +void FakeInput::requestTouchCancel() +{ + Q_ASSERT(d->manager.isValid()); + org_kde_kwin_fake_input_touch_cancel(d->manager); +} + +void FakeInput::requestTouchFrame() +{ + Q_ASSERT(d->manager.isValid()); + org_kde_kwin_fake_input_touch_frame(d->manager); +} + FakeInput::operator org_kde_kwin_fake_input*() const { return d->manager; diff --git a/src/client/protocols/fake-input.xml b/src/client/protocols/fake-input.xml --- a/src/client/protocols/fake-input.xml +++ b/src/client/protocols/fake-input.xml @@ -16,7 +16,7 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . ]]> - + This interface allows other processes to provide fake input events. Purpose is on the one hand side to provide testing facilities like XTest on X11. @@ -49,5 +49,39 @@ + + + A client should use this request to send touch down event at specific + co-ordinates. + + + + + + + + A client should use this request to send touch motion to specific position. + + + + + + + + A client should use this request to send touch up event. + + + + + + A client should use this request to cancel the current + touch event. + + + + + A client should use this request to send touch frame event. + + diff --git a/src/client/registry.cpp b/src/client/registry.cpp --- a/src/client/registry.cpp +++ b/src/client/registry.cpp @@ -159,7 +159,7 @@ &Registry::idleRemoved }}, {Registry::Interface::FakeInput, { - 1, + 2, QByteArrayLiteral("org_kde_kwin_fake_input"), &org_kde_kwin_fake_input_interface, &Registry::fakeInputAnnounced, diff --git a/src/server/fakeinput_interface.h b/src/server/fakeinput_interface.h --- a/src/server/fakeinput_interface.h +++ b/src/server/fakeinput_interface.h @@ -125,6 +125,36 @@ * Requests a pointer axis for the given @p orientation by @p delta. **/ void pointerAxisRequested(Qt::Orientation orientation, qreal delta); + /** + * Requests a touch down at @p pos and identified by @p id. + * + * @since 5.23 + **/ + void touchDownRequested(quint32 id, const QPointF &pos); + /** + * Requests a touch motion by @p pos and identified by @p id. + * + * @since 5.23 + **/ + void touchMotionRequested(quint32 id, const QPointF &pos); + /** + * Requests a touch up identified by @p id. + * + * @since 5.23 + **/ + void touchUpRequested(quint32 id); + /** + * Requests a touch cancel event. + * + * @since 5.23 + **/ + void touchCancelRequested(); + /** + * Requests a touch frame event. + * + * @since 5.23 + **/ + void touchFrameRequested(); private: friend class FakeInputInterface; diff --git a/src/server/fakeinput_interface.cpp b/src/server/fakeinput_interface.cpp --- a/src/server/fakeinput_interface.cpp +++ b/src/server/fakeinput_interface.cpp @@ -22,6 +22,7 @@ #include "global_p.h" #include +#include #include #include @@ -43,6 +44,11 @@ static void pointerMotionCallback(wl_client *client, wl_resource *resource, wl_fixed_t delta_x, wl_fixed_t delta_y); static void buttonCallback(wl_client *client, wl_resource *resource, uint32_t button, uint32_t state); static void axisCallback(wl_client *client, wl_resource *resource, uint32_t axis, wl_fixed_t value); + static void touchDownCallback(wl_client *client, wl_resource *resource, quint32 id, wl_fixed_t x, wl_fixed_t y); + static void touchMotionCallback(wl_client *client, wl_resource *resource, quint32 id, wl_fixed_t x, wl_fixed_t y); + static void touchUpCallback(wl_client *client, wl_resource *resource, quint32 id); + static void touchCancelCallback(wl_client *client, wl_resource *resource); + static void touchFrameCallback(wl_client *client, wl_resource *resource); static void unbind(wl_resource *resource); static Private *cast(wl_resource *r) { @@ -67,14 +73,19 @@ FakeInputDevice *q; }; -const quint32 FakeInputInterface::Private::s_version = 1; +const quint32 FakeInputInterface::Private::s_version = 2; #ifndef DOXYGEN_SHOULD_SKIP_THIS const struct org_kde_kwin_fake_input_interface FakeInputInterface::Private::s_interface = { authenticateCallback, pointerMotionCallback, buttonCallback, - axisCallback + axisCallback, + touchDownCallback, + touchMotionCallback, + touchUpCallback, + touchCancelCallback, + touchFrameCallback }; #endif @@ -178,6 +189,56 @@ } } +void FakeInputInterface::Private::touchDownCallback(wl_client *client, wl_resource *resource, quint32 id, wl_fixed_t x, wl_fixed_t y) +{ + Q_UNUSED(client) + FakeInputDevice *d = device(resource); + if (!d || !d->isAuthenticated()) { + return; + } + emit d->touchDownRequested(id, QPointF(wl_fixed_to_double(x), wl_fixed_to_double(y))); +} + +void FakeInputInterface::Private::touchMotionCallback(wl_client *client, wl_resource *resource, quint32 id, wl_fixed_t x, wl_fixed_t y) +{ + Q_UNUSED(client) + FakeInputDevice *d = device(resource); + if (!d || !d->isAuthenticated()) { + return; + } + emit d->touchMotionRequested(id, QPointF(wl_fixed_to_double(x), wl_fixed_to_double(y))); +} + +void FakeInputInterface::Private::touchUpCallback(wl_client *client, wl_resource *resource, quint32 id) +{ + Q_UNUSED(client) + FakeInputDevice *d = device(resource); + if (!d || !d->isAuthenticated()) { + return; + } + emit d->touchUpRequested(id); +} + +void FakeInputInterface::Private::touchCancelCallback(wl_client *client, wl_resource *resource) +{ + Q_UNUSED(client) + FakeInputDevice *d = device(resource); + if (!d || !d->isAuthenticated()) { + return; + } + emit d->touchCancelRequested(); +} + +void FakeInputInterface::Private::touchFrameCallback(wl_client *client, wl_resource *resource) +{ + Q_UNUSED(client) + FakeInputDevice *d = device(resource); + if (!d || !d->isAuthenticated()) { + return; + } + emit d->touchFrameRequested(); +} + FakeInputInterface::FakeInputInterface(Display *display, QObject *parent) : Global(new Private(this, display), parent) {