Exemplo n.º 1
0
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
    }
}