void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) { if (xi2PrepareXIGenericDeviceEvent(event, m_xiOpCode)) { xXIGenericDeviceEvent *xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(event); #ifndef QT_NO_TABLETEVENT for (int i = 0; i < m_tabletData.count(); ++i) { if (m_tabletData.at(i).deviceId == xiEvent->deviceid) { if (xi2HandleTabletEvent(xiEvent, &m_tabletData[i])) return; } } #endif // QT_NO_TABLETEVENT #ifdef XCB_USE_XINPUT22 if (xiEvent->evtype == XI_TouchBegin || xiEvent->evtype == XI_TouchUpdate || xiEvent->evtype == XI_TouchEnd) { xXIDeviceEvent* xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event); #ifdef XI2_TOUCH_DEBUG qDebug("XI2 event type %d seq %d detail %d pos 0x%X,0x%X %f,%f root pos %f,%f", event->event_type, xiEvent->sequenceNumber, xiDeviceEvent->detail, xiDeviceEvent->event_x, xiDeviceEvent->event_y, fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y), fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y) ); #endif if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) { XInput2DeviceData *dev = deviceForId(xiEvent->deviceid); if (xiEvent->evtype == XI_TouchBegin) { QWindowSystemInterface::TouchPoint tp; tp.id = xiDeviceEvent->detail % INT_MAX; tp.state = Qt::TouchPointPressed; tp.pressure = -1.0; m_touchPoints[tp.id] = tp; } QWindowSystemInterface::TouchPoint &touchPoint = m_touchPoints[xiDeviceEvent->detail]; qreal x = fixed1616ToReal(xiDeviceEvent->root_x); qreal y = fixed1616ToReal(xiDeviceEvent->root_y); qreal nx = -1.0, ny = -1.0, w = 0.0, h = 0.0; QXcbScreen* screen = m_screens.at(0); for (int i = 0; i < dev->xiDeviceInfo->num_classes; ++i) { XIAnyClassInfo *classinfo = dev->xiDeviceInfo->classes[i]; if (classinfo->type == XIValuatorClass) { XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(classinfo); int n = vci->number; double value; if (!xi2GetValuatorValueIfSet(xiDeviceEvent, n, &value)) continue; #ifdef XI2_TOUCH_DEBUG qDebug(" valuator class label %d value %lf from range %lf -> %lf name %s", vci->label, value, vci->min, vci->max, XGetAtomName(static_cast<Display *>(m_xlib_display), vci->label) ); #endif if (vci->label == atom(QXcbAtom::AbsMTPositionX)) { nx = valuatorNormalized(value, vci); } else if (vci->label == atom(QXcbAtom::AbsMTPositionY)) { ny = valuatorNormalized(value, vci); } else if (vci->label == atom(QXcbAtom::AbsMTTouchMajor)) { // Convert the value within its range as a fraction of a finger's max (contact patch) // width in mm, and from there to pixels depending on screen resolution w = valuatorNormalized(value, vci) * FINGER_MAX_WIDTH_MM * screen->geometry().width() / screen->physicalSize().width(); } else if (vci->label == atom(QXcbAtom::AbsMTTouchMinor)) { h = valuatorNormalized(value, vci) * FINGER_MAX_WIDTH_MM * screen->geometry().height() / screen->physicalSize().height(); } else if (vci->label == atom(QXcbAtom::AbsMTPressure) || vci->label == atom(QXcbAtom::AbsPressure)) { touchPoint.pressure = valuatorNormalized(value, vci); } } } // If any value was not updated, use the last-known value. if (nx == -1.0) { x = touchPoint.area.center().x(); nx = x / screen->geometry().width(); } if (ny == -1.0) { y = touchPoint.area.center().y(); ny = y / screen->geometry().height(); } if (xiEvent->evtype != XI_TouchEnd) { if (w == 0.0) w = touchPoint.area.width(); if (h == 0.0) h = touchPoint.area.height(); } switch (xiEvent->evtype) { case XI_TouchUpdate: if (touchPoint.area.center() != QPoint(x, y)) touchPoint.state = Qt::TouchPointMoved; else touchPoint.state = Qt::TouchPointStationary; break; case XI_TouchEnd: touchPoint.state = Qt::TouchPointReleased; } touchPoint.area = QRectF(x - w/2, y - h/2, w, h); touchPoint.normalPosition = QPointF(nx, ny); #ifdef XI2_TOUCH_DEBUG qDebug() << " tp " << touchPoint.id << " state " << touchPoint.state << " pos norm " << touchPoint.normalPosition << " area " << touchPoint.area << " pressure " << touchPoint.pressure; #endif QWindowSystemInterface::handleTouchEvent(platformWindow->window(), xiEvent->time, dev->qtTouchDevice, m_touchPoints.values()); // If a touchpoint was released, we can forget it, because the ID won't be reused. if (touchPoint.state == Qt::TouchPointReleased) m_touchPoints.remove(touchPoint.id); } } #endif } }