diff --git a/autotests/integration/internal_window.cpp b/autotests/integration/internal_window.cpp index 1fc3919d0f..614ee5ae4f 100644 --- a/autotests/integration/internal_window.cpp +++ b/autotests/integration/internal_window.cpp @@ -85,6 +85,9 @@ Q_SIGNALS: void wheel(); void keyPressed(); void keyReleased(); + void touchDown(int id, const QPointF &pos); + void touchUp(int id); + void touchMotion(int id, const QPointF &pos); protected: void paintEvent(QPaintEvent *event) override; @@ -95,6 +98,7 @@ protected: void wheelEvent(QWheelEvent *event) override; void keyPressEvent(QKeyEvent *event) override; void keyReleaseEvent(QKeyEvent *event) override; + void touchEvent(QTouchEvent *event) override; private: QPoint m_latestGlobalMousePos; @@ -161,6 +165,28 @@ void HelperWindow::keyReleaseEvent(QKeyEvent *event) Q_EMIT keyReleased(); } +void HelperWindow::touchEvent(QTouchEvent *event) +{ + for (int i = 0; i < event->pointCount(); ++i) { + QEventPoint &point = event->point(i); + + switch (point.state()) { + case QEventPoint::Unknown: + case QEventPoint::Stationary: + break; + case QEventPoint::Pressed: + Q_EMIT touchDown(point.id(), point.position()); + break; + case QEventPoint::Updated: + Q_EMIT touchMotion(point.id(), point.position()); + break; + case QEventPoint::Released: + Q_EMIT touchUp(point.id()); + break; + } + } +} + void InternalWindowTest::initTestCase() { qRegisterMetaType(); @@ -408,56 +434,24 @@ void InternalWindowTest::testTouch() win.show(); QTRY_COMPARE(windowAddedSpy.count(), 1); - QSignalSpy pressSpy(&win, &HelperWindow::mousePressed); - QSignalSpy releaseSpy(&win, &HelperWindow::mouseReleased); - QSignalSpy moveSpy(&win, &HelperWindow::mouseMoved); + QSignalSpy touchDownSpy(&win, &HelperWindow::touchDown); + QSignalSpy touchUpSpy(&win, &HelperWindow::touchUp); + QSignalSpy touchMotionSpy(&win, &HelperWindow::touchMotion); quint32 timestamp = 1; - QCOMPARE(win.pressedButtons(), Qt::MouseButtons()); - Test::touchDown(0, QPointF(50, 50), timestamp++); - QCOMPARE(pressSpy.count(), 1); - QCOMPARE(win.latestGlobalMousePos(), QPoint(50, 50)); - QCOMPARE(win.pressedButtons(), Qt::MouseButtons(Qt::LeftButton)); + Test::touchDown(1, QPointF(50, 50), timestamp++); + QCOMPARE(touchDownSpy.count(), 1); + QCOMPARE(touchDownSpy.last().at(0).toInt(), 1); + QCOMPARE(touchDownSpy.last().at(1).toPointF(), QPointF(50, 50)); - // further touch down should not trigger - Test::touchDown(1, QPointF(75, 75), timestamp++); - QCOMPARE(pressSpy.count(), 1); - Test::touchUp(1, timestamp++); - QCOMPARE(releaseSpy.count(), 0); - QCOMPARE(win.latestGlobalMousePos(), QPoint(50, 50)); - QCOMPARE(win.pressedButtons(), Qt::MouseButtons(Qt::LeftButton)); + Test::touchMotion(1, QPointF(90, 80), timestamp++); + QCOMPARE(touchMotionSpy.count(), 1); + QCOMPARE(touchMotionSpy.last().at(0).toInt(), 1); + QCOMPARE(touchMotionSpy.last().at(1).toPointF(), QPointF(90, 80)); - // another press - Test::touchDown(1, QPointF(10, 10), timestamp++); - QCOMPARE(pressSpy.count(), 1); - QCOMPARE(win.latestGlobalMousePos(), QPoint(50, 50)); - QCOMPARE(win.pressedButtons(), Qt::MouseButtons(Qt::LeftButton)); - - // simulate the move - QCOMPARE(moveSpy.count(), 0); - Test::touchMotion(0, QPointF(80, 90), timestamp++); - QCOMPARE(moveSpy.count(), 1); - QCOMPARE(win.latestGlobalMousePos(), QPoint(80, 90)); - QCOMPARE(win.pressedButtons(), Qt::MouseButtons(Qt::LeftButton)); - - // move on other ID should not do anything - Test::touchMotion(1, QPointF(20, 30), timestamp++); - QCOMPARE(moveSpy.count(), 1); - QCOMPARE(win.latestGlobalMousePos(), QPoint(80, 90)); - QCOMPARE(win.pressedButtons(), Qt::MouseButtons(Qt::LeftButton)); - - // now up our main point - Test::touchUp(0, timestamp++); - QCOMPARE(releaseSpy.count(), 1); - QCOMPARE(win.latestGlobalMousePos(), QPoint(80, 90)); - QCOMPARE(win.pressedButtons(), Qt::MouseButtons()); - - // and up the additional point Test::touchUp(1, timestamp++); - QCOMPARE(releaseSpy.count(), 1); - QCOMPARE(moveSpy.count(), 1); - QCOMPARE(win.latestGlobalMousePos(), QPoint(80, 90)); - QCOMPARE(win.pressedButtons(), Qt::MouseButtons()); + QCOMPARE(touchUpSpy.count(), 1); + QCOMPARE(touchUpSpy.last().at(0).toInt(), 1); } void InternalWindowTest::testOpacity() diff --git a/src/input.cpp b/src/input.cpp index 96d7229121..82000f7129 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -1208,6 +1208,10 @@ public: InternalWindowEventFilter() : InputEventFilter(InputFilterOrder::InternalWindow) { + m_touchDevice = std::make_unique(QLatin1String("some touchscreen"), 0, QInputDevice::DeviceType::TouchScreen, + QPointingDevice::PointerType::Finger, QInputDevice::Capability::Position, + 10, 0, kwinApp()->session()->seat(), QPointingDeviceUniqueId()); + QWindowSystemInterface::registerInputDevice(m_touchDevice.get()); } bool pointerEvent(MouseEvent *event, quint32 nativeButton) override { @@ -1315,19 +1319,23 @@ public: return false; } touch->setInternalPressId(id); - // Qt's touch event API is rather complex, let's do fake mouse events instead - QWindow *internal = static_cast(input()->touch()->focus())->handle(); - m_lastGlobalTouchPos = pos; - m_lastLocalTouchPos = pos - internal->position(); - QEnterEvent enterEvent(m_lastLocalTouchPos, m_lastLocalTouchPos, pos); - QCoreApplication::sendEvent(internal, &enterEvent); + const qreal contactAreaWidth = 8; + const qreal contactAreaHeight = 8; - QMouseEvent e(QEvent::MouseButtonPress, m_lastLocalTouchPos, pos, Qt::LeftButton, Qt::LeftButton, input()->keyboardModifiers()); - e.setAccepted(false); - QCoreApplication::sendEvent(internal, &e); + auto &touchPoint = m_touchPoints.emplaceBack(QWindowSystemInterface::TouchPoint{}); + touchPoint.id = id; + touchPoint.area = QRectF(pos.x() - contactAreaWidth / 2, pos.y() - contactAreaHeight / 2, contactAreaWidth, contactAreaHeight); + touchPoint.state = QEventPoint::State::Pressed; + touchPoint.pressure = 1; + + QWindow *internal = static_cast(input()->touch()->focus())->handle(); + QWindowSystemInterface::handleTouchEvent(internal, m_touchDevice.get(), m_touchPoints, input()->keyboardModifiers()); + + touchPoint.state = QEventPoint::State::Stationary; return true; } + bool touchMotion(qint32 id, const QPointF &pos, std::chrono::microseconds time) override { auto touch = input()->touch(); @@ -1342,12 +1350,21 @@ public: // ignore, but filter out return true; } + + auto it = std::ranges::find_if(m_touchPoints, [id](const auto &touchPoint) { + return touchPoint.id == id; + }); + if (it == m_touchPoints.end()) { + return false; + } + + it->area.moveCenter(pos); + it->state = QEventPoint::State::Updated; + QWindow *internal = static_cast(input()->touch()->focus())->handle(); - m_lastGlobalTouchPos = pos; - m_lastLocalTouchPos = pos - QPointF(internal->x(), internal->y()); + QWindowSystemInterface::handleTouchEvent(internal, m_touchDevice.get(), m_touchPoints, input()->keyboardModifiers()); - QMouseEvent e(QEvent::MouseMove, m_lastLocalTouchPos, m_lastGlobalTouchPos, Qt::LeftButton, Qt::LeftButton, input()->keyboardModifiers()); - QCoreApplication::instance()->sendEvent(internal, &e); + it->state = QEventPoint::State::Stationary; return true; } bool touchUp(qint32 id, std::chrono::microseconds time) override @@ -1365,25 +1382,29 @@ public: if (!input()->touch()->focus() || !input()->touch()->focus()->isInternal()) { return removed; } - QWindow *internal = static_cast(input()->touch()->focus())->handle(); - // send mouse up - QMouseEvent e(QEvent::MouseButtonRelease, m_lastLocalTouchPos, m_lastGlobalTouchPos, Qt::LeftButton, Qt::MouseButtons(), input()->keyboardModifiers()); - e.setAccepted(false); - QCoreApplication::sendEvent(internal, &e); + input()->touch()->setInternalPressId(-1); - QEvent leaveEvent(QEvent::Leave); - QCoreApplication::sendEvent(internal, &leaveEvent); + auto it = std::ranges::find_if(m_touchPoints, [id](const auto &touchPoint) { + return touchPoint.id == id; + }); + if (it == m_touchPoints.end()) { + return false; + } - m_lastGlobalTouchPos = QPointF(); - m_lastLocalTouchPos = QPointF(); - input()->touch()->setInternalPressId(-1); + it->pressure = 0; + it->state = QEventPoint::State::Released; + + QWindow *internal = static_cast(input()->touch()->focus())->handle(); + QWindowSystemInterface::handleTouchEvent(internal, m_touchDevice.get(), m_touchPoints, input()->keyboardModifiers()); + + m_touchPoints.erase(it); return true; } private: + std::unique_ptr m_touchDevice; + QList m_touchPoints; QSet m_pressedIds; - QPointF m_lastGlobalTouchPos; - QPointF m_lastLocalTouchPos; }; class MouseWheelAccumulator