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