1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qmousetslib_qws.h"
43
44 #if !defined(QT_NO_QWS_MOUSE_TSLIB) || defined(QT_PLUGIN)
45
46 #include <QtCore/qregexp.h>
47 #include <QtCore/qstringlist.h>
48 #include "qsocketnotifier.h"
49 #include "qscreen_qws.h"
50
51 #include <tslib.h>
52 #include <errno.h>
53
54 QT_BEGIN_NAMESPACE
55
56 #ifdef TSLIBMOUSEHANDLER_DEBUG
57 # include <QtCore/QDebug>
58 #endif
59
60 /*!
61 \internal
62
63 \class QWSTslibMouseHandler
64 \ingroup qws
65
66 \brief The QWSTslibMouseHandler class implements a mouse driver
67 for the Universal Touch Screen Library, tslib.
68
69 QWSTslibMouseHandler inherits the QWSCalibratedMouseHandler class,
70 providing calibration and noise reduction functionality in
71 addition to generating mouse events, for devices using the
72 Universal Touch Screen Library.
73
74 To be able to compile this mouse handler, \l{Qt for Embedded Linux}
75 must be configured with the \c -qt-mouse-tslib option, see the
76 \l{Pointer Handling} documentation for details. In addition, the tslib
77 headers and library must be present in the build environment. The
78 tslib sources can be downloaded from \l
79 {http://tslib.berlios.de/}. Use the \c -L and \c -I options
80 with \c configure to explicitly specify the location of the
81 library and its headers:
82
83 \snippet doc/src/snippets/code/src_gui_embedded_qmousetslib_qws.cpp 0
84
85 In order to use this mouse handler, tslib must also be correctly
86 installed on the target machine. This includes providing a \c
87 ts.conf configuration file and setting the necessary environment
88 variables, see the README file provided with tslib for details.
89
90 The ts.conf file will usually contain the following two lines
91
92 \snippet doc/src/snippets/code/src_gui_embedded_qmousetslib_qws.cpp 1
93
94 To make \l{Qt for Embedded Linux} explicitly choose the tslib mouse
95 handler, set the QWS_MOUSE_PROTO environment variable.
96
97 \sa {Pointer Handling}, {Qt for Embedded Linux}
98 */
99
100 class QWSTslibMouseHandlerPrivate : public QObject
101 {
102 Q_OBJECT
103 public:
104 QWSTslibMouseHandlerPrivate(QWSTslibMouseHandler *h,
105 const QString &device);
106 ~QWSTslibMouseHandlerPrivate();
107
108 void suspend();
109 void resume();
110
111 void calibrate(const QWSPointerCalibrationData *data);
112 void clearCalibration();
113
114 private:
115 QWSTslibMouseHandler *handler;
116 struct tsdev *dev;
117 QSocketNotifier *mouseNotifier;
118 int jitter_limit;
119
120 struct ts_sample lastSample;
121 bool wasPressed;
122 int lastdx;
123 int lastdy;
124
125 bool calibrated;
126 QString devName;
127
128 bool open();
129 void close();
130 inline bool get_sample(struct ts_sample *sample);
131
132 private slots:
133 void readMouseData();
134 };
135
QWSTslibMouseHandlerPrivate(QWSTslibMouseHandler * h,const QString & device)136 QWSTslibMouseHandlerPrivate::QWSTslibMouseHandlerPrivate(QWSTslibMouseHandler *h,
137 const QString &device)
138 : handler(h), dev(0), mouseNotifier(0), jitter_limit(3)
139 {
140 QStringList args = device.split(QLatin1Char(':'), QString::SkipEmptyParts);
141 QRegExp jitterRegex(QLatin1String("^jitter_limit=(\\d+)$"));
142 int index = args.indexOf(jitterRegex);
143 if (index >= 0) {
144 jitter_limit = jitterRegex.cap(1).toInt();
145 args.removeAt(index);
146 }
147
148 devName = args.join(QString());
149
150 if (devName.isNull()) {
151 const char *str = getenv("TSLIB_TSDEVICE");
152 if (str)
153 devName = QString::fromLocal8Bit(str);
154 }
155
156 if (devName.isNull())
157 devName = QLatin1String("/dev/ts");
158
159 if (!open())
160 return;
161
162 calibrated = true;
163
164 int fd = ts_fd(dev);
165 mouseNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, this);
166 connect(mouseNotifier, SIGNAL(activated(int)),this, SLOT(readMouseData()));
167 resume();
168 }
169
~QWSTslibMouseHandlerPrivate()170 QWSTslibMouseHandlerPrivate::~QWSTslibMouseHandlerPrivate()
171 {
172 close();
173 }
174
open()175 bool QWSTslibMouseHandlerPrivate::open()
176 {
177 dev = ts_open(devName.toLocal8Bit().constData(), 1);
178 if (!dev) {
179 qCritical("QWSTslibMouseHandlerPrivate: ts_open() failed"
180 " with error: '%s'", strerror(errno));
181 qCritical("Please check your tslib installation!");
182 return false;
183 }
184
185 if (ts_config(dev)) {
186 qCritical("QWSTslibMouseHandlerPrivate: ts_config() failed"
187 " with error: '%s'", strerror(errno));
188 qCritical("Please check your tslib installation!");
189 close();
190 return false;
191 }
192
193 return true;
194 }
195
close()196 void QWSTslibMouseHandlerPrivate::close()
197 {
198 if (dev)
199 ts_close(dev);
200 }
201
suspend()202 void QWSTslibMouseHandlerPrivate::suspend()
203 {
204 if (mouseNotifier)
205 mouseNotifier->setEnabled(false);
206 }
207
resume()208 void QWSTslibMouseHandlerPrivate::resume()
209 {
210 memset(&lastSample, 0, sizeof(lastSample));
211 wasPressed = false;
212 lastdx = 0;
213 lastdy = 0;
214 if (mouseNotifier)
215 mouseNotifier->setEnabled(true);
216 }
217
get_sample(struct ts_sample * sample)218 bool QWSTslibMouseHandlerPrivate::get_sample(struct ts_sample *sample)
219 {
220 if (!calibrated)
221 return (ts_read_raw(dev, sample, 1) == 1);
222
223 return (ts_read(dev, sample, 1) == 1);
224 }
225
readMouseData()226 void QWSTslibMouseHandlerPrivate::readMouseData()
227 {
228 if (!qt_screen)
229 return;
230
231 for(;;) {
232 struct ts_sample sample = lastSample;
233 bool pressed = wasPressed;
234
235 // Fast return if there's no events.
236 if (!get_sample(&sample))
237 return;
238 pressed = (sample.pressure > 0);
239
240 // Only return last sample unless there's a press/release event.
241 while (pressed == wasPressed) {
242 if (!get_sample(&sample))
243 break;
244 pressed = (sample.pressure > 0);
245 }
246
247 // work around missing coordinates on mouse release
248 if (!pressed && sample.x == 0 && sample.y == 0) {
249 sample.x = lastSample.x;
250 sample.y = lastSample.y;
251 }
252
253 int dx = sample.x - lastSample.x;
254 int dy = sample.y - lastSample.y;
255
256 // Remove small movements in oppsite direction
257 if (dx * lastdx < 0 && qAbs(dx) < jitter_limit) {
258 sample.x = lastSample.x;
259 dx = 0;
260 }
261 if (dy * lastdy < 0 && qAbs(dy) < jitter_limit) {
262 sample.y = lastSample.y;
263 dy = 0;
264 }
265
266 if (wasPressed == pressed && dx == 0 && dy == 0)
267 return;
268
269 #ifdef TSLIBMOUSEHANDLER_DEBUG
270 qDebug() << "last" << QPoint(lastSample.x, lastSample.y)
271 << "curr" << QPoint(sample.x, sample.y)
272 << "dx,dy" << QPoint(dx, dy)
273 << "ddx,ddy" << QPoint(dx*lastdx, dy*lastdy)
274 << "pressed" << wasPressed << pressed;
275 #endif
276
277 lastSample = sample;
278 wasPressed = pressed;
279 if (dx != 0)
280 lastdx = dx;
281 if (dy != 0)
282 lastdy = dy;
283
284 const QPoint p(sample.x, sample.y);
285 if (calibrated) {
286 // tslib should do all the translation and filtering, so we send a
287 // "raw" mouse event
288 handler->QWSMouseHandler::mouseChanged(p, pressed);
289 } else {
290 handler->sendFiltered(p, pressed);
291 }
292 }
293 }
294
clearCalibration()295 void QWSTslibMouseHandlerPrivate::clearCalibration()
296 {
297 suspend();
298 close();
299 handler->QWSCalibratedMouseHandler::clearCalibration();
300 calibrated = false;
301 open();
302 resume();
303 }
304
calibrate(const QWSPointerCalibrationData * data)305 void QWSTslibMouseHandlerPrivate::calibrate(const QWSPointerCalibrationData *data)
306 {
307 suspend();
308 close();
309 // default implementation writes to /etc/pointercal
310 // using the same format as the tslib linear module.
311 handler->QWSCalibratedMouseHandler::calibrate(data);
312 calibrated = true;
313 open();
314 resume();
315 }
316
317 /*!
318 \internal
319 */
QWSTslibMouseHandler(const QString & driver,const QString & device)320 QWSTslibMouseHandler::QWSTslibMouseHandler(const QString &driver,
321 const QString &device)
322 : QWSCalibratedMouseHandler(driver, device)
323 {
324 d = new QWSTslibMouseHandlerPrivate(this, device);
325 }
326
327 /*!
328 \internal
329 */
~QWSTslibMouseHandler()330 QWSTslibMouseHandler::~QWSTslibMouseHandler()
331 {
332 delete d;
333 }
334
335 /*!
336 \reimp
337 */
suspend()338 void QWSTslibMouseHandler::suspend()
339 {
340 d->suspend();
341 }
342
343 /*!
344 \reimp
345 */
resume()346 void QWSTslibMouseHandler::resume()
347 {
348 d->resume();
349 }
350
351 /*!
352 \reimp
353 */
clearCalibration()354 void QWSTslibMouseHandler::clearCalibration()
355 {
356 d->clearCalibration();
357 }
358
359 /*!
360 \reimp
361 */
calibrate(const QWSPointerCalibrationData * data)362 void QWSTslibMouseHandler::calibrate(const QWSPointerCalibrationData *data)
363 {
364 d->calibrate(data);
365 }
366
367 QT_END_NAMESPACE
368
369 #include "qmousetslib_qws.moc"
370
371 #endif //QT_NO_QWS_MOUSE_TSLIB
372