Forward touch events using QWindowSystemInterface API

QWindowSystemInterface is a more appropriate api to send touch events.

BUG: 450441
(cherry picked from commit 1f89b7ca81)
wilder/Plasma/6.2
Vlad Zahorodnii 2 years ago
parent 4ea62b9b4b
commit 33efc38450
  1. 84
      autotests/integration/internal_window.cpp
  2. 71
      src/input.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<KWin::Window *>();
@ -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()

@ -1208,6 +1208,10 @@ public:
InternalWindowEventFilter()
: InputEventFilter(InputFilterOrder::InternalWindow)
{
m_touchDevice = std::make_unique<QPointingDevice>(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<InternalWindow *>(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<InternalWindow *>(input()->touch()->focus())->handle();
QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(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<InternalWindow *>(input()->touch()->focus())->handle();
m_lastGlobalTouchPos = pos;
m_lastLocalTouchPos = pos - QPointF(internal->x(), internal->y());
QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(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<InternalWindow *>(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<InternalWindow *>(input()->touch()->focus())->handle();
QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(internal, m_touchDevice.get(), m_touchPoints, input()->keyboardModifiers());
m_touchPoints.erase(it);
return true;
}
private:
std::unique_ptr<QPointingDevice> m_touchDevice;
QList<QWindowSystemInterface::TouchPoint> m_touchPoints;
QSet<qint32> m_pressedIds;
QPointF m_lastGlobalTouchPos;
QPointF m_lastLocalTouchPos;
};
class MouseWheelAccumulator

Loading…
Cancel
Save