author | Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com> |
Fri, 19 Feb 2010 23:40:16 +0200 | |
branch | RCL_3 |
changeset 4 | 3b1da2848fc7 |
parent 0 | 1918ee327afb |
permissions | -rw-r--r-- |
0 | 1 |
/**************************************************************************** |
2 |
** |
|
4
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
3 |
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
0 | 4 |
** All rights reserved. |
5 |
** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 |
** |
|
7 |
** This file is part of the QtGui module of the Qt Toolkit. |
|
8 |
** |
|
9 |
** $QT_BEGIN_LICENSE:LGPL$ |
|
10 |
** No Commercial Usage |
|
11 |
** This file contains pre-release code and may not be distributed. |
|
12 |
** You may use this file in accordance with the terms and conditions |
|
13 |
** contained in the Technology Preview License Agreement accompanying |
|
14 |
** this package. |
|
15 |
** |
|
16 |
** GNU Lesser General Public License Usage |
|
17 |
** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 |
** General Public License version 2.1 as published by the Free Software |
|
19 |
** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 |
** packaging of this file. Please review the following information to |
|
21 |
** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 |
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 |
** |
|
24 |
** In addition, as a special exception, Nokia gives you certain additional |
|
25 |
** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 |
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 |
** |
|
28 |
** If you have questions regarding the use of this file, please contact |
|
29 |
** Nokia at qt-info@nokia.com. |
|
30 |
** |
|
31 |
** |
|
32 |
** |
|
33 |
** |
|
34 |
** |
|
35 |
** |
|
36 |
** |
|
37 |
** |
|
38 |
** $QT_END_LICENSE$ |
|
39 |
** |
|
40 |
****************************************************************************/ |
|
41 |
||
42 |
#include "qmouse_qws.h" |
|
43 |
#include "qwindowsystem_qws.h" |
|
44 |
#include "qscreen_qws.h" |
|
45 |
#include "qapplication.h" |
|
46 |
#include "qtextstream.h" |
|
47 |
#include "qfile.h" |
|
48 |
#include "qdebug.h" |
|
49 |
#include "qscreen_qws.h" |
|
50 |
||
51 |
QT_BEGIN_NAMESPACE |
|
52 |
||
53 |
/*! |
|
54 |
\class QWSPointerCalibrationData |
|
55 |
\ingroup qws |
|
56 |
||
57 |
\brief The QWSPointerCalibrationData class is a container for |
|
58 |
mouse calibration data in Qt for Embedded Linux. |
|
59 |
||
60 |
Note that this class is only available in \l{Qt for Embedded Linux}. |
|
61 |
||
62 |
QWSPointerCalibrationData stores device and screen coordinates in |
|
63 |
the devPoints and screenPoints variables, respectively. |
|
64 |
||
65 |
A calibration program should create a QWSPointerCalibrationData |
|
66 |
object, fill the devPoints and screenPoints variables with its |
|
67 |
device and screen coordinates, and pass the object to the mouse |
|
68 |
driver using the QWSMouseHandler::calibrate() function. |
|
69 |
||
70 |
\sa QWSCalibratedMouseHandler, {Mouse Calibration Example} |
|
71 |
*/ |
|
72 |
||
73 |
/*! |
|
74 |
\variable QWSPointerCalibrationData::devPoints |
|
75 |
\brief the raw device coordinates for each value of the Location enum. |
|
76 |
*/ |
|
77 |
||
78 |
/*! |
|
79 |
\variable QWSPointerCalibrationData::screenPoints |
|
80 |
\brief the logical screen coordinates for each value of the Location enum. |
|
81 |
*/ |
|
82 |
||
83 |
/*! |
|
84 |
\enum QWSPointerCalibrationData::Location |
|
85 |
||
86 |
This enum describes the various logical positions that can be |
|
87 |
specified by the devPoints and screenPoints variables. |
|
88 |
||
89 |
\value TopLeft Index of the top left corner of the screen. |
|
90 |
\value BottomLeft Index of the bottom left corner of the screen. |
|
91 |
\value BottomRight Index of the bottom right corner of the screen. |
|
92 |
\value TopRight Index of the top right corner of the screen. |
|
93 |
\value Center Index of the center of the screen. |
|
94 |
\value LastLocation Last index in the pointer arrays. |
|
95 |
*/ |
|
96 |
||
97 |
class QWSMouseHandlerPrivate |
|
98 |
{ |
|
99 |
public: |
|
100 |
QWSMouseHandlerPrivate() : screen(qt_screen) {} |
|
101 |
||
102 |
const QScreen *screen; |
|
103 |
}; |
|
104 |
||
105 |
/*! |
|
106 |
\class QWSMouseHandler |
|
107 |
\ingroup qws |
|
108 |
||
109 |
\brief The QWSMouseHandler class is a base class for mouse drivers in |
|
110 |
Qt for Embedded Linux. |
|
111 |
||
112 |
Note that this class is only available in \l{Qt for Embedded Linux}. |
|
113 |
||
114 |
\l{Qt for Embedded Linux} provides ready-made drivers for several mouse |
|
115 |
protocols, see the \l{Qt for Embedded Linux Pointer Handling}{pointer |
|
116 |
handling} documentation for details. Custom mouse drivers can be |
|
117 |
implemented by subclassing the QWSMouseHandler class and creating |
|
118 |
a mouse driver plugin (derived from QMouseDriverPlugin). |
|
119 |
The default implementation of the QMouseDriverFactory class |
|
120 |
will automatically detect the plugin, and load the driver into the |
|
121 |
server application at run-time using Qt's \l {How to Create Qt |
|
122 |
Plugins}{plugin system}. |
|
123 |
||
124 |
The mouse driver receives mouse events from the system device and |
|
125 |
encapsulates each event with an instance of the QWSEvent class |
|
126 |
which it then passes to the server application (the server is |
|
127 |
responsible for propagating the event to the appropriate |
|
128 |
client). To receive mouse events, a QWSMouseHandler object will |
|
129 |
usually create a QSocketNotifier object for the given device. The |
|
130 |
QSocketNotifier class provides support for monitoring activity on |
|
131 |
a file descriptor. When the socket notifier receives data, it will |
|
132 |
call the mouse driver's mouseChanged() function to send the event |
|
133 |
to the \l{Qt for Embedded Linux} server application for relaying to |
|
134 |
clients. |
|
135 |
||
136 |
If you are creating a driver for a device that needs calibration |
|
137 |
or noise reduction, such as a touchscreen, use the |
|
138 |
QWSCalibratedMouseHandler subclass instead to take advantage of |
|
139 |
the calibrate() and clearCalibration() functions. The \l |
|
140 |
{qws/mousecalibration}{Mouse Calibration} |
|
141 |
demonstrates how to write a simple program using the mechanisms |
|
142 |
provided by the QWSMouseHandler class to calibrate a mouse driver. |
|
143 |
||
144 |
Note that when deriving from the QWSMouseHandler class, the |
|
145 |
resume() and suspend() functions must be reimplemented to control |
|
146 |
the flow of mouse input, i.e., the default implementation does |
|
147 |
nothing. Reimplementations of these functions typically call the |
|
148 |
QSocketNotifier::setEnabled() function to enable or disable the |
|
149 |
socket notifier, respectively. |
|
150 |
||
151 |
In addition, QWSMouseHandler provides the setScreen() function |
|
152 |
that allows you to specify a screen for your mouse driver and the |
|
153 |
limitToScreen() function that ensures that a given position is |
|
154 |
within this screen's boundaries (changing the position if |
|
155 |
necessary). Finally, QWSMouseHandler provides the pos() function |
|
156 |
returning the current mouse position. |
|
157 |
||
158 |
\sa QMouseDriverPlugin, QMouseDriverFactory, {Qt for Embedded Linux Pointer |
|
159 |
Handling} |
|
160 |
*/ |
|
161 |
||
162 |
||
163 |
/*! |
|
164 |
\fn void QWSMouseHandler::suspend() |
|
165 |
||
166 |
Implement this function to suspend reading and handling of mouse |
|
167 |
events, e.g., call the QSocketNotifier::setEnabled() function to |
|
168 |
disable the socket notifier. |
|
169 |
||
170 |
\sa resume() |
|
171 |
*/ |
|
172 |
||
173 |
/*! |
|
174 |
\fn void QWSMouseHandler::resume() |
|
175 |
||
176 |
Implement this function to resume reading and handling mouse |
|
177 |
events, e.g., call the QSocketNotifier::setEnabled() function to |
|
178 |
enable the socket notifier. |
|
179 |
||
180 |
\sa suspend() |
|
181 |
*/ |
|
182 |
||
183 |
/*! |
|
184 |
\fn const QPoint &QWSMouseHandler::pos() const |
|
185 |
||
186 |
Returns the current mouse position. |
|
187 |
||
188 |
\sa mouseChanged(), limitToScreen() |
|
189 |
*/ |
|
190 |
||
191 |
/*! |
|
192 |
Constructs a mouse driver. The \a driver and \a device arguments |
|
193 |
are passed by the QWS_MOUSE_PROTO environment variable. |
|
194 |
||
195 |
Call the QWSServer::setMouseHandler() function to make the newly |
|
196 |
created mouse driver, the primary driver. Note that the primary |
|
197 |
driver is controlled by the system, i.e., the system will delete |
|
198 |
it upon exit. |
|
199 |
*/ |
|
200 |
QWSMouseHandler::QWSMouseHandler(const QString &, const QString &) |
|
201 |
: mousePos(QWSServer::mousePosition), d_ptr(new QWSMouseHandlerPrivate) |
|
202 |
{ |
|
203 |
} |
|
204 |
||
205 |
/*! |
|
206 |
Destroys this mouse driver. |
|
207 |
||
208 |
Do not call this function if this driver is the primary mouse |
|
209 |
driver, i.e., if QWSServer::setMouseHandler() function has been |
|
210 |
called passing this driver as argument. The primary mouse |
|
211 |
driver is deleted by the system. |
|
212 |
*/ |
|
213 |
QWSMouseHandler::~QWSMouseHandler() |
|
214 |
{ |
|
215 |
delete d_ptr; |
|
216 |
} |
|
217 |
||
218 |
/*! |
|
219 |
Ensures that the given \a position is within the screen's |
|
220 |
boundaries, changing the \a position if necessary. |
|
221 |
||
222 |
\sa pos(), setScreen() |
|
223 |
*/ |
|
224 |
||
225 |
void QWSMouseHandler::limitToScreen(QPoint &position) |
|
226 |
{ |
|
227 |
position.setX(qMin(d_ptr->screen->deviceWidth() - 1, qMax(0, position.x()))); |
|
228 |
position.setY(qMin(d_ptr->screen->deviceHeight() - 1, qMax(0, position.y()))); |
|
229 |
} |
|
230 |
||
231 |
/*! |
|
232 |
\since 4.2 |
|
233 |
||
234 |
Sets the screen for this mouse driver to be the given \a screen. |
|
235 |
||
236 |
\sa limitToScreen() |
|
237 |
*/ |
|
238 |
void QWSMouseHandler::setScreen(const QScreen *screen) |
|
239 |
{ |
|
240 |
d_ptr->screen = (screen ? screen : qt_screen); |
|
241 |
} |
|
242 |
||
243 |
/*! |
|
244 |
Notifies the system of a new mouse event. |
|
245 |
||
246 |
This function updates the current mouse position and sends the |
|
247 |
event to the \l{Qt for Embedded Linux} server application for |
|
248 |
delivery to the correct widget. Note that a custom mouse driver must call |
|
249 |
this function whenever it wants to deliver a new mouse event. |
|
250 |
||
251 |
The given \a position is the global position of the mouse cursor. |
|
252 |
The \a state parameter is a bitmask of the Qt::MouseButton enum's |
|
253 |
values, indicating which mouse buttons are pressed. The \a wheel |
|
254 |
parameter is the delta value of the mouse wheel as returned by |
|
255 |
QWheelEvent::delta(). |
|
256 |
||
257 |
\sa pos() |
|
258 |
*/ |
|
259 |
void QWSMouseHandler::mouseChanged(const QPoint &position, int state, int wheel) |
|
260 |
{ |
|
261 |
mousePos = position + d_ptr->screen->offset(); |
|
262 |
QWSServer::sendMouseEvent(mousePos, state, wheel); |
|
263 |
} |
|
264 |
||
265 |
/*! |
|
266 |
\fn QWSMouseHandler::clearCalibration() |
|
267 |
||
268 |
This virtual function allows subclasses of QWSMouseHandler to |
|
269 |
clear the calibration information. Note that the default |
|
270 |
implementation does nothing. |
|
271 |
||
272 |
\sa QWSCalibratedMouseHandler::clearCalibration(), calibrate() |
|
273 |
*/ |
|
274 |
||
275 |
/*! |
|
276 |
\fn QWSMouseHandler::calibrate(const QWSPointerCalibrationData *data) |
|
277 |
||
278 |
This virtual function allows subclasses of QWSMouseHandler to set |
|
279 |
the calibration information passed in the given \a data. Note that |
|
280 |
the default implementation does nothing. |
|
281 |
||
282 |
\sa QWSCalibratedMouseHandler::calibrate(), clearCalibration() |
|
283 |
*/ |
|
284 |
||
285 |
/*! \fn QWSMouseHandler::getCalibration(QWSPointerCalibrationData *data) const |
|
286 |
This virtual function allows subclasses of QWSMouseHandler |
|
287 |
to fill in the device coordinates in \a data with values |
|
288 |
that correspond to screen coordinates that are already in |
|
289 |
\a data. Note that the default implementation does nothing. |
|
290 |
*/ |
|
291 |
||
292 |
/*! |
|
293 |
\class QWSCalibratedMouseHandler |
|
294 |
\ingroup qws |
|
295 |
||
296 |
\brief The QWSCalibratedMouseHandler class provides mouse |
|
297 |
calibration and noise reduction in Qt for Embedded Linux. |
|
298 |
||
299 |
Note that this class is only available in \l{Qt for Embedded Linux}. |
|
300 |
||
301 |
\l{Qt for Embedded Linux} provides ready-made drivers for several mouse |
|
302 |
protocols, see the \l{Qt for Embedded Linux Pointer Handling}{pointer |
|
303 |
handling} documentation for details. In general, custom mouse |
|
304 |
drivers can be implemented by subclassing the QWSMouseHandler |
|
305 |
class. But when the system device does not have a fixed mapping |
|
306 |
between device and screen coordinates and/or produces noisy events |
|
307 |
(e.g., a touchscreen), you should derive from the |
|
308 |
QWSCalibratedMouseHandler class instead to take advantage of its |
|
309 |
calibration functionality. As always, you must also create a mouse |
|
310 |
driver plugin (derived from QMouseDriverPlugin); |
|
311 |
the implementation of the QMouseDriverFactory class will then |
|
312 |
automatically detect the plugin, and load the driver into the |
|
313 |
server application at run-time using Qt's |
|
314 |
\l{How to Create Qt Plugins}{plugin system}. |
|
315 |
||
316 |
QWSCalibratedMouseHandler provides an implementation of the |
|
317 |
calibrate() function to update the calibration parameters based on |
|
318 |
coordinate mapping of the given calibration data. The calibration |
|
319 |
data is represented by an QWSPointerCalibrationData object. The |
|
320 |
linear transformation between device coordinates and screen |
|
321 |
coordinates is performed by calling the transform() function |
|
322 |
explicitly on the points passed to the |
|
323 |
QWSMouseHandler::mouseChanged() function. Use the |
|
324 |
clearCalibration() function to make the mouse driver return mouse |
|
325 |
events in raw device coordinates and not in screen coordinates. |
|
326 |
||
327 |
The calibration parameters are recalculated whenever calibrate() |
|
328 |
is called, and they can be stored using the writeCalibration() |
|
329 |
function. Previously written parameters can be retrieved at any |
|
330 |
time using the readCalibration() function (calibration parameters |
|
331 |
are always read when the class is instantiated). Note that the |
|
332 |
calibration parameters is written to and read from the file |
|
333 |
currently specified by the POINTERCAL_FILE environment variable; |
|
334 |
the default file is \c /etc/pointercal. |
|
335 |
||
336 |
To achieve noise reduction, QWSCalibratedMouseHandler provides the |
|
337 |
sendFiltered() function. Use this function instead of |
|
338 |
mouseChanged() whenever a mouse event occurs. The filter's size |
|
339 |
can be manipulated using the setFilterSize() function. |
|
340 |
||
341 |
\sa QWSMouseHandler, QWSPointerCalibrationData, |
|
342 |
{Mouse Calibration Example} |
|
343 |
*/ |
|
344 |
||
345 |
||
346 |
/*! |
|
347 |
\internal |
|
348 |
*/ |
|
349 |
||
350 |
QWSCalibratedMouseHandler::QWSCalibratedMouseHandler(const QString &, const QString &) |
|
351 |
: samples(5), currSample(0), numSamples(0) |
|
352 |
{ |
|
353 |
clearCalibration(); |
|
354 |
readCalibration(); |
|
355 |
} |
|
356 |
||
357 |
/*! |
|
358 |
Fills \a cd with the device coordinates corresponding to the given |
|
359 |
screen coordinates. |
|
360 |
||
361 |
\internal |
|
362 |
*/ |
|
363 |
void QWSCalibratedMouseHandler::getCalibration(QWSPointerCalibrationData *cd) const |
|
364 |
{ |
|
365 |
const qint64 scale = qint64(a) * qint64(e) - qint64(b) * qint64(d); |
|
366 |
const qint64 xOff = qint64(b) * qint64(f) - qint64(c) * qint64(e); |
|
367 |
const qint64 yOff = qint64(c) * qint64(d) - qint64(a) * qint64(f); |
|
368 |
for (int i = 0; i <= QWSPointerCalibrationData::LastLocation; ++i) { |
|
369 |
const qint64 sX = cd->screenPoints[i].x(); |
|
370 |
const qint64 sY = cd->screenPoints[i].y(); |
|
371 |
const qint64 dX = (s*(e*sX - b*sY) + xOff) / scale; |
|
372 |
const qint64 dY = (s*(a*sY - d*sX) + yOff) / scale; |
|
373 |
cd->devPoints[i] = QPoint(dX, dY); |
|
374 |
} |
|
375 |
} |
|
376 |
||
377 |
/*! |
|
378 |
Clears the current calibration, i.e., makes the mouse |
|
379 |
driver return mouse events in raw device coordinates instead of |
|
380 |
screen coordinates. |
|
381 |
||
382 |
\sa calibrate() |
|
383 |
*/ |
|
384 |
void QWSCalibratedMouseHandler::clearCalibration() |
|
385 |
{ |
|
386 |
a = 1; |
|
387 |
b = 0; |
|
388 |
c = 0; |
|
389 |
d = 0; |
|
390 |
e = 1; |
|
391 |
f = 0; |
|
392 |
s = 1; |
|
393 |
} |
|
394 |
||
395 |
||
396 |
/*! |
|
397 |
Saves the current calibration parameters in \c /etc/pointercal |
|
398 |
(separated by whitespace and in alphabetical order). |
|
399 |
||
400 |
You can override the default \c /etc/pointercal by specifying |
|
401 |
another file using the POINTERCAL_FILE environment variable. |
|
402 |
||
403 |
\sa readCalibration() |
|
404 |
*/ |
|
405 |
void QWSCalibratedMouseHandler::writeCalibration() |
|
406 |
{ |
|
407 |
QString calFile; |
|
408 |
calFile = QString::fromLocal8Bit(qgetenv("POINTERCAL_FILE")); |
|
409 |
if (calFile.isEmpty()) |
|
410 |
calFile = QLatin1String("/etc/pointercal"); |
|
411 |
||
412 |
#ifndef QT_NO_TEXTSTREAM |
|
413 |
QFile file(calFile); |
|
414 |
if (file.open(QIODevice::WriteOnly)) { |
|
415 |
QTextStream t(&file); |
|
416 |
t << a << ' ' << b << ' ' << c << ' '; |
|
417 |
t << d << ' ' << e << ' ' << f << ' ' << s << endl; |
|
418 |
} else |
|
419 |
#endif |
|
420 |
{ |
|
421 |
qCritical("QWSCalibratedMouseHandler::writeCalibration: " |
|
422 |
"Could not save calibration into %s", qPrintable(calFile)); |
|
423 |
} |
|
424 |
} |
|
425 |
||
426 |
/*! |
|
427 |
Reads previously written calibration parameters which are stored |
|
428 |
in \c /etc/pointercal (separated by whitespace and in alphabetical |
|
429 |
order). |
|
430 |
||
431 |
You can override the default \c /etc/pointercal by specifying |
|
432 |
another file using the POINTERCAL_FILE environment variable. |
|
433 |
||
434 |
||
435 |
\sa writeCalibration() |
|
436 |
*/ |
|
437 |
void QWSCalibratedMouseHandler::readCalibration() |
|
438 |
{ |
|
439 |
QString calFile = QString::fromLocal8Bit(qgetenv("POINTERCAL_FILE")); |
|
440 |
if (calFile.isEmpty()) |
|
441 |
calFile = QLatin1String("/etc/pointercal"); |
|
442 |
||
443 |
#ifndef QT_NO_TEXTSTREAM |
|
444 |
QFile file(calFile); |
|
445 |
if (file.open(QIODevice::ReadOnly)) { |
|
446 |
QTextStream t(&file); |
|
447 |
t >> a >> b >> c >> d >> e >> f >> s; |
|
448 |
if (s == 0 || t.status() != QTextStream::Ok) { |
|
449 |
qCritical("Corrupt calibration data"); |
|
450 |
clearCalibration(); |
|
451 |
} |
|
452 |
} else |
|
453 |
#endif |
|
454 |
{ |
|
455 |
qDebug() << "Could not read calibration:" <<calFile; |
|
456 |
} |
|
457 |
} |
|
458 |
||
459 |
static int ilog2(quint32 n) |
|
460 |
{ |
|
461 |
int result = 0; |
|
462 |
||
463 |
if (n & 0xffff0000) { |
|
464 |
n >>= 16; |
|
465 |
result += 16; |
|
466 |
} |
|
467 |
if (n & 0xff00) { |
|
468 |
n >>= 8; |
|
469 |
result += 8;} |
|
470 |
if (n & 0xf0) { |
|
471 |
n >>= 4; |
|
472 |
result += 4; |
|
473 |
} |
|
474 |
if (n & 0xc) { |
|
475 |
n >>= 2; |
|
476 |
result += 2; |
|
477 |
} |
|
478 |
if (n & 0x2) |
|
479 |
result += 1; |
|
480 |
||
481 |
return result; |
|
482 |
} |
|
483 |
||
484 |
/*! |
|
485 |
Updates the calibration parameters based on coordinate mapping of |
|
486 |
the given \a data. |
|
487 |
||
488 |
Create an instance of the QWSPointerCalibrationData class, fill in |
|
489 |
the device and screen coordinates and pass that object to the mouse |
|
490 |
driver using this function. |
|
491 |
||
492 |
\sa clearCalibration(), transform() |
|
493 |
*/ |
|
494 |
void QWSCalibratedMouseHandler::calibrate(const QWSPointerCalibrationData *data) |
|
495 |
{ |
|
496 |
// Algorithm derived from |
|
497 |
// "How To Calibrate Touch Screens" by Carlos E. Vidales, |
|
498 |
// printed in Embedded Systems Programming, Vol. 15 no 6, June 2002 |
|
499 |
// URL: http://www.embedded.com/showArticle.jhtml?articleID=9900629 |
|
500 |
||
501 |
const QPoint pd0 = data->devPoints[QWSPointerCalibrationData::TopLeft]; |
|
502 |
const QPoint pd1 = data->devPoints[QWSPointerCalibrationData::TopRight]; |
|
503 |
const QPoint pd2 = data->devPoints[QWSPointerCalibrationData::BottomRight]; |
|
504 |
const QPoint p0 = data->screenPoints[QWSPointerCalibrationData::TopLeft]; |
|
505 |
const QPoint p1 = data->screenPoints[QWSPointerCalibrationData::TopRight]; |
|
506 |
const QPoint p2 = data->screenPoints[QWSPointerCalibrationData::BottomRight]; |
|
507 |
||
508 |
const qint64 xd0 = pd0.x(); |
|
509 |
const qint64 xd1 = pd1.x(); |
|
510 |
const qint64 xd2 = pd2.x(); |
|
511 |
const qint64 yd0 = pd0.y(); |
|
512 |
const qint64 yd1 = pd1.y(); |
|
513 |
const qint64 yd2 = pd2.y(); |
|
514 |
const qint64 x0 = p0.x(); |
|
515 |
const qint64 x1 = p1.x(); |
|
516 |
const qint64 x2 = p2.x(); |
|
517 |
const qint64 y0 = p0.y(); |
|
518 |
const qint64 y1 = p1.y(); |
|
519 |
const qint64 y2 = p2.y(); |
|
520 |
||
521 |
qint64 scale = ((xd0 - xd2)*(yd1 - yd2) - (xd1 - xd2)*(yd0 - yd2)); |
|
522 |
int shift = 0; |
|
523 |
qint64 absScale = qAbs(scale); |
|
524 |
// use maximum 16 bit precision to reduce risk of integer overflow |
|
525 |
if (absScale > (1 << 16)) { |
|
526 |
shift = ilog2(absScale >> 16) + 1; |
|
527 |
scale >>= shift; |
|
528 |
} |
|
529 |
||
530 |
s = scale; |
|
531 |
a = ((x0 - x2)*(yd1 - yd2) - (x1 - x2)*(yd0 - yd2)) >> shift; |
|
532 |
b = ((xd0 - xd2)*(x1 - x2) - (x0 - x2)*(xd1 - xd2)) >> shift; |
|
533 |
c = (yd0*(xd2*x1 - xd1*x2) + yd1*(xd0*x2 - xd2*x0) + yd2*(xd1*x0 - xd0*x1)) >> shift; |
|
534 |
d = ((y0 - y2)*(yd1 - yd2) - (y1 - y2)*(yd0 - yd2)) >> shift; |
|
535 |
e = ((xd0 - xd2)*(y1 - y2) - (y0 - y2)*(xd1 - xd2)) >> shift; |
|
536 |
f = (yd0*(xd2*y1 - xd1*y2) + yd1*(xd0*y2 - xd2*y0) + yd2*(xd1*y0 - xd0*y1)) >> shift; |
|
537 |
||
538 |
writeCalibration(); |
|
539 |
} |
|
540 |
||
541 |
/*! |
|
542 |
Transforms the given \a position from device coordinates to screen |
|
543 |
coordinates, and returns the transformed position. |
|
544 |
||
545 |
This function is typically called explicitly on the points passed |
|
546 |
to the QWSMouseHandler::mouseChanged() function. |
|
547 |
||
548 |
This implementation is a linear transformation using 7 parameters |
|
549 |
(\c a, \c b, \c c, \c d, \c e, \c f and \c s) to transform the |
|
550 |
device coordinates (\c Xd, \c Yd) into screen coordinates (\c Xs, |
|
551 |
\c Ys) using the following equations: |
|
552 |
||
553 |
\snippet doc/src/snippets/code/src_gui_embedded_qmouse_qws.cpp 0 |
|
554 |
||
555 |
\sa mouseChanged() |
|
556 |
*/ |
|
557 |
QPoint QWSCalibratedMouseHandler::transform(const QPoint &position) |
|
558 |
{ |
|
559 |
QPoint tp; |
|
560 |
||
561 |
tp.setX((a * position.x() + b * position.y() + c) / s); |
|
562 |
tp.setY((d * position.x() + e * position.y() + f) / s); |
|
563 |
||
564 |
return tp; |
|
565 |
} |
|
566 |
||
567 |
/*! |
|
568 |
Sets the size of the filter used in noise reduction to the given |
|
569 |
\a size. |
|
570 |
||
571 |
The sendFiltered() function reduces noice by calculating an |
|
572 |
average position from a collection of mouse event positions. The |
|
573 |
filter size determines the number of positions that forms the |
|
574 |
basis for these calculations. |
|
575 |
||
576 |
\sa sendFiltered() |
|
577 |
*/ |
|
578 |
void QWSCalibratedMouseHandler::setFilterSize(int size) |
|
579 |
{ |
|
580 |
samples.resize(qMax(1, size)); |
|
581 |
numSamples = 0; |
|
582 |
currSample = 0; |
|
583 |
} |
|
584 |
||
585 |
/*! |
|
586 |
\fn bool QWSCalibratedMouseHandler::sendFiltered(const QPoint &position, int state) |
|
587 |
||
588 |
Notifies the system of a new mouse event \e after applying a noise |
|
589 |
reduction filter. Returns true if the filtering process is |
|
590 |
successful; otherwise returns false. Note that if the filtering |
|
591 |
process failes, the system is not notified about the event. |
|
592 |
||
593 |
The given \a position is the global position of the mouse. The \a |
|
594 |
state parameter is a bitmask of the Qt::MouseButton enum's values |
|
595 |
indicating which mouse buttons are pressed. |
|
596 |
||
597 |
The noice is reduced by calculating an average position from a |
|
598 |
collection of mouse event positions and then calling the |
|
599 |
mouseChanged() function with the new position. The number of |
|
600 |
positions that is used is determined by the filter size. |
|
601 |
||
602 |
\sa mouseChanged(), setFilterSize() |
|
603 |
*/ |
|
604 |
bool QWSCalibratedMouseHandler::sendFiltered(const QPoint &position, int button) |
|
605 |
{ |
|
606 |
if (!button) { |
|
607 |
if (numSamples >= samples.count()) |
|
608 |
mouseChanged(transform(position), 0); |
|
609 |
currSample = 0; |
|
610 |
numSamples = 0; |
|
611 |
return true; |
|
612 |
} |
|
613 |
||
614 |
bool sent = false; |
|
615 |
samples[currSample] = position; |
|
616 |
numSamples++; |
|
617 |
if (numSamples >= samples.count()) { |
|
618 |
||
619 |
int ignore = -1; |
|
620 |
if (samples.count() > 2) { // throw away the "worst" sample |
|
621 |
int maxd = 0; |
|
622 |
for (int i = 0; i < samples.count(); i++) { |
|
623 |
int d = (mousePos - samples[i]).manhattanLength(); |
|
624 |
if (d > maxd) { |
|
625 |
maxd = d; |
|
626 |
ignore = i; |
|
627 |
} |
|
628 |
} |
|
629 |
} |
|
630 |
||
631 |
// average the rest |
|
632 |
QPoint pos(0, 0); |
|
633 |
int numAveraged = 0; |
|
634 |
for (int i = 0; i < samples.count(); i++) { |
|
635 |
if (ignore == i) |
|
636 |
continue; |
|
637 |
pos += samples[i]; |
|
638 |
++numAveraged; |
|
639 |
} |
|
640 |
if (numAveraged) |
|
641 |
pos /= numAveraged; |
|
642 |
||
643 |
mouseChanged(transform(pos), button); |
|
644 |
sent = true; |
|
645 |
} |
|
646 |
currSample++; |
|
647 |
if (currSample >= samples.count()) |
|
648 |
currSample = 0; |
|
649 |
||
650 |
return sent; |
|
651 |
} |
|
652 |
||
653 |
QT_END_NAMESPACE |