xcb: Take into account the orientation of touch points

Add support for ABS_MT_ORIENTATION value. Linux kernel multi-touch
protocol allows it to be in a wide range:
https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt,
but we need only to know whether the touch point rect is rotated
by 90 degress. So adjust the angle to the closest axis.

Change-Id: Ie20725dc4bef509e2f9b19571efc69502d00c019
Reviewed-by: Shawn Rutledge <shawn.rutledge@theqtcompany.com>
This commit is contained in:
Alexander Volkov 2015-06-11 18:29:44 +03:00
parent 10bf53ae19
commit 40e4949674
3 changed files with 40 additions and 5 deletions

View File

@ -1922,6 +1922,7 @@ static const char * xcb_atomnames = {
"Abs MT Position Y\0" "Abs MT Position Y\0"
"Abs MT Touch Major\0" "Abs MT Touch Major\0"
"Abs MT Touch Minor\0" "Abs MT Touch Minor\0"
"Abs MT Orientation\0"
"Abs MT Pressure\0" "Abs MT Pressure\0"
"Abs MT Tracking ID\0" "Abs MT Tracking ID\0"
"Max Contacts\0" "Max Contacts\0"

View File

@ -261,6 +261,7 @@ namespace QXcbAtom {
AbsMTPositionY, AbsMTPositionY,
AbsMTTouchMajor, AbsMTTouchMajor,
AbsMTTouchMinor, AbsMTTouchMinor,
AbsMTOrientation,
AbsMTPressure, AbsMTPressure,
AbsMTTrackingID, AbsMTTrackingID,
MaxContacts, MaxContacts,

View File

@ -48,6 +48,7 @@ struct XInput2TouchDeviceData {
XInput2TouchDeviceData() XInput2TouchDeviceData()
: xiDeviceInfo(0) : xiDeviceInfo(0)
, qtTouchDevice(0) , qtTouchDevice(0)
, providesTouchOrientation(false)
{ {
} }
XIDeviceInfo *xiDeviceInfo; XIDeviceInfo *xiDeviceInfo;
@ -59,6 +60,7 @@ struct XInput2TouchDeviceData {
QPointF firstPressedPosition; // in screen coordinates where the first point was pressed QPointF firstPressedPosition; // in screen coordinates where the first point was pressed
QPointF firstPressedNormalPosition; // device coordinates (0 to 1, 0 to 1) where the first point was pressed QPointF firstPressedNormalPosition; // device coordinates (0 to 1, 0 to 1) where the first point was pressed
QSizeF size; // device size in mm QSizeF size; // device size in mm
bool providesTouchOrientation;
}; };
void QXcbConnection::initializeXInput2() void QXcbConnection::initializeXInput2()
@ -413,6 +415,8 @@ XInput2TouchDeviceData *QXcbConnection::touchDeviceForId(int id)
caps |= QTouchDevice::Position | QTouchDevice::NormalizedPosition; caps |= QTouchDevice::Position | QTouchDevice::NormalizedPosition;
else if (vci->label == atom(QXcbAtom::AbsMTTouchMajor)) else if (vci->label == atom(QXcbAtom::AbsMTTouchMajor))
caps |= QTouchDevice::Area; caps |= QTouchDevice::Area;
else if (vci->label == atom(QXcbAtom::AbsMTOrientation))
dev->providesTouchOrientation = true;
else if (vci->label == atom(QXcbAtom::AbsMTPressure) || vci->label == atom(QXcbAtom::AbsPressure)) else if (vci->label == atom(QXcbAtom::AbsMTPressure) || vci->label == atom(QXcbAtom::AbsPressure))
caps |= QTouchDevice::Pressure; caps |= QTouchDevice::Pressure;
else if (vci->label == atom(QXcbAtom::RelX)) { else if (vci->label == atom(QXcbAtom::RelX)) {
@ -574,7 +578,9 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
QXcbScreen* screen = platformWindow->xcbScreen(); QXcbScreen* screen = platformWindow->xcbScreen();
qreal x = fixed1616ToReal(xiDeviceEvent->root_x); qreal x = fixed1616ToReal(xiDeviceEvent->root_x);
qreal y = fixed1616ToReal(xiDeviceEvent->root_y); qreal y = fixed1616ToReal(xiDeviceEvent->root_y);
qreal nx = -1.0, ny = -1.0, d = 0.0; qreal nx = -1.0, ny = -1.0;
qreal w = 0.0, h = 0.0;
bool majorAxisIsY = touchPoint.area.height() > touchPoint.area.width();
for (int i = 0; i < dev->xiDeviceInfo->num_classes; ++i) { for (int i = 0; i < dev->xiDeviceInfo->num_classes; ++i) {
XIAnyClassInfo *classinfo = dev->xiDeviceInfo->classes[i]; XIAnyClassInfo *classinfo = dev->xiDeviceInfo->classes[i];
if (classinfo->type == XIValuatorClass) { if (classinfo->type == XIValuatorClass) {
@ -599,7 +605,24 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
} else if (vci->label == atom(QXcbAtom::AbsMTPositionY)) { } else if (vci->label == atom(QXcbAtom::AbsMTPositionY)) {
ny = valuatorNormalized(value, vci); ny = valuatorNormalized(value, vci);
} else if (vci->label == atom(QXcbAtom::AbsMTTouchMajor)) { } else if (vci->label == atom(QXcbAtom::AbsMTTouchMajor)) {
d = valuatorNormalized(value, vci) * screen->geometry().width(); const qreal sw = screen->geometry().width();
const qreal sh = screen->geometry().height();
w = valuatorNormalized(value, vci) * std::sqrt(sw * sw + sh * sh);
} else if (vci->label == atom(QXcbAtom::AbsMTTouchMinor)) {
const qreal sw = screen->geometry().width();
const qreal sh = screen->geometry().height();
h = valuatorNormalized(value, vci) * std::sqrt(sw * sw + sh * sh);
} else if (vci->label == atom(QXcbAtom::AbsMTOrientation)) {
// Find the closest axis.
// 0 corresponds to the Y axis, vci->max to the X axis.
// Flipping over the Y axis and rotating by 180 degrees
// don't change the result, so normalize value to range
// [0, vci->max] first.
value = qAbs(value);
while (value > vci->max)
value -= 2 * vci->max;
value = qAbs(value);
majorAxisIsY = value < vci->max - value;
} else if (vci->label == atom(QXcbAtom::AbsMTPressure) || } else if (vci->label == atom(QXcbAtom::AbsMTPressure) ||
vci->label == atom(QXcbAtom::AbsPressure)) { vci->label == atom(QXcbAtom::AbsPressure)) {
touchPoint.pressure = valuatorNormalized(value, vci); touchPoint.pressure = valuatorNormalized(value, vci);
@ -616,8 +639,18 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
ny = y / screen->geometry().height(); ny = y / screen->geometry().height();
} }
if (xiDeviceEvent->evtype != XI_TouchEnd) { if (xiDeviceEvent->evtype != XI_TouchEnd) {
if (d == 0.0) if (!dev->providesTouchOrientation) {
d = touchPoint.area.width(); if (w == 0.0)
w = touchPoint.area.width();
h = w;
} else {
if (w == 0.0)
w = qMax(touchPoint.area.width(), touchPoint.area.height());
if (h == 0.0)
h = qMin(touchPoint.area.width(), touchPoint.area.height());
if (majorAxisIsY)
qSwap(w, h);
}
} }
switch (xiDeviceEvent->evtype) { switch (xiDeviceEvent->evtype) {
@ -681,7 +714,7 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
} }
dev->pointPressedPosition.remove(touchPoint.id); dev->pointPressedPosition.remove(touchPoint.id);
} }
touchPoint.area = QRectF(x - d/2, y - d/2, d, d); touchPoint.area = QRectF(x - w/2, y - h/2, w, h);
touchPoint.normalPosition = QPointF(nx, ny); touchPoint.normalPosition = QPointF(nx, ny);
if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled())) if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled()))