1 /***************************************************************************
3 ** Copyright (C) 2011 - 2012 Research In Motion
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the plugins of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include "qqnxscreeneventhandler.h"
43 #include "qqnxintegration.h"
44 #include "qqnxkeytranslator.h"
47 #include <QGuiApplication>
50 #include <sys/keycodes.h>
52 #ifdef QQNXSCREENEVENT_DEBUG
53 #define qScreenEventDebug qDebug
55 #define qScreenEventDebug QT_NO_QDEBUG_MACRO
60 QQnxScreenEventHandler::QQnxScreenEventHandler()
61 : m_lastButtonState(Qt::NoButton)
62 , m_lastMouseWindow(0)
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);
71 // initialize array of touch points
72 for (int i = 0; i < MaximumTouchPoints; i++) {
74 // map array index to id
75 m_touchPoints[i].id = i;
77 // pressure is not supported - use default
78 m_touchPoints[i].pressure = 1.0;
81 m_touchPoints[i].state = Qt::TouchPointReleased;
85 bool QQnxScreenEventHandler::handleEvent(screen_event_t event)
90 int result = screen_get_event_property_iv(event, SCREEN_PROPERTY_TYPE, &qnxType);
92 qFatal("QQNX: failed to query event type, errno=%d", errno);
95 return handleEvent(event, qnxType);
98 bool QQnxScreenEventHandler::handleEvent(screen_event_t event, int qnxType)
101 case SCREEN_EVENT_MTOUCH_TOUCH:
102 case SCREEN_EVENT_MTOUCH_MOVE:
103 case SCREEN_EVENT_MTOUCH_RELEASE:
104 handleTouchEvent(event, qnxType);
107 case SCREEN_EVENT_KEYBOARD:
108 handleKeyboardEvent(event);
111 case SCREEN_EVENT_POINTER:
112 handlePointerEvent(event);
115 case SCREEN_EVENT_CREATE:
116 handleCreateEvent(event);
119 case SCREEN_EVENT_CLOSE:
120 handleCloseEvent(event);
125 qScreenEventDebug() << Q_FUNC_INFO << "unknown event";
132 void QQnxScreenEventHandler::injectKeyboardEvent(int flags, int sym, int modifiers, int scan, int cap)
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;
144 // determine event type
145 QEvent::Type type = (flags & KEY_DOWN) ? QEvent::KeyPress : QEvent::KeyRelease;
147 // Check if the key cap is valid
148 if (flags & KEY_CAP_VALID) {
152 if (cap >= 0x20 && cap <= 0x0ff) {
153 key = Qt::Key(std::toupper(cap)); // Qt expects the CAP to be upper case.
155 if ( qtMod & Qt::ControlModifier ) {
156 keyStr = QChar((int)(key & 0x3f));
158 if (flags & KEY_SYM_VALID) {
162 } else if ((cap > 0x0ff && cap < UNICODE_PRIVATE_USE_AREA_FIRST) || cap > UNICODE_PRIVATE_USE_AREA_LAST) {
166 if (isKeypadKey(cap))
167 qtMod |= Qt::KeypadModifier; // Is this right?
168 key = keyTranslator(cap);
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;
177 void QQnxScreenEventHandler::handleKeyboardEvent(screen_event_t event)
179 // get flags of key event
182 int result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_FLAGS, &flags);
184 qFatal("QQNX: failed to query event flags, errno=%d", errno);
190 result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_SYM, &sym);
192 qFatal("QQNX: failed to query event sym, errno=%d", errno);
196 result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_MODIFIERS, &modifiers);
198 qFatal("QQNX: failed to query event modifiers, errno=%d", errno);
202 result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_SCAN, &scan);
204 qFatal("QQNX: failed to query event modifiers, errno=%d", errno);
208 result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_CAP, &cap);
210 qFatal("QQNX: failed to query event cap, errno=%d", errno);
213 injectKeyboardEvent(flags, sym, modifiers, scan, cap);
216 void QQnxScreenEventHandler::handlePointerEvent(screen_event_t event)
220 // Query the window that was clicked
221 screen_window_t qnxWindow;
223 int result = screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle);
225 qFatal("QQNX: failed to query event window, errno=%d", errno);
227 qnxWindow = static_cast<screen_window_t>(handle);
229 // Query the button states
231 result = screen_get_event_property_iv(event, SCREEN_PROPERTY_BUTTONS, &buttonState);
233 qFatal("QQNX: failed to query event button state, errno=%d", errno);
236 // Query the window position
238 result = screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, windowPos);
240 qFatal("QQNX: failed to query event window position, errno=%d", errno);
243 // Query the screen position
245 result = screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, pos);
247 qFatal("QQNX: failed to query event position, errno=%d", errno);
250 // Query the wheel delta
252 result = screen_get_event_property_iv(event, SCREEN_PROPERTY_MOUSE_WHEEL, &wheelDelta);
254 qFatal("QQNX: failed to query event wheel delta, errno=%d", errno);
257 // Map window handle to top-level QWindow
258 QWindow *w = QQnxIntegration::window(qnxWindow);
260 // Generate enter and leave events as needed.
261 if (qnxWindow != m_lastMouseWindow) {
262 QWindow *wOld = QQnxIntegration::window(m_lastMouseWindow);
265 QWindowSystemInterface::handleLeaveEvent(wOld);
266 qScreenEventDebug() << Q_FUNC_INFO << "Qt leave, w=" << wOld;
270 QWindowSystemInterface::handleEnterEvent(w);
271 qScreenEventDebug() << Q_FUNC_INFO << "Qt enter, w=" << w;
274 m_lastMouseWindow = qnxWindow;
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
281 // convert point to local coordinates
282 QPoint globalPoint(pos[0], pos[1]);
283 QPoint localPoint(windowPos[0], windowPos[1]);
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;
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);
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);
324 m_lastGlobalMousePoint = globalPoint;
325 m_lastLocalMousePoint = localPoint;
326 m_lastButtonState = buttons;
329 void QQnxScreenEventHandler::handleTouchEvent(screen_event_t event, int qnxType)
331 // get display coordinates of touch
334 int result = screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, pos);
336 qFatal("QQNX: failed to query event position, errno=%d", errno);
339 // get window coordinates of touch
342 result = screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, windowPos);
344 qFatal("QQNX: failed to query event window position, errno=%d", errno);
347 // determine which finger touched
350 result = screen_get_event_property_iv(event, SCREEN_PROPERTY_TOUCH_ID, &touchId);
352 qFatal("QQNX: failed to query event touch id, errno=%d", errno);
355 // determine which window was touched
358 result = screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle);
360 qFatal("QQNX: failed to query event window, errno=%d", errno);
362 screen_window_t qnxWindow = static_cast<screen_window_t>(handle);
364 // check if finger is valid
365 if (touchId < MaximumTouchPoints) {
367 // Map window handle to top-level QWindow
368 QWindow *w = QQnxIntegration::window(qnxWindow);
370 // Generate enter and leave events as needed.
371 if (qnxWindow != m_lastMouseWindow) {
372 QWindow *wOld = QQnxIntegration::window(m_lastMouseWindow);
375 QWindowSystemInterface::handleLeaveEvent(wOld);
376 qScreenEventDebug() << Q_FUNC_INFO << "Qt leave, w=" << wOld;
380 QWindowSystemInterface::handleEnterEvent(w);
381 qScreenEventDebug() << Q_FUNC_INFO << "Qt enter, w=" << w;
384 m_lastMouseWindow = qnxWindow;
387 // get size of screen which contains window
388 QPlatformScreen *platformScreen = QPlatformScreen::platformScreenForWindow(w);
389 QSizeF screenSize = platformScreen->physicalSize();
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 );
395 // determine event type and update state of current touch point
396 QEvent::Type type = QEvent::None;
398 case SCREEN_EVENT_MTOUCH_TOUCH:
399 m_touchPoints[touchId].state = Qt::TouchPointPressed;
400 type = QEvent::TouchBegin;
402 case SCREEN_EVENT_MTOUCH_MOVE:
403 m_touchPoints[touchId].state = Qt::TouchPointMoved;
404 type = QEvent::TouchUpdate;
406 case SCREEN_EVENT_MTOUCH_RELEASE:
407 m_touchPoints[touchId].state = Qt::TouchPointReleased;
408 type = QEvent::TouchEnd;
412 // build list of active touch points
413 QList<QWindowSystemInterface::TouchPoint> pointList;
414 for (int i = 0; i < MaximumTouchPoints; i++) {
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]);
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]
431 // convert primary touch to mouse event
434 // convert point to local coordinates
435 QPoint globalPoint(pos[0], pos[1]);
436 QPoint localPoint(windowPos[0], windowPos[1]);
438 // map touch state to button state
439 Qt::MouseButtons buttons = (qnxType == SCREEN_EVENT_MTOUCH_RELEASE) ? Qt::NoButton : Qt::LeftButton;
441 // inject event into Qt
442 QWindowSystemInterface::handleMouseEvent(w, localPoint, globalPoint, buttons);
443 qScreenEventDebug() << Q_FUNC_INFO << "Qt mouse, w =" << w
444 << ", (" << localPoint.x() << "," << localPoint.y()
445 << "), b =" << buttons;
451 void QQnxScreenEventHandler::handleCloseEvent(screen_event_t event)
453 screen_window_t window = 0;
454 if (screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, (void**)&window) != 0)
455 qFatal("QQnx: failed to query window property, errno=%d", errno);
457 Q_EMIT windowClosed(window);
459 // Map window handle to top-level QWindow
460 QWindow *w = QQnxIntegration::window(window);
462 QWindowSystemInterface::handleCloseEvent(w);
466 void QQnxScreenEventHandler::handleCreateEvent(screen_event_t event)
468 screen_window_t window = 0;
469 if (screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, (void**)&window) != 0)
470 qFatal("QQnx: failed to query window property, errno=%d", errno);
472 Q_EMIT newWindowCreated(window);
475 #include "moc_qqnxscreeneventhandler.cpp"