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 "qmouselinuxtp_qws.h"
43
44 #ifndef QT_NO_QWS_MOUSE_LINUXTP
45 #include "qwindowsystem_qws.h"
46 #include "qsocketnotifier.h"
47 #include "qtimer.h"
48 #include "qapplication.h"
49 #include "qscreen_qws.h"
50 #include <private/qcore_unix_p.h> // overrides QT_OPEN
51
52 #include <unistd.h>
53 #include <stdlib.h>
54 #include <stdio.h>
55 #include <sys/ioctl.h>
56 #include <sys/types.h>
57 #include <sys/stat.h>
58 #include <fcntl.h>
59 #include <errno.h>
60 #include <termios.h>
61
62 QT_BEGIN_NAMESPACE
63
64 #if defined(QT_QWS_IPAQ)
65 #define QT_QWS_IPAQ_RAW
66 #define QT_QWS_SCREEN_COORDINATES
67 typedef struct {
68 unsigned short pressure;
69 unsigned short x;
70 unsigned short y;
71 unsigned short pad;
72 } TS_EVENT;
73 #elif defined(QT_QWS_EBX)
74 #define QT_QWS_EBX_RAW
75 #define QT_QWS_SCREEN_COORDINATES
76 #ifndef QT_QWS_SHARP
77 typedef struct {
78 unsigned short pressure;
79 unsigned short x;
80 unsigned short y;
81 unsigned short pad;
82 } TS_EVENT;
83 #else
84 typedef struct {
85 long y;
86 long x;
87 long pressure;
88 long long millisecs;
89 } TS_EVENT;
90 #define QT_QWS_TP_SAMPLE_SIZE 10
91 #define QT_QWS_TP_MINIMUM_SAMPLES 4
92 #define QT_QWS_TP_PRESSURE_THRESHOLD 500
93 #define QT_QWS_TP_MOVE_LIMIT 50
94 #define QT_QWS_TP_JITTER_LIMIT 2
95 #endif
96 #else // not IPAQ, not SHARP
97 typedef struct {
98 unsigned short pressure;
99 unsigned short x;
100 unsigned short y;
101 unsigned short pad;
102 } TS_EVENT;
103 #endif
104
105 #ifndef QT_QWS_TP_SAMPLE_SIZE
106 #define QT_QWS_TP_SAMPLE_SIZE 5
107 #endif
108
109 #ifndef QT_QWS_TP_MINIMUM_SAMPLES
110 #define QT_QWS_TP_MINIMUM_SAMPLES 5
111 #endif
112
113 #ifndef QT_QWS_TP_PRESSURE_THRESHOLD
114 #define QT_QWS_TP_PRESSURE_THRESHOLD 1
115 #endif
116
117 #ifndef QT_QWS_TP_MOVE_LIMIT
118 #define QT_QWS_TP_MOVE_LIMIT 100
119 #endif
120
121 #ifndef QT_QWS_TP_JITTER_LIMIT
122 #define QT_QWS_TP_JITTER_LIMIT 2
123 #endif
124
125 class QWSLinuxTPMouseHandlerPrivate : public QObject
126 {
127 Q_OBJECT
128 public:
129 QWSLinuxTPMouseHandlerPrivate(QWSLinuxTPMouseHandler *h, const QString &);
130 ~QWSLinuxTPMouseHandlerPrivate();
131
132 void suspend();
133 void resume();
134 private:
135 static const int mouseBufSize = 2048;
136 int mouseFD;
137 QPoint oldmouse;
138 QPoint oldTotalMousePos;
139 bool waspressed;
140 QPolygon samples;
141 int currSample;
142 int lastSample;
143 int numSamples;
144 int skipCount;
145 int mouseIdx;
146 uchar mouseBuf[mouseBufSize];
147 QWSLinuxTPMouseHandler *handler;
148 QSocketNotifier *mouseNotifier;
149
150 private slots:
151 void readMouseData();
152 };
153
QWSLinuxTPMouseHandler(const QString & driver,const QString & device)154 QWSLinuxTPMouseHandler::QWSLinuxTPMouseHandler(const QString &driver, const QString &device)
155 : QWSCalibratedMouseHandler(driver, device)
156 {
157 d = new QWSLinuxTPMouseHandlerPrivate(this, device);
158 }
159
~QWSLinuxTPMouseHandler()160 QWSLinuxTPMouseHandler::~QWSLinuxTPMouseHandler()
161 {
162 delete d;
163 }
164
suspend()165 void QWSLinuxTPMouseHandler::suspend()
166 {
167 d->suspend();
168 }
169
resume()170 void QWSLinuxTPMouseHandler::resume()
171 {
172 d->resume();
173 }
174
QWSLinuxTPMouseHandlerPrivate(QWSLinuxTPMouseHandler * h,const QString & device)175 QWSLinuxTPMouseHandlerPrivate::QWSLinuxTPMouseHandlerPrivate(QWSLinuxTPMouseHandler *h,
176 const QString &device)
177 : samples(QT_QWS_TP_SAMPLE_SIZE), currSample(0), lastSample(0),
178 numSamples(0), skipCount(0), handler(h)
179 {
180 QString mousedev;
181 if (device.isEmpty()) {
182 #if defined(QT_QWS_IPAQ)
183 # ifdef QT_QWS_IPAQ_RAW
184 mousedev = QLatin1String("/dev/h3600_tsraw");
185 # else
186 mousedev = QLatin1String("/dev/h3600_ts");
187 # endif
188 #else
189 mousedev = QLatin1String("/dev/ts");
190 #endif
191 } else {
192 mousedev = device;
193 }
194 if ((mouseFD = QT_OPEN(mousedev.toLatin1().constData(), O_RDONLY | O_NDELAY)) < 0) {
195 qWarning("Cannot open %s (%s)", qPrintable(mousedev), strerror(errno));
196 return;
197 }
198
199 mouseNotifier = new QSocketNotifier(mouseFD, QSocketNotifier::Read,
200 this);
201 connect(mouseNotifier, SIGNAL(activated(int)),this, SLOT(readMouseData()));
202 waspressed=false;
203 mouseIdx = 0;
204 }
205
~QWSLinuxTPMouseHandlerPrivate()206 QWSLinuxTPMouseHandlerPrivate::~QWSLinuxTPMouseHandlerPrivate()
207 {
208 if (mouseFD >= 0)
209 QT_CLOSE(mouseFD);
210 }
211
suspend()212 void QWSLinuxTPMouseHandlerPrivate::suspend()
213 {
214 if (mouseNotifier)
215 mouseNotifier->setEnabled(false);
216 }
217
resume()218 void QWSLinuxTPMouseHandlerPrivate::resume()
219 {
220 mouseIdx=0;
221 currSample=0;
222 lastSample=0;
223 numSamples=0;
224 skipCount=0;
225 if (mouseNotifier)
226 mouseNotifier->setEnabled(true);
227 }
228
229
readMouseData()230 void QWSLinuxTPMouseHandlerPrivate::readMouseData()
231 {
232 if(!qt_screen)
233 return;
234
235 int n;
236 do {
237 n = QT_READ(mouseFD, mouseBuf+mouseIdx, mouseBufSize-mouseIdx);
238 if (n > 0)
239 mouseIdx += n;
240 } while (n > 0 && mouseIdx < mouseBufSize);
241
242 //qDebug("readMouseData()");
243
244 TS_EVENT *data;
245 int idx = 0;
246
247 // perhaps we shouldn't be reading EVERY SAMPLE.
248 while (mouseIdx-idx >= (int)sizeof(TS_EVENT)) {
249 uchar *mb = mouseBuf+idx;
250 data = (TS_EVENT *) mb;
251
252 if(data->pressure >= QT_QWS_TP_PRESSURE_THRESHOLD) {
253 #ifdef QT_QWS_SHARP
254 samples[currSample] = QPoint(1000 - data->x, data->y);
255 #else
256 samples[currSample] = QPoint(data->x, data->y);
257 #endif
258 numSamples++;
259 if (numSamples >= QT_QWS_TP_MINIMUM_SAMPLES) {
260 int sampleCount = qMin(numSamples + 1,samples.count());
261
262 // average the rest
263 QPoint mousePos = QPoint(0, 0);
264 QPoint totalMousePos = oldTotalMousePos;
265 totalMousePos += samples[currSample];
266 if(numSamples >= samples.count())
267 totalMousePos -= samples[lastSample];
268
269 mousePos = totalMousePos / (sampleCount - 1);
270 #if defined(QT_QWS_SCREEN_COORDINATES)
271 mousePos = handler->transform(mousePos);
272 #endif
273 if(!waspressed)
274 oldmouse = mousePos;
275 QPoint dp = mousePos - oldmouse;
276 int dxSqr = dp.x() * dp.x();
277 int dySqr = dp.y() * dp.y();
278 if (dxSqr + dySqr < (QT_QWS_TP_MOVE_LIMIT * QT_QWS_TP_MOVE_LIMIT)) {
279 if (waspressed) {
280 if ((dxSqr + dySqr > (QT_QWS_TP_JITTER_LIMIT * QT_QWS_TP_JITTER_LIMIT)) || skipCount > 2) {
281 handler->mouseChanged(mousePos,Qt::LeftButton);
282 oldmouse = mousePos;
283 skipCount = 0;
284 } else {
285 skipCount++;
286 }
287 } else {
288 handler->mouseChanged(mousePos,Qt::LeftButton);
289 oldmouse=mousePos;
290 waspressed=true;
291 }
292
293 // save recuring information
294 currSample++;
295 if (numSamples >= samples.count())
296 lastSample++;
297 oldTotalMousePos = totalMousePos;
298 } else {
299 numSamples--; // don't use this sample, it was bad.
300 }
301 } else {
302 // build up the average
303 oldTotalMousePos += samples[currSample];
304 currSample++;
305 }
306 if (currSample >= samples.count())
307 currSample = 0;
308 if (lastSample >= samples.count())
309 lastSample = 0;
310 } else {
311 currSample = 0;
312 lastSample = 0;
313 numSamples = 0;
314 skipCount = 0;
315 oldTotalMousePos = QPoint(0,0);
316 if (waspressed) {
317 handler->mouseChanged(oldmouse,0);
318 oldmouse = QPoint(-100, -100);
319 waspressed=false;
320 }
321 }
322 idx += sizeof(TS_EVENT);
323 }
324
325 int surplus = mouseIdx - idx;
326 for (int i = 0; i < surplus; i++)
327 mouseBuf[i] = mouseBuf[idx+i];
328 mouseIdx = surplus;
329 }
330
331 QT_END_NAMESPACE
332
333 #include "qmouselinuxtp_qws.moc"
334
335 #endif //QT_NO_QWS_MOUSE_LINUXTP
336