Update the touchscreen plug-in.
Now works with bcm5974: Added manual contact tracking for drivers that do not report a tracking id and fixed abs limit querying to use ABS_MT_* instead of ABS_*. Fixed reported area: The incoming point was the top-left point instead of the center which was incorrect. Added pressure support. Tracking of event type has been removed as handleTouchEvent no longer needs it. Broken debug prints have been removed. Changed udev auto-detection to pick only /dev/input/event*. Fixed multiple released state reports with some drivers. Name and capabilities are now set properly for the QTouchDevice. Change-Id: I8f026c9a14465bfb6d567f4dcf36c5c03f843868 Reviewed-by: Jørgen Lind <jorgen.lind@nokia.com>
This commit is contained in:
parent
87679491cb
commit
2edada763a
@ -1,6 +1,8 @@
|
||||
Generic plug-in for evdev touch events
|
||||
Generic plug-in for evdev touch events.
|
||||
|
||||
(a) Using as a QPA generic plug-in
|
||||
Tested with the following drivers: bcm5974, hid_magicmouse.
|
||||
|
||||
(1) Using as a QPA generic plug-in
|
||||
|
||||
1. set up and connect the touch device
|
||||
2. install libudev-dev or similar
|
||||
@ -24,20 +26,22 @@ replacement by default. For embedded systems the code could to be
|
||||
extended to generate also mouse events (by calling handleMouseEvent
|
||||
for the primary touch point for example).
|
||||
|
||||
(b) Using in a compositor
|
||||
(2) Using in a compositor
|
||||
|
||||
The classes (QTouchScreenHandler, QTouchScreenHandlerThread) are also
|
||||
suitable for direct inclusion into an application, e.g. a Wayland
|
||||
compositor. The compositor will then usually register its own
|
||||
compositor. The compositor may then register its own
|
||||
QTouchScreenObserver because relying on the QTouchEvents generated by
|
||||
the QPA event sender is often not satisfactory, as some low-level
|
||||
details may get lost, and due to performance reasons.
|
||||
the QPA event sender may not always be satisfactory as some low-level
|
||||
details get lost, and due to performance reasons.
|
||||
|
||||
|
||||
Known issues:
|
||||
(3) Possible issues and solutions
|
||||
|
||||
The udev rule matches any touchpad device. If there are multiple ones,
|
||||
specify the device as described above.
|
||||
|
||||
If no evdev events are read, remove 50-synaptics.conf from
|
||||
/usr/share/X11/xorg.conf.d and restart X.
|
||||
If no evdev events are read, remove 50-synaptics.conf (or similar)
|
||||
from /usr/share/X11/xorg.conf.d and restart X. Or at least temporarily
|
||||
disable the device by running xinput set-prop <device> <device enabled
|
||||
property> 0. Use xinput list and xinput list-props to figure out the
|
||||
values.
|
||||
|
@ -47,8 +47,6 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
//#define POINT_DEBUG
|
||||
|
||||
QTouchEventSenderQPA::QTouchEventSenderQPA(const QString &spec)
|
||||
{
|
||||
m_forceToActiveWindow = spec.split(QLatin1Char(':')).contains(QLatin1String("force_window"));
|
||||
@ -58,12 +56,22 @@ QTouchEventSenderQPA::QTouchEventSenderQPA(const QString &spec)
|
||||
QWindowSystemInterface::registerTouchDevice(m_device);
|
||||
}
|
||||
|
||||
void QTouchEventSenderQPA::touch_configure(int x_min, int x_max, int y_min, int y_max)
|
||||
void QTouchEventSenderQPA::touch_configure(int x_min, int x_max, int y_min, int y_max,
|
||||
int pressure_min, int pressure_max,
|
||||
const QString &dev_name)
|
||||
{
|
||||
hw_range_x_min = x_min;
|
||||
hw_range_x_max = x_max;
|
||||
hw_range_y_min = y_min;
|
||||
hw_range_y_max = y_max;
|
||||
|
||||
hw_pressure_min = pressure_min;
|
||||
hw_pressure_max = pressure_max;
|
||||
|
||||
m_device->setName(dev_name);
|
||||
|
||||
if (hw_pressure_max > hw_pressure_min)
|
||||
m_device->setCapabilities(m_device->capabilities() | QTouchDevice::Pressure);
|
||||
}
|
||||
|
||||
void QTouchEventSenderQPA::touch_point(const QList<QWindowSystemInterface::TouchPoint> &points)
|
||||
@ -78,32 +86,28 @@ void QTouchEventSenderQPA::touch_point(const QList<QWindowSystemInterface::Touch
|
||||
winRect = QGuiApplication::primaryScreen()->geometry();
|
||||
}
|
||||
|
||||
#ifdef POINT_DEBUG
|
||||
qDebug() << "QPA: Mapping" << points.size() << "points to" << winRect << state;
|
||||
#endif
|
||||
const int hw_w = hw_range_x_max - hw_range_x_min;
|
||||
const int hw_h = hw_range_y_max - hw_range_y_min;
|
||||
|
||||
QList<QWindowSystemInterface::TouchPoint> touchPoints = points;
|
||||
// Translate the coordinates and set the normalized position. QPA expects
|
||||
// 'area' to be in screen coordinates, while the device reports them in its
|
||||
// own system with (0, 0) being the center point of the device.
|
||||
// Map the coordinates based on the normalized position. QPA expects 'area'
|
||||
// to be in screen coordinates.
|
||||
for (int i = 0; i < touchPoints.size(); ++i) {
|
||||
QWindowSystemInterface::TouchPoint &tp(touchPoints[i]);
|
||||
|
||||
const int hw_w = hw_range_x_max - hw_range_x_min;
|
||||
const int hw_h = hw_range_y_max - hw_range_y_min;
|
||||
|
||||
qreal nx = tp.normalPosition.x();
|
||||
qreal ny = tp.normalPosition.y();
|
||||
|
||||
// Generate a screen position that is always inside the active window or the default screen.
|
||||
const int wx = winRect.left() + int(nx * winRect.width());
|
||||
const int wy = winRect.top() + int(ny * winRect.height());
|
||||
// Generate a screen position that is always inside the active window
|
||||
// or the primary screen.
|
||||
const int wx = winRect.left() + int(tp.normalPosition.x() * winRect.width());
|
||||
const int wy = winRect.top() + int(tp.normalPosition.y() * winRect.height());
|
||||
const qreal sizeRatio = (winRect.width() + winRect.height()) / qreal(hw_w + hw_h);
|
||||
tp.area = QRect(wx, wy, tp.area.width() * sizeRatio, tp.area.height() * sizeRatio);
|
||||
tp.area = QRect(0, 0, tp.area.width() * sizeRatio, tp.area.height() * sizeRatio);
|
||||
tp.area.moveCenter(QPoint(wx, wy));
|
||||
|
||||
#ifdef POINT_DEBUG
|
||||
qDebug() << " " << i << tp.area << tp.state << tp.id << tp.flags << tp.pressure;
|
||||
#endif
|
||||
// Calculate normalized pressure.
|
||||
if (!hw_pressure_min && !hw_pressure_max)
|
||||
tp.pressure = tp.state == Qt::TouchPointReleased ? 0 : 1;
|
||||
else
|
||||
tp.pressure = (tp.pressure - hw_pressure_min) / qreal(hw_pressure_max - hw_pressure_min);
|
||||
}
|
||||
|
||||
QWindowSystemInterface::handleTouchEvent(0, m_device, touchPoints);
|
||||
|
@ -54,7 +54,8 @@ class QTouchEventSenderQPA : public QTouchScreenObserver
|
||||
{
|
||||
public:
|
||||
QTouchEventSenderQPA(const QString &spec = QString());
|
||||
void touch_configure(int x_min, int x_max, int y_min, int y_max);
|
||||
void touch_configure(int x_min, int x_max, int y_min, int y_max,
|
||||
int pressure_min, int pressure_max, const QString &dev_name);
|
||||
void touch_point(const QList<QWindowSystemInterface::TouchPoint> &points);
|
||||
|
||||
private:
|
||||
@ -63,6 +64,9 @@ private:
|
||||
int hw_range_x_max;
|
||||
int hw_range_y_min;
|
||||
int hw_range_y_max;
|
||||
int hw_pressure_min;
|
||||
int hw_pressure_max;
|
||||
QString hw_dev_name;
|
||||
QTouchDevice *m_device;
|
||||
};
|
||||
|
||||
|
@ -41,28 +41,23 @@
|
||||
|
||||
#include "qtouchscreen.h"
|
||||
#include <QStringList>
|
||||
#include <QHash>
|
||||
#include <QSocketNotifier>
|
||||
#include <QDebug>
|
||||
#include <QtCore/private/qcore_unix_p.h>
|
||||
#include <linux/input.h>
|
||||
#include <libudev.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
//#define POINT_DEBUG
|
||||
|
||||
class QTouchScreenData
|
||||
{
|
||||
public:
|
||||
QTouchScreenData(QTouchScreenHandler *q_ptr, const QStringList &args);
|
||||
|
||||
void processInputEvent(input_event *data);
|
||||
|
||||
void dump();
|
||||
void assignIds();
|
||||
|
||||
QTouchScreenHandler *q;
|
||||
QEvent::Type m_state;
|
||||
QEvent::Type m_prevState;
|
||||
int m_lastEventType;
|
||||
QList<QWindowSystemInterface::TouchPoint> m_touchPoints;
|
||||
|
||||
@ -71,17 +66,24 @@ public:
|
||||
int x;
|
||||
int y;
|
||||
int maj;
|
||||
int pressure;
|
||||
Qt::TouchPointState state;
|
||||
QTouchEvent::TouchPoint::InfoFlags flags;
|
||||
Contact() : trackingId(0), x(0), y(0), maj(1), state(Qt::TouchPointPressed), flags(0) { }
|
||||
Contact() : trackingId(-1),
|
||||
x(0), y(0), maj(1), pressure(0),
|
||||
state(Qt::TouchPointPressed), flags(0) { }
|
||||
};
|
||||
QMap<int, Contact> m_contacts, m_lastContacts;
|
||||
QHash<int, Contact> m_contacts, m_lastContacts;
|
||||
Contact m_currentData;
|
||||
|
||||
int findClosestContact(const QHash<int, Contact> &contacts, int x, int y, int *dist);
|
||||
|
||||
int hw_range_x_min;
|
||||
int hw_range_x_max;
|
||||
int hw_range_y_min;
|
||||
int hw_range_y_max;
|
||||
int hw_pressure_min;
|
||||
int hw_pressure_max;
|
||||
QString hw_name;
|
||||
|
||||
QList<QTouchScreenObserver *> m_observers;
|
||||
@ -89,11 +91,10 @@ public:
|
||||
|
||||
QTouchScreenData::QTouchScreenData(QTouchScreenHandler *q_ptr, const QStringList &args)
|
||||
: q(q_ptr),
|
||||
m_state(QEvent::TouchBegin),
|
||||
m_prevState(m_state),
|
||||
m_lastEventType(-1),
|
||||
hw_range_x_min(0), hw_range_x_max(0),
|
||||
hw_range_y_min(0), hw_range_y_max(0)
|
||||
hw_range_y_min(0), hw_range_y_max(0),
|
||||
hw_pressure_min(0), hw_pressure_max(0)
|
||||
{
|
||||
Q_UNUSED(args);
|
||||
}
|
||||
@ -101,7 +102,7 @@ QTouchScreenData::QTouchScreenData(QTouchScreenHandler *q_ptr, const QStringList
|
||||
QTouchScreenHandler::QTouchScreenHandler(const QString &spec)
|
||||
: m_notify(0), m_fd(-1), d(0)
|
||||
{
|
||||
setObjectName(QLatin1String("LinuxInputSubsystem Touch Handler"));
|
||||
setObjectName(QLatin1String("Linux Touch Handler"));
|
||||
|
||||
QString dev = QLatin1String("/dev/input/event5");
|
||||
try_udev(&dev);
|
||||
@ -126,16 +127,23 @@ QTouchScreenHandler::QTouchScreenHandler(const QString &spec)
|
||||
|
||||
input_absinfo absInfo;
|
||||
memset(&absInfo, 0, sizeof(input_absinfo));
|
||||
if (!ioctl(m_fd, EVIOCGABS(ABS_X), &absInfo) >= 0) {
|
||||
if (ioctl(m_fd, EVIOCGABS(ABS_MT_POSITION_X), &absInfo) >= 0) {
|
||||
qDebug("min X: %d max X: %d", absInfo.minimum, absInfo.maximum);
|
||||
d->hw_range_x_min = absInfo.minimum;
|
||||
d->hw_range_x_max = absInfo.maximum;
|
||||
}
|
||||
if (!ioctl(m_fd, EVIOCGABS(ABS_Y), &absInfo) >= 0) {
|
||||
if (ioctl(m_fd, EVIOCGABS(ABS_MT_POSITION_Y), &absInfo) >= 0) {
|
||||
qDebug("min Y: %d max Y: %d", absInfo.minimum, absInfo.maximum);
|
||||
d->hw_range_y_min = absInfo.minimum;
|
||||
d->hw_range_y_max = absInfo.maximum;
|
||||
}
|
||||
if (ioctl(m_fd, EVIOCGABS(ABS_PRESSURE), &absInfo) >= 0) {
|
||||
qDebug("min pressure: %d max pressure: %d", absInfo.minimum, absInfo.maximum);
|
||||
if (absInfo.maximum > absInfo.minimum) {
|
||||
d->hw_pressure_min = absInfo.minimum;
|
||||
d->hw_pressure_max = absInfo.maximum;
|
||||
}
|
||||
}
|
||||
char name[1024];
|
||||
if (ioctl(m_fd, EVIOCGNAME(sizeof(name) - 1), name) >= 0) {
|
||||
d->hw_name = QString::fromLocal8Bit(name);
|
||||
@ -157,11 +165,14 @@ void QTouchScreenHandler::addObserver(QTouchScreenObserver *observer)
|
||||
return;
|
||||
d->m_observers.append(observer);
|
||||
observer->touch_configure(d->hw_range_x_min, d->hw_range_x_max,
|
||||
d->hw_range_y_min, d->hw_range_y_max);
|
||||
d->hw_range_y_min, d->hw_range_y_max,
|
||||
d->hw_pressure_min, d->hw_pressure_max,
|
||||
d->hw_name);
|
||||
}
|
||||
|
||||
void QTouchScreenHandler::try_udev(QString *path)
|
||||
{
|
||||
*path = QString();
|
||||
udev *u = udev_new();
|
||||
udev_enumerate *ue = udev_enumerate_new(u);
|
||||
udev_enumerate_add_match_subsystem(ue, "input");
|
||||
@ -171,9 +182,10 @@ void QTouchScreenHandler::try_udev(QString *path)
|
||||
udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(ue)) {
|
||||
const char *syspath = udev_list_entry_get_name(entry);
|
||||
udev_device *udevice = udev_device_new_from_syspath(u, syspath);
|
||||
*path = QString::fromLocal8Bit(udev_device_get_devnode(udevice));
|
||||
qDebug("from udev: %s", qPrintable(*path));
|
||||
QString candidate = QString::fromLocal8Bit(udev_device_get_devnode(udevice));
|
||||
udev_device_unref(udevice);
|
||||
if (path->isEmpty() && candidate.startsWith("/dev/input/event"))
|
||||
*path = candidate;
|
||||
}
|
||||
udev_enumerate_unref(ue);
|
||||
udev_unref(u);
|
||||
@ -213,137 +225,152 @@ void QTouchScreenData::processInputEvent(input_event *data)
|
||||
{
|
||||
if (data->type == EV_ABS) {
|
||||
|
||||
if (data->code == ABS_MT_POSITION_X) {
|
||||
m_currentData.x = data->value;
|
||||
} else if (data->code == ABS_MT_POSITION_Y) {
|
||||
m_currentData.y = data->value;
|
||||
} else if (data->code == ABS_MT_TRACKING_ID) {
|
||||
m_currentData.trackingId = data->value;
|
||||
if (m_contacts.isEmpty())
|
||||
m_currentData.flags |= QTouchEvent::TouchPoint::Primary;
|
||||
} else if (data->code == ABS_MT_TOUCH_MAJOR) {
|
||||
m_currentData.maj = data->value;
|
||||
if (data->value == 0)
|
||||
m_currentData.state = Qt::TouchPointReleased;
|
||||
}
|
||||
if (data->code == ABS_MT_POSITION_X) {
|
||||
m_currentData.x = qBound(hw_range_x_min, data->value, hw_range_x_max);
|
||||
} else if (data->code == ABS_MT_POSITION_Y) {
|
||||
m_currentData.y = qBound(hw_range_y_min, data->value, hw_range_y_max);
|
||||
} else if (data->code == ABS_MT_TRACKING_ID) {
|
||||
m_currentData.trackingId = data->value;
|
||||
} else if (data->code == ABS_MT_TOUCH_MAJOR) {
|
||||
m_currentData.maj = data->value;
|
||||
if (data->value == 0)
|
||||
m_currentData.state = Qt::TouchPointReleased;
|
||||
} else if (data->code == ABS_PRESSURE) {
|
||||
m_currentData.pressure = qBound(hw_pressure_min, data->value, hw_pressure_max);
|
||||
}
|
||||
|
||||
} else if (data->type == EV_SYN && data->code == SYN_MT_REPORT && m_lastEventType != EV_SYN) {
|
||||
|
||||
m_contacts.insert(m_currentData.trackingId, m_currentData);
|
||||
// If there is no tracking id, one will be generated later.
|
||||
// Until that use a temporary key.
|
||||
int key = m_currentData.trackingId;
|
||||
if (key == -1)
|
||||
key = m_contacts.count();
|
||||
|
||||
// Mark the first point as primary.
|
||||
if (m_contacts.isEmpty())
|
||||
m_currentData.flags |= QTouchEvent::TouchPoint::Primary;
|
||||
|
||||
m_contacts.insert(key, m_currentData);
|
||||
m_currentData = Contact();
|
||||
|
||||
} else if (data->type == EV_SYN && data->code == SYN_REPORT) {
|
||||
|
||||
m_touchPoints.clear();
|
||||
for (QMap<int, Contact>::iterator it = m_contacts.begin(), ite = m_contacts.end();
|
||||
it != ite; ++it) {
|
||||
QWindowSystemInterface::TouchPoint tp;
|
||||
tp.id = it->trackingId;
|
||||
tp.flags = it->flags;
|
||||
tp.pressure = it->state == Qt::TouchPointReleased ? 0 : 1;
|
||||
// Ensure valid IDs even when the driver does not report ABS_MT_TRACKING_ID.
|
||||
if (!m_contacts.isEmpty() && m_contacts.constBegin().value().trackingId == -1)
|
||||
assignIds();
|
||||
|
||||
if (m_lastContacts.contains(it->trackingId)) {
|
||||
const Contact &prev(m_lastContacts.value(it->trackingId));
|
||||
if (it->state == Qt::TouchPointReleased) {
|
||||
m_touchPoints.clear();
|
||||
Qt::TouchPointStates combinedStates;
|
||||
QMutableHashIterator<int, Contact> it(m_contacts);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
QWindowSystemInterface::TouchPoint tp;
|
||||
Contact &contact(it.value());
|
||||
tp.id = contact.trackingId;
|
||||
tp.flags = contact.flags;
|
||||
|
||||
if (m_lastContacts.contains(contact.trackingId)) {
|
||||
const Contact &prev(m_lastContacts.value(contact.trackingId));
|
||||
if (contact.state == Qt::TouchPointReleased) {
|
||||
// Copy over the previous values for released points, just in case.
|
||||
it->x = prev.x;
|
||||
it->y = prev.y;
|
||||
it->maj = prev.maj;
|
||||
contact.x = prev.x;
|
||||
contact.y = prev.y;
|
||||
contact.maj = prev.maj;
|
||||
} else {
|
||||
it->state = (prev.x == it->x && prev.y == it->y) ? Qt::TouchPointStationary : Qt::TouchPointMoved;
|
||||
contact.state = (prev.x == contact.x && prev.y == contact.y)
|
||||
? Qt::TouchPointStationary : Qt::TouchPointMoved;
|
||||
}
|
||||
}
|
||||
|
||||
tp.state = it->state;
|
||||
tp.area = QRectF(it->x, it->y, it->maj, it->maj);
|
||||
// Avoid reporting a contact in released state more than once.
|
||||
if (contact.state == Qt::TouchPointReleased
|
||||
&& !m_lastContacts.contains(contact.trackingId)) {
|
||||
it.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
tp.state = contact.state;
|
||||
combinedStates |= tp.state;
|
||||
|
||||
// Store the HW coordinates. Observers can then map it to screen space or something else.
|
||||
tp.area = QRectF(0, 0, contact.maj, contact.maj);
|
||||
tp.area.moveCenter(QPoint(contact.x, contact.y));
|
||||
tp.pressure = contact.pressure;
|
||||
|
||||
// Translate so that (0, 0) is the top-left corner.
|
||||
const int hw_x = qBound(hw_range_x_min, int(tp.area.left()), hw_range_x_max) - hw_range_x_min;
|
||||
const int hw_y = qBound(hw_range_y_min, int(tp.area.top()), hw_range_y_max) - hw_range_y_min;
|
||||
// Get a normalized position in range 0..1.
|
||||
const int hw_w = hw_range_x_max - hw_range_x_min;
|
||||
const int hw_h = hw_range_y_max - hw_range_y_min;
|
||||
tp.normalPosition = QPointF(hw_x / qreal(hw_w),
|
||||
hw_y / qreal(hw_h));
|
||||
tp.normalPosition = QPointF((contact.x - hw_range_x_min) / qreal(hw_range_x_max - hw_range_x_min),
|
||||
(contact.y - hw_range_y_min) / qreal(hw_range_y_max - hw_range_y_min));
|
||||
|
||||
m_touchPoints.append(tp);
|
||||
}
|
||||
|
||||
if (m_contacts.isEmpty())
|
||||
m_state = QEvent::TouchEnd;
|
||||
if (contact.state == Qt::TouchPointReleased)
|
||||
it.remove();
|
||||
}
|
||||
|
||||
m_lastContacts = m_contacts;
|
||||
m_contacts.clear();
|
||||
|
||||
// No need to deliver if all points are stationary.
|
||||
bool skip = false;
|
||||
if (m_state == QEvent::TouchUpdate) {
|
||||
skip = true;
|
||||
for (int i = 0; i < m_touchPoints.count(); ++i)
|
||||
if (m_touchPoints.at(i).state != Qt::TouchPointStationary) {
|
||||
skip = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef POINT_DEBUG
|
||||
dump();
|
||||
#endif
|
||||
|
||||
if (!skip && !(m_state == m_prevState && m_state == QEvent::TouchEnd))
|
||||
if (!m_touchPoints.isEmpty() && combinedStates != Qt::TouchPointStationary) {
|
||||
for (int i = 0; i < m_observers.count(); ++i)
|
||||
m_observers.at(i)->touch_point(m_touchPoints);
|
||||
|
||||
m_prevState = m_state;
|
||||
if (m_state == QEvent::TouchBegin)
|
||||
m_state = QEvent::TouchUpdate;
|
||||
else if (m_state == QEvent::TouchEnd)
|
||||
m_state = QEvent::TouchBegin;
|
||||
}
|
||||
}
|
||||
|
||||
m_lastEventType = data->type;
|
||||
}
|
||||
|
||||
void QTouchScreenData::dump()
|
||||
int QTouchScreenData::findClosestContact(const QHash<int, Contact> &contacts, int x, int y, int *dist)
|
||||
{
|
||||
const char *eventType;
|
||||
switch (m_state) {
|
||||
case QEvent::TouchBegin:
|
||||
eventType = "TouchBegin";
|
||||
break;
|
||||
case QEvent::TouchUpdate:
|
||||
eventType = "TouchUpdate";
|
||||
break;
|
||||
case QEvent::TouchEnd:
|
||||
eventType = "TouchEnd";
|
||||
break;
|
||||
default:
|
||||
eventType = "unknown";
|
||||
break;
|
||||
}
|
||||
qDebug() << "touch event" << eventType;
|
||||
foreach (const QWindowSystemInterface::TouchPoint &tp, m_touchPoints) {
|
||||
const char *pointState;
|
||||
switch (tp.state) {
|
||||
case Qt::TouchPointPressed:
|
||||
pointState = "pressed";
|
||||
break;
|
||||
case Qt::TouchPointMoved:
|
||||
pointState = "moved";
|
||||
break;
|
||||
case Qt::TouchPointStationary:
|
||||
pointState = "stationary";
|
||||
break;
|
||||
case Qt::TouchPointReleased:
|
||||
pointState = "released";
|
||||
break;
|
||||
default:
|
||||
pointState = "unknown";
|
||||
break;
|
||||
int minDist = -1, id = -1;
|
||||
for (QHash<int, Contact>::const_iterator it = contacts.constBegin(), ite = contacts.constEnd();
|
||||
it != ite; ++it) {
|
||||
const Contact &contact(it.value());
|
||||
int dx = x - contact.x;
|
||||
int dy = y - contact.y;
|
||||
int dist = dx * dx + dy * dy;
|
||||
if (minDist == -1 || dist < minDist) {
|
||||
minDist = dist;
|
||||
id = contact.trackingId;
|
||||
}
|
||||
qDebug() << " " << tp.id << tp.area << pointState << tp.normalPosition
|
||||
<< tp.pressure << tp.flags << tp.area.center();
|
||||
}
|
||||
if (dist)
|
||||
*dist = minDist;
|
||||
return id;
|
||||
}
|
||||
|
||||
void QTouchScreenData::assignIds()
|
||||
{
|
||||
QHash<int, Contact> candidates = m_lastContacts, pending = m_contacts, newContacts;
|
||||
int maxId = -1;
|
||||
QHash<int, Contact>::iterator it, ite, bestMatch;
|
||||
while (!pending.isEmpty() && !candidates.isEmpty()) {
|
||||
int bestDist = -1, bestId;
|
||||
for (it = pending.begin(), ite = pending.end(); it != ite; ++it) {
|
||||
int dist;
|
||||
int id = findClosestContact(candidates, it->x, it->y, &dist);
|
||||
if (id >= 0 && (bestDist == -1 || dist < bestDist)) {
|
||||
bestDist = dist;
|
||||
bestId = id;
|
||||
bestMatch = it;
|
||||
}
|
||||
}
|
||||
if (bestDist >= 0) {
|
||||
bestMatch->trackingId = bestId;
|
||||
newContacts.insert(bestId, *bestMatch);
|
||||
candidates.remove(bestId);
|
||||
pending.erase(bestMatch);
|
||||
if (bestId > maxId)
|
||||
maxId = bestId;
|
||||
}
|
||||
}
|
||||
if (candidates.isEmpty()) {
|
||||
for (it = pending.begin(), ite = pending.end(); it != ite; ++it) {
|
||||
it->trackingId = ++maxId;
|
||||
newContacts.insert(it->trackingId, *it);
|
||||
}
|
||||
}
|
||||
m_contacts = newContacts;
|
||||
}
|
||||
|
||||
|
||||
|
@ -58,7 +58,8 @@ class QTouchScreenData;
|
||||
class QTouchScreenObserver
|
||||
{
|
||||
public:
|
||||
virtual void touch_configure(int x_min, int x_max, int y_min, int y_max) = 0;
|
||||
virtual void touch_configure(int x_min, int x_max, int y_min, int y_max,
|
||||
int pressure_min, int pressure_max, const QString &dev_name) = 0;
|
||||
virtual void touch_point(const QList<QWindowSystemInterface::TouchPoint> &points) = 0;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user