QNX: Remove mouse events synthetized from touch events
[profile/ivi/qtbase.git] / src / plugins / platforms / qnx / qqnxscreeneventhandler.cpp
1 /***************************************************************************
2 **
3 ** Copyright (C) 2011 - 2012 Research In Motion
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qqnxscreeneventhandler.h"
43 #include "qqnxintegration.h"
44 #include "qqnxkeytranslator.h"
45
46 #include <QDebug>
47 #include <QGuiApplication>
48
49 #include <errno.h>
50 #include <sys/keycodes.h>
51
52 #ifdef QQNXSCREENEVENT_DEBUG
53 #define qScreenEventDebug qDebug
54 #else
55 #define qScreenEventDebug QT_NO_QDEBUG_MACRO
56 #endif
57
58 QT_BEGIN_NAMESPACE
59
60 QQnxScreenEventHandler::QQnxScreenEventHandler()
61     : m_lastButtonState(Qt::NoButton)
62     , m_lastMouseWindow(0)
63     , m_touchDevice(0)
64 {
65     // Create a touch device
66     m_touchDevice = new QTouchDevice;
67     m_touchDevice->setType(QTouchDevice::TouchScreen);
68     m_touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | QTouchDevice::NormalizedPosition);
69     QWindowSystemInterface::registerTouchDevice(m_touchDevice);
70
71     // initialize array of touch points
72     for (int i = 0; i < MaximumTouchPoints; i++) {
73
74         // map array index to id
75         m_touchPoints[i].id = i;
76
77         // pressure is not supported - use default
78         m_touchPoints[i].pressure = 1.0;
79
80         // nothing touching
81         m_touchPoints[i].state = Qt::TouchPointReleased;
82     }
83 }
84
85 bool QQnxScreenEventHandler::handleEvent(screen_event_t event)
86 {
87     // get the event type
88     errno = 0;
89     int qnxType;
90     int result = screen_get_event_property_iv(event, SCREEN_PROPERTY_TYPE, &qnxType);
91     if (result) {
92         qFatal("QQNX: failed to query event type, errno=%d", errno);
93     }
94
95     return handleEvent(event, qnxType);
96 }
97
98 bool QQnxScreenEventHandler::handleEvent(screen_event_t event, int qnxType)
99 {
100     switch (qnxType) {
101     case SCREEN_EVENT_MTOUCH_TOUCH:
102     case SCREEN_EVENT_MTOUCH_MOVE:
103     case SCREEN_EVENT_MTOUCH_RELEASE:
104         handleTouchEvent(event, qnxType);
105         break;
106
107     case SCREEN_EVENT_KEYBOARD:
108         handleKeyboardEvent(event);
109         break;
110
111     case SCREEN_EVENT_POINTER:
112         handlePointerEvent(event);
113         break;
114
115     case SCREEN_EVENT_CREATE:
116         handleCreateEvent(event);
117         break;
118
119     case SCREEN_EVENT_CLOSE:
120         handleCloseEvent(event);
121         break;
122
123     default:
124         // event ignored
125         qScreenEventDebug() << Q_FUNC_INFO << "unknown event";
126         return false;
127     }
128
129     return true;
130 }
131
132 void QQnxScreenEventHandler::injectKeyboardEvent(int flags, int sym, int modifiers, int scan, int cap)
133 {
134     Q_UNUSED(scan);
135
136     Qt::KeyboardModifiers qtMod = Qt::NoModifier;
137     if (modifiers & KEYMOD_SHIFT)
138         qtMod |= Qt::ShiftModifier;
139     if (modifiers & KEYMOD_CTRL)
140         qtMod |= Qt::ControlModifier;
141     if (modifiers & KEYMOD_ALT)
142         qtMod |= Qt::AltModifier;
143
144     // determine event type
145     QEvent::Type type = (flags & KEY_DOWN) ? QEvent::KeyPress : QEvent::KeyRelease;
146
147     // Check if the key cap is valid
148     if (flags & KEY_CAP_VALID) {
149         Qt::Key key;
150         QString keyStr;
151
152         if (cap >= 0x20 && cap <= 0x0ff) {
153             key = Qt::Key(std::toupper(cap));   // Qt expects the CAP to be upper case.
154
155             if ( qtMod & Qt::ControlModifier ) {
156                 keyStr = QChar((int)(key & 0x3f));
157             } else {
158                 if (flags & KEY_SYM_VALID) {
159                     keyStr = QChar(sym);
160                 }
161             }
162         } else if ((cap > 0x0ff && cap < UNICODE_PRIVATE_USE_AREA_FIRST) || cap > UNICODE_PRIVATE_USE_AREA_LAST) {
163             key = (Qt::Key)cap;
164             keyStr = QChar(sym);
165         } else {
166             if (isKeypadKey(cap))
167                 qtMod |= Qt::KeypadModifier; // Is this right?
168             key = keyTranslator(cap);
169         }
170
171         QWindowSystemInterface::handleExtendedKeyEvent(QGuiApplication::focusWindow(), type, key, qtMod,
172                 scan, sym, modifiers, keyStr);
173         qScreenEventDebug() << Q_FUNC_INFO << "Qt key t=" << type << ", k=" << key << ", s=" << keyStr;
174     }
175 }
176
177 void QQnxScreenEventHandler::handleKeyboardEvent(screen_event_t event)
178 {
179     // get flags of key event
180     errno = 0;
181     int flags;
182     int result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_FLAGS, &flags);
183     if (result) {
184         qFatal("QQNX: failed to query event flags, errno=%d", errno);
185     }
186
187     // get key code
188     errno = 0;
189     int sym;
190     result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_SYM, &sym);
191     if (result) {
192         qFatal("QQNX: failed to query event sym, errno=%d", errno);
193     }
194
195     int modifiers;
196     result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_MODIFIERS, &modifiers);
197     if (result) {
198         qFatal("QQNX: failed to query event modifiers, errno=%d", errno);
199     }
200
201     int scan;
202     result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_SCAN, &scan);
203     if (result) {
204         qFatal("QQNX: failed to query event modifiers, errno=%d", errno);
205     }
206
207     int cap;
208     result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_CAP, &cap);
209     if (result) {
210         qFatal("QQNX: failed to query event cap, errno=%d", errno);
211     }
212
213     injectKeyboardEvent(flags, sym, modifiers, scan, cap);
214 }
215
216 void QQnxScreenEventHandler::handlePointerEvent(screen_event_t event)
217 {
218     errno = 0;
219
220     // Query the window that was clicked
221     screen_window_t qnxWindow;
222     void *handle;
223     int result = screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle);
224     if (result) {
225         qFatal("QQNX: failed to query event window, errno=%d", errno);
226     }
227     qnxWindow = static_cast<screen_window_t>(handle);
228
229     // Query the button states
230     int buttonState = 0;
231     result = screen_get_event_property_iv(event, SCREEN_PROPERTY_BUTTONS, &buttonState);
232     if (result) {
233         qFatal("QQNX: failed to query event button state, errno=%d", errno);
234     }
235
236     // Query the window position
237     int windowPos[2];
238     result = screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, windowPos);
239     if (result) {
240         qFatal("QQNX: failed to query event window position, errno=%d", errno);
241     }
242
243     // Query the screen position
244     int pos[2];
245     result = screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, pos);
246     if (result) {
247         qFatal("QQNX: failed to query event position, errno=%d", errno);
248     }
249
250     // Query the wheel delta
251     int wheelDelta = 0;
252     result = screen_get_event_property_iv(event, SCREEN_PROPERTY_MOUSE_WHEEL, &wheelDelta);
253     if (result) {
254         qFatal("QQNX: failed to query event wheel delta, errno=%d", errno);
255     }
256
257     // Map window handle to top-level QWindow
258     QWindow *w = QQnxIntegration::window(qnxWindow);
259
260     // Generate enter and leave events as needed.
261     if (qnxWindow != m_lastMouseWindow) {
262         QWindow *wOld = QQnxIntegration::window(m_lastMouseWindow);
263
264         if (wOld) {
265             QWindowSystemInterface::handleLeaveEvent(wOld);
266             qScreenEventDebug() << Q_FUNC_INFO << "Qt leave, w=" << wOld;
267         }
268
269         if (w) {
270             QWindowSystemInterface::handleEnterEvent(w);
271             qScreenEventDebug() << Q_FUNC_INFO << "Qt enter, w=" << w;
272         }
273     }
274     m_lastMouseWindow = qnxWindow;
275
276     // Apply scaling to wheel delta and invert value for Qt. We'll probably want to scale
277     // this via a system preference at some point. But for now this is a sane value and makes
278     // the wheel usable.
279     wheelDelta *= -10;
280
281     // convert point to local coordinates
282     QPoint globalPoint(pos[0], pos[1]);
283     QPoint localPoint(windowPos[0], windowPos[1]);
284
285     // Convert buttons.
286     // Some QNX header files invert 'Right Button versus "Left Button' ('Right' == 0x01). But they also offer a 'Button Swap' bit,
287     // so we may receive events as shown. (If this is wrong, the fix is easy.)
288     // QNX Button mask is 8 buttons wide, with a maximum value of x080.
289     Qt::MouseButtons buttons = Qt::NoButton;
290     if (buttonState & 0x01)
291         buttons |= Qt::LeftButton;
292     if (buttonState & 0x02)
293         buttons |= Qt::MidButton;
294     if (buttonState & 0x04)
295         buttons |= Qt::RightButton;
296     if (buttonState & 0x08)
297         buttons |= Qt::ExtraButton1;    // AKA 'Qt::BackButton'
298     if (buttonState & 0x10)
299         buttons |= Qt::ExtraButton2;    // AKA 'Qt::ForwardButton'
300     if (buttonState & 0x20)
301         buttons |= Qt::ExtraButton3;
302     if (buttonState & 0x40)
303         buttons |= Qt::ExtraButton4;
304     if (buttonState & 0x80)
305         buttons |= Qt::ExtraButton5;
306
307     if (w) {
308         // Inject mouse event into Qt only if something has changed.
309         if (m_lastGlobalMousePoint != globalPoint ||
310             m_lastLocalMousePoint != localPoint ||
311             m_lastButtonState != buttons) {
312             QWindowSystemInterface::handleMouseEvent(w, localPoint, globalPoint, buttons);
313             qScreenEventDebug() << Q_FUNC_INFO << "Qt mouse, w=" << w << ", (" << localPoint.x() << "," << localPoint.y() << "), b=" << static_cast<int>(buttons);
314         }
315
316         if (wheelDelta) {
317             // Screen only supports a single wheel, so we will assume Vertical orientation for
318             // now since that is pretty much standard.
319             QWindowSystemInterface::handleWheelEvent(w, localPoint, globalPoint, wheelDelta, Qt::Vertical);
320             qScreenEventDebug() << Q_FUNC_INFO << "Qt wheel, w=" << w << ", (" << localPoint.x() << "," << localPoint.y() << "), d=" << static_cast<int>(wheelDelta);
321         }
322     }
323
324     m_lastGlobalMousePoint = globalPoint;
325     m_lastLocalMousePoint = localPoint;
326     m_lastButtonState = buttons;
327 }
328
329 void QQnxScreenEventHandler::handleTouchEvent(screen_event_t event, int qnxType)
330 {
331     // get display coordinates of touch
332     errno = 0;
333     int pos[2];
334     int result = screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, pos);
335     if (result) {
336         qFatal("QQNX: failed to query event position, errno=%d", errno);
337     }
338
339     // get window coordinates of touch
340     errno = 0;
341     int windowPos[2];
342     result = screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, windowPos);
343     if (result) {
344         qFatal("QQNX: failed to query event window position, errno=%d", errno);
345     }
346
347     // determine which finger touched
348     errno = 0;
349     int touchId;
350     result = screen_get_event_property_iv(event, SCREEN_PROPERTY_TOUCH_ID, &touchId);
351     if (result) {
352         qFatal("QQNX: failed to query event touch id, errno=%d", errno);
353     }
354
355     // determine which window was touched
356     errno = 0;
357     void *handle;
358     result = screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle);
359     if (result) {
360         qFatal("QQNX: failed to query event window, errno=%d", errno);
361     }
362     screen_window_t qnxWindow = static_cast<screen_window_t>(handle);
363
364     // check if finger is valid
365     if (touchId < MaximumTouchPoints) {
366
367         // Map window handle to top-level QWindow
368         QWindow *w = QQnxIntegration::window(qnxWindow);
369
370         // Generate enter and leave events as needed.
371         if (qnxWindow != m_lastMouseWindow) {
372             QWindow *wOld = QQnxIntegration::window(m_lastMouseWindow);
373
374             if (wOld) {
375                 QWindowSystemInterface::handleLeaveEvent(wOld);
376                 qScreenEventDebug() << Q_FUNC_INFO << "Qt leave, w=" << wOld;
377             }
378
379             if (w) {
380                 QWindowSystemInterface::handleEnterEvent(w);
381                 qScreenEventDebug() << Q_FUNC_INFO << "Qt enter, w=" << w;
382             }
383         }
384         m_lastMouseWindow = qnxWindow;
385
386         if (w) {
387             // get size of screen which contains window
388             QPlatformScreen *platformScreen = QPlatformScreen::platformScreenForWindow(w);
389             QSizeF screenSize = platformScreen->physicalSize();
390
391             // update cached position of current touch point
392             m_touchPoints[touchId].normalPosition = QPointF( static_cast<qreal>(pos[0]) / screenSize.width(), static_cast<qreal>(pos[1]) / screenSize.height() );
393             m_touchPoints[touchId].area = QRectF( pos[0], pos[1], 0.0, 0.0 );
394
395             // determine event type and update state of current touch point
396             QEvent::Type type = QEvent::None;
397             switch (qnxType) {
398             case SCREEN_EVENT_MTOUCH_TOUCH:
399                 m_touchPoints[touchId].state = Qt::TouchPointPressed;
400                 type = QEvent::TouchBegin;
401                 break;
402             case SCREEN_EVENT_MTOUCH_MOVE:
403                 m_touchPoints[touchId].state = Qt::TouchPointMoved;
404                 type = QEvent::TouchUpdate;
405                 break;
406             case SCREEN_EVENT_MTOUCH_RELEASE:
407                 m_touchPoints[touchId].state = Qt::TouchPointReleased;
408                 type = QEvent::TouchEnd;
409                 break;
410             }
411
412             // build list of active touch points
413             QList<QWindowSystemInterface::TouchPoint> pointList;
414             for (int i = 0; i < MaximumTouchPoints; i++) {
415                 if (i == touchId) {
416                     // current touch point is always active
417                     pointList.append(m_touchPoints[i]);
418                 } else if (m_touchPoints[i].state != Qt::TouchPointReleased) {
419                     // finger is down but did not move
420                     m_touchPoints[i].state = Qt::TouchPointStationary;
421                     pointList.append(m_touchPoints[i]);
422                 }
423             }
424
425             // inject event into Qt
426             QWindowSystemInterface::handleTouchEvent(w, m_touchDevice, pointList);
427             qScreenEventDebug() << Q_FUNC_INFO << "Qt touch, w =" << w
428                                 << ", p=(" << pos[0] << "," << pos[1]
429                                 << "), t=" << type;
430         }
431     }
432 }
433
434 void QQnxScreenEventHandler::handleCloseEvent(screen_event_t event)
435 {
436     screen_window_t window = 0;
437     if (screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, (void**)&window) != 0)
438         qFatal("QQnx: failed to query window property, errno=%d", errno);
439
440     Q_EMIT windowClosed(window);
441
442     // Map window handle to top-level QWindow
443     QWindow *w = QQnxIntegration::window(window);
444     if (w != 0) {
445         QWindowSystemInterface::handleCloseEvent(w);
446     }
447 }
448
449 void QQnxScreenEventHandler::handleCreateEvent(screen_event_t event)
450 {
451     screen_window_t window = 0;
452     if (screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, (void**)&window) != 0)
453         qFatal("QQnx: failed to query window property, errno=%d", errno);
454
455     Q_EMIT newWindowCreated(window);
456 }
457
458 #include "moc_qqnxscreeneventhandler.cpp"
459
460 QT_END_NAMESPACE