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:
parent
10bf53ae19
commit
40e4949674
src/plugins/platforms/xcb
@ -1922,6 +1922,7 @@ static const char * xcb_atomnames = {
|
||||
"Abs MT Position Y\0"
|
||||
"Abs MT Touch Major\0"
|
||||
"Abs MT Touch Minor\0"
|
||||
"Abs MT Orientation\0"
|
||||
"Abs MT Pressure\0"
|
||||
"Abs MT Tracking ID\0"
|
||||
"Max Contacts\0"
|
||||
|
@ -261,6 +261,7 @@ namespace QXcbAtom {
|
||||
AbsMTPositionY,
|
||||
AbsMTTouchMajor,
|
||||
AbsMTTouchMinor,
|
||||
AbsMTOrientation,
|
||||
AbsMTPressure,
|
||||
AbsMTTrackingID,
|
||||
MaxContacts,
|
||||
|
@ -48,6 +48,7 @@ struct XInput2TouchDeviceData {
|
||||
XInput2TouchDeviceData()
|
||||
: xiDeviceInfo(0)
|
||||
, qtTouchDevice(0)
|
||||
, providesTouchOrientation(false)
|
||||
{
|
||||
}
|
||||
XIDeviceInfo *xiDeviceInfo;
|
||||
@ -59,6 +60,7 @@ struct XInput2TouchDeviceData {
|
||||
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
|
||||
QSizeF size; // device size in mm
|
||||
bool providesTouchOrientation;
|
||||
};
|
||||
|
||||
void QXcbConnection::initializeXInput2()
|
||||
@ -413,6 +415,8 @@ XInput2TouchDeviceData *QXcbConnection::touchDeviceForId(int id)
|
||||
caps |= QTouchDevice::Position | QTouchDevice::NormalizedPosition;
|
||||
else if (vci->label == atom(QXcbAtom::AbsMTTouchMajor))
|
||||
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))
|
||||
caps |= QTouchDevice::Pressure;
|
||||
else if (vci->label == atom(QXcbAtom::RelX)) {
|
||||
@ -574,7 +578,9 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
|
||||
QXcbScreen* screen = platformWindow->xcbScreen();
|
||||
qreal x = fixed1616ToReal(xiDeviceEvent->root_x);
|
||||
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) {
|
||||
XIAnyClassInfo *classinfo = dev->xiDeviceInfo->classes[i];
|
||||
if (classinfo->type == XIValuatorClass) {
|
||||
@ -599,7 +605,24 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
|
||||
} else if (vci->label == atom(QXcbAtom::AbsMTPositionY)) {
|
||||
ny = valuatorNormalized(value, vci);
|
||||
} 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) ||
|
||||
vci->label == atom(QXcbAtom::AbsPressure)) {
|
||||
touchPoint.pressure = valuatorNormalized(value, vci);
|
||||
@ -616,8 +639,18 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
|
||||
ny = y / screen->geometry().height();
|
||||
}
|
||||
if (xiDeviceEvent->evtype != XI_TouchEnd) {
|
||||
if (d == 0.0)
|
||||
d = touchPoint.area.width();
|
||||
if (!dev->providesTouchOrientation) {
|
||||
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) {
|
||||
@ -681,7 +714,7 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
|
||||
}
|
||||
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);
|
||||
|
||||
if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled()))
|
||||
|
Loading…
Reference in New Issue
Block a user