Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqnxscreeneventhandler.cpp
Go to the documentation of this file.
1// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
6
7#include "qqnxglobal.h"
8
13#include "qqnxscreen.h"
16
17#include "qqnxwindow.h"
18
19#include <QDebug>
20#include <QGuiApplication>
21
22#include <errno.h>
23#include <sys/keycodes.h>
24
25using namespace std::chrono_literals;
26
27Q_LOGGING_CATEGORY(lcQpaScreenEvents, "qt.qpa.screen.events");
28
29static int qtKey(int virtualKey, QChar::Category category)
30{
31 if (Q_UNLIKELY(category == QChar::Other_NotAssigned))
32 return virtualKey;
33 else if (category == QChar::Other_PrivateUse)
34 return qtKeyForPrivateUseQnxKey(virtualKey);
35 else
36 return QChar::toUpper(virtualKey);
37}
38
39static QString keyString(int sym, QChar::Category category)
40{
41 if (Q_UNLIKELY(category == QChar::Other_NotAssigned)) {
42 return QString();
43 } else if (category == QChar::Other_PrivateUse) {
44 return keyStringForPrivateUseQnxKey(sym);
45 } else {
46 return QStringView{QChar::fromUcs4(sym)}.toString();
47 }
48}
49
50static QString capKeyString(int cap, int modifiers, int key)
51{
52 if (cap >= 0x20 && cap <= 0x0ff) {
53 if (modifiers & KEYMOD_CTRL)
54 return QChar((int)(key & 0x3f));
55 }
56 return QString();
57}
58
59template <typename T>
60static void finishCloseEvent(screen_event_t event)
61{
62 T t;
63 screen_get_event_property_pv(event,
64 screen_traits<T>::propertyName,
65 reinterpret_cast<void**>(&t));
66 screen_traits<T>::destroy(t);
67}
68
69static void finishCloseEvent(screen_event_t event)
70{
71 // Let libscreen know that we're finished with anything that may have been acquired.
72 int objectType = SCREEN_OBJECT_TYPE_CONTEXT;
73 screen_get_event_property_iv(event, SCREEN_PROPERTY_OBJECT_TYPE, &objectType);
74 switch (objectType) {
75 case SCREEN_OBJECT_TYPE_CONTEXT:
76 finishCloseEvent<screen_context_t>(event);
77 break;
78 case SCREEN_OBJECT_TYPE_DEVICE:
79 finishCloseEvent<screen_device_t>(event);
80 break;
81 case SCREEN_OBJECT_TYPE_DISPLAY:
82 // no screen_destroy_display
83 break;
84 case SCREEN_OBJECT_TYPE_GROUP:
85 finishCloseEvent<screen_group_t>(event);
86 break;
87 case SCREEN_OBJECT_TYPE_PIXMAP:
88 finishCloseEvent<screen_pixmap_t>(event);
89 break;
90 case SCREEN_OBJECT_TYPE_SESSION:
91 finishCloseEvent<screen_session_t>(event);
92 break;
94 case SCREEN_OBJECT_TYPE_STREAM:
95 finishCloseEvent<screen_stream_t>(event);
96 break;
97#endif
98 case SCREEN_OBJECT_TYPE_WINDOW:
99 finishCloseEvent<screen_window_t>(event);
100 break;
101 }
102}
103
104QT_BEGIN_NAMESPACE
105
106using namespace Qt::StringLiterals;
107
108QQnxScreenEventHandler::QQnxScreenEventHandler(QQnxIntegration *integration)
109 : m_qnxIntegration(integration)
110 , m_lastButtonState(Qt::NoButton)
111 , m_lastMouseWindow(0)
112 , m_mouseDevice(0)
113 , m_eventThread(0)
114{
115 m_mouseDevice = new QPointingDevice("mouse"_L1, 2, QInputDevice::DeviceType::Mouse,
116 QPointingDevice::PointerType::Generic,
117 QPointingDevice::Capability::Position, 1, 8);
118 QWindowSystemInterface::registerInputDevice(m_mouseDevice);
119}
120
122{
123 m_eventFilters.append(filter);
124}
125
127{
128 m_eventFilters.removeOne(filter);
129}
130
131bool QQnxScreenEventHandler::handleEvent(screen_event_t event)
132{
133 // get the event type
134 int qnxType;
135 Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_TYPE, &qnxType),
136 "Failed to query event type");
137
138 return handleEvent(event, qnxType);
139}
140
141bool QQnxScreenEventHandler::handleEvent(screen_event_t event, int qnxType)
142{
143 switch (qnxType) {
144 case SCREEN_EVENT_MTOUCH_TOUCH:
145 case SCREEN_EVENT_MTOUCH_MOVE:
146 case SCREEN_EVENT_MTOUCH_RELEASE:
147 handleTouchEvent(event, qnxType);
148 break;
149
150 case SCREEN_EVENT_KEYBOARD:
151 handleKeyboardEvent(event);
152 break;
153
154 case SCREEN_EVENT_POINTER:
155 handlePointerEvent(event);
156 break;
157
158 case SCREEN_EVENT_CREATE:
159 handleCreateEvent(event);
160 break;
161
162 case SCREEN_EVENT_CLOSE:
163 handleCloseEvent(event);
164 break;
165
166 case SCREEN_EVENT_DISPLAY:
167 handleDisplayEvent(event);
168 break;
169
170 case SCREEN_EVENT_PROPERTY:
171 handlePropertyEvent(event);
172 break;
173
174 case SCREEN_EVENT_MANAGER:
175 handleManagerEvent(event);
176 break;
177
178 default:
179 // event ignored
180 qCDebug(lcQpaScreenEvents) << Q_FUNC_INFO << "Unknown event" << qnxType;
181 return false;
182 }
183
184 return true;
185}
186
187void QQnxScreenEventHandler::injectKeyboardEvent(int flags, int sym, int modifiers, int scan, int cap)
188{
189 Q_UNUSED(scan);
190
191 if (!(flags & KEY_CAP_VALID))
192 return;
193
194 // Correct erroneous information.
195 if ((flags & KEY_SYM_VALID) && sym == static_cast<int>(0xFFFFFFFF))
196 flags &= ~(KEY_SYM_VALID);
197
198 Qt::KeyboardModifiers qtMod = Qt::NoModifier;
199 if (modifiers & KEYMOD_SHIFT)
200 qtMod |= Qt::ShiftModifier;
201 if (modifiers & KEYMOD_CTRL)
202 qtMod |= Qt::ControlModifier;
203 if (modifiers & KEYMOD_ALT)
204 qtMod |= Qt::AltModifier;
205 if (isKeypadKey(cap))
206 qtMod |= Qt::KeypadModifier;
207
208 QEvent::Type type = (flags & KEY_DOWN) ? QEvent::KeyPress : QEvent::KeyRelease;
209
210 int virtualKey = (flags & KEY_SYM_VALID) ? sym : cap;
211 QChar::Category category = QChar::category(virtualKey);
212 int key = qtKey(virtualKey, category);
213 QString keyStr = (flags & KEY_SYM_VALID) ? keyString(sym, category) :
214 capKeyString(cap, modifiers, key);
215
216 QWindowSystemInterface::handleExtendedKeyEvent(QGuiApplication::focusWindow(), type, key, qtMod,
217 scan, virtualKey, modifiers, keyStr, flags & KEY_REPEAT);
218 qCDebug(lcQpaScreenEvents) << "Qt key t=" << type << ", k=" << key << ", s=" << keyStr;
219}
220
221void QQnxScreenEventHandler::setScreenEventThread(QQnxScreenEventThread *eventThread)
222{
223 m_eventThread = eventThread;
224 connect(m_eventThread, &QQnxScreenEventThread::eventsPending,
225 this, &QQnxScreenEventHandler::processEvents);
226 connect(m_eventThread, &QQnxScreenEventThread::postEventReceived,
227 this, &QQnxScreenEventHandler::processPostEvent);
228}
229
230void QQnxScreenEventHandler::processEvents()
231{
232 if (!m_eventThread)
233 return;
234
235 screen_event_t event = nullptr;
236 if (screen_create_event(&event) != 0)
237 return;
238
239 int count = 0;
240 for (;;) {
241 if (screen_get_event(m_eventThread->context(), event, 0) != 0)
242 break;
243
244 int type = SCREEN_EVENT_NONE;
245 screen_get_event_property_iv(event, SCREEN_PROPERTY_TYPE, &type);
246 if (type == SCREEN_EVENT_NONE)
247 break;
248
249 ++count;
250 qintptr result = 0;
251 QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance();
252 bool handled = dispatcher && dispatcher->filterNativeEvent(QByteArrayLiteral("screen_event_t"), event, &result);
253 if (!handled)
254 handleEvent(event);
255
256 if (type == SCREEN_EVENT_CLOSE)
257 finishCloseEvent(event);
258 }
259
260 m_eventThread->armEventsPending(count);
261 screen_destroy_event(event);
262}
263
264void QQnxScreenEventHandler::handleKeyboardEvent(screen_event_t event)
265{
266 // get flags of key event
267 int flags;
268 Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_FLAGS, &flags),
269 "Failed to query event flags");
270
271 // get key code
272 int sym;
273 Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_SYM, &sym),
274 "Failed to query event sym");
275
276 int modifiers;
277 Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_MODIFIERS, &modifiers),
278 "Failed to query event modifieres");
279
280 int scan;
281 Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_SCAN, &scan),
282 "Failed to query event scan");
283
284 int cap;
285 Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_CAP, &cap),
286 "Failed to query event cap");
287
288 int sequenceId = 0;
289 bool inject = true;
290
291 Q_FOREACH (QQnxScreenEventFilter *filter, m_eventFilters) {
292 if (filter->handleKeyboardEvent(flags, sym, modifiers, scan, cap, sequenceId)) {
293 inject = false;
294 break;
295 }
296 }
297
298 if (inject)
299 injectKeyboardEvent(flags, sym, modifiers, scan, cap);
300}
301
302void QQnxScreenEventHandler::handlePointerEvent(screen_event_t event)
303{
304 errno = 0;
305
306 // Query the window that was clicked
307 screen_window_t qnxWindow;
308 void *handle;
309 Q_SCREEN_CHECKERROR(screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle),
310 "Failed to query event window");
311
312 qnxWindow = static_cast<screen_window_t>(handle);
313
314 // Query the button states
315 int buttonState = 0;
316 Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_BUTTONS, &buttonState),
317 "Failed to query event button state");
318
319 // Query the window position
320 int windowPos[2];
322 screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, windowPos),
323 "Failed to query event window position");
324
325 // Query the screen position
326 int pos[2];
327 Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, pos),
328 "Failed to query event position");
329
330 // Query the wheel delta
331 int wheelDelta = 0;
333 screen_get_event_property_iv(event, SCREEN_PROPERTY_MOUSE_WHEEL, &wheelDelta),
334 "Failed to query event wheel delta");
335
336 long long timestamp;
337 Q_SCREEN_CHECKERROR(screen_get_event_property_llv(event, SCREEN_PROPERTY_TIMESTAMP, &timestamp),
338 "Failed to get timestamp");
339
340 // Map window handle to top-level QWindow
341 QWindow *w = QQnxIntegration::instance()->window(qnxWindow);
342
343 // Generate enter and leave events as needed.
344 if (qnxWindow != m_lastMouseWindow) {
345 QWindow *wOld = QQnxIntegration::instance()->window(m_lastMouseWindow);
346
347 if (wOld) {
348 QWindowSystemInterface::handleLeaveEvent(wOld);
349 qCDebug(lcQpaScreenEvents) << "Qt leave, w=" << wOld;
350 }
351
352 if (w) {
353 QWindowSystemInterface::handleEnterEvent(w);
354 qCDebug(lcQpaScreenEvents) << "Qt enter, w=" << w;
355 }
356 }
357
358 m_lastMouseWindow = qnxWindow;
359
360 // Apply scaling to wheel delta and invert value for Qt. We'll probably want to scale
361 // this via a system preference at some point. But for now this is a sane value and makes
362 // the wheel usable.
363 wheelDelta *= -10;
364
365 // convert point to local coordinates
366 QPoint globalPoint(pos[0], pos[1]);
367 QPoint localPoint(windowPos[0], windowPos[1]);
368
369 // Convert buttons.
370 // Some QNX header files invert 'Right Button versus "Left Button' ('Right' == 0x01). But they also offer a 'Button Swap' bit,
371 // so we may receive events as shown. (If this is wrong, the fix is easy.)
372 // QNX Button mask is 8 buttons wide, with a maximum value of x080.
373 Qt::MouseButtons buttons = Qt::NoButton;
374 if (buttonState & 0x01)
375 buttons |= Qt::LeftButton;
376 if (buttonState & 0x02)
377 buttons |= Qt::MiddleButton;
378 if (buttonState & 0x04)
379 buttons |= Qt::RightButton;
380 if (buttonState & 0x08)
381 buttons |= Qt::ExtraButton1; // AKA 'Qt::BackButton'
382 if (buttonState & 0x10)
383 buttons |= Qt::ExtraButton2; // AKA 'Qt::ForwardButton'
384 if (buttonState & 0x20)
385 buttons |= Qt::ExtraButton3;
386 if (buttonState & 0x40)
387 buttons |= Qt::ExtraButton4;
388 if (buttonState & 0x80)
389 buttons |= Qt::ExtraButton5;
390
391 if (w) {
392 // Inject mouse event into Qt only if something has changed.
393 if (m_lastGlobalMousePoint != globalPoint || m_lastLocalMousePoint != localPoint) {
394 QWindowSystemInterface::handleMouseEvent(w, timestamp, m_mouseDevice, localPoint,
395 globalPoint, buttons, Qt::NoButton,
396 QEvent::MouseMove);
397 qCDebug(lcQpaScreenEvents) << "Qt mouse move, w=" << w << ", (" << localPoint.x() << ","
398 << localPoint.y() << "), b=" << static_cast<int>(buttons);
399 }
400
401 if (m_lastButtonState != buttons) {
402 static const auto supportedButtons = { Qt::LeftButton, Qt::MiddleButton,
403 Qt::RightButton, Qt::ExtraButton1,
404 Qt::ExtraButton2, Qt::ExtraButton3,
405 Qt::ExtraButton4, Qt::ExtraButton5 };
406
407 int releasedButtons = (m_lastButtonState ^ buttons) & ~buttons;
408 for (auto button : supportedButtons) {
409 if (releasedButtons & button) {
410 QWindowSystemInterface::handleMouseEvent(w, timestamp, m_mouseDevice,
411 localPoint, globalPoint, buttons,
412 button, QEvent::MouseButtonRelease);
413 qCDebug(lcQpaScreenEvents) << "Qt mouse release, w=" << w << ", (" << localPoint.x()
414 << "," << localPoint.y() << "), b=" << button;
415 }
416 }
417
418 if (m_lastButtonState != 0 && buttons == 0) {
419 (static_cast<QQnxWindow *>(w->handle()))->handleActivationEvent();
420 }
421
422 int pressedButtons = (m_lastButtonState ^ buttons) & buttons;
423 for (auto button : supportedButtons) {
424 if (pressedButtons & button) {
425 QWindowSystemInterface::handleMouseEvent(w, timestamp, m_mouseDevice,
426 localPoint, globalPoint, buttons,
427 button, QEvent::MouseButtonPress);
428 qCDebug(lcQpaScreenEvents) << "Qt mouse press, w=" << w << ", (" << localPoint.x()
429 << "," << localPoint.y() << "), b=" << button;
430 }
431 }
432 }
433
434 if (wheelDelta) {
435 // Screen only supports a single wheel, so we will assume Vertical orientation for
436 // now since that is pretty much standard.
437 QPoint angleDelta(0, wheelDelta);
438 QWindowSystemInterface::handleWheelEvent(w, timestamp, m_mouseDevice, localPoint,
439 globalPoint, QPoint(), angleDelta);
440 qCDebug(lcQpaScreenEvents) << "Qt wheel, w=" << w << ", (" << localPoint.x() << ","
441 << localPoint.y() << "), d=" << static_cast<int>(wheelDelta);
442 }
443 }
444
445 m_lastGlobalMousePoint = globalPoint;
446 m_lastLocalMousePoint = localPoint;
447 m_lastButtonState = buttons;
448}
449
450void QQnxScreenEventHandler::initializeTouchDevices()
451{
452 const auto &screens = QQnxIntegration::instance()->screens();
453 if (screens.isEmpty())
454 return;
455
456 const int screenCount = screens.size();
457 m_touchDevices.resize(screenCount);
458 m_touchPoints.resize(screenCount * MaximumTouchPoints);
459 m_touchPointWindows.resize(screenCount * MaximumTouchPoints);
460 m_touchPointWindows.fill(nullptr);
461
462 for (int i = 0; i < m_touchPoints.size(); i++) {
463 m_touchPoints[i].id = i % MaximumTouchPoints;
464 m_touchPoints[i].pressure = 1.0;
465 m_touchPoints[i].state = QEventPoint::State::Released;
466 }
467
468 for (int i = 0; i < m_touchDevices.size(); i++) {
469 const int displayId = screens[i]->displayId();
470 // Use the hardware display ID offset by 0x10000 to stay well above the
471 // reserved low-id range (mouse=2, keyboard). Fall back to 0x20000 + screenIndex
472 // if the display ID could not be queried.
473 const int systemId = displayId >= 0 ? 0x10000 + displayId : 0x20000 + i;
474 m_touchDevices[i] = new QPointingDevice(
475 "touchscreen-"_L1 + QString::number(displayId >= 0 ? displayId : i), systemId,
476 QInputDevice::DeviceType::TouchScreen,
477 QPointingDevice::PointerType::Finger,
478 QPointingDevice::Capability::Position | QPointingDevice::Capability::Area
479 | QPointingDevice::Capability::Pressure
480 | QPointingDevice::Capability::NormalizedPosition,
481 MaximumTouchPoints, 8, QString(), QPointingDeviceUniqueId(), this);
482 QWindowSystemInterface::registerInputDevice(m_touchDevices[i]);
483 }
484}
485
486void QQnxScreenEventHandler::handleTouchEvent(screen_event_t event, int qnxType)
487{
488 if (m_touchDevices.isEmpty()) {
489 initializeTouchDevices();
490 if (m_touchDevices.isEmpty()) {
491 qCDebug(lcQpaScreenEvents) << "Touch event dropped: no screens available";
492 return;
493 }
494 }
495
496 // get display coordinates of touch
497 int pos[2];
498 Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, pos),
499 "Failed to query event position");
500
501 QCursor::setPos(pos[0], pos[1]);
502
503 // get window coordinates of touch
504 int windowPos[2];
505 Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, windowPos),
506 "Failed to query event window position");
507
508 // determine which finger touched
509 int touchId;
510 Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_TOUCH_ID, &touchId),
511 "Failed to query event touch id");
512
513 // determine which window was touched
514 void *handle;
515 Q_SCREEN_CHECKERROR(screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle),
516 "Failed to query event window");
517
518 errno = 0;
519 int touchArea[2];
520 Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_SIZE, touchArea),
521 "Failed to query event touch area");
522
523 int touchPressure;
525 screen_get_event_property_iv(event, SCREEN_PROPERTY_TOUCH_PRESSURE, &touchPressure),
526 "Failed to query event touch pressure");
527
528 screen_window_t qnxWindow = static_cast<screen_window_t>(handle);
529
530 if (touchId < 0 || touchId >= MaximumTouchPoints) {
531 qCWarning(lcQpaScreenEvents) << "Touch event dropped: touchId" << touchId
532 << "out of range [0," << MaximumTouchPoints << ")";
533 return;
534 }
535
536 // Map window handle to top-level QWindow
537 QWindow *w = QQnxIntegration::instance()->window(qnxWindow);
538
539 // Generate enter and leave events as needed.
540 if (qnxWindow != m_lastMouseWindow) {
541 QWindow *wOld = QQnxIntegration::instance()->window(m_lastMouseWindow);
542
543 if (wOld) {
544 QWindowSystemInterface::handleLeaveEvent(wOld);
545 qCDebug(lcQpaScreenEvents) << "Qt leave, w=" << wOld;
546 }
547
548 if (w) {
549 QWindowSystemInterface::handleEnterEvent(w);
550 qCDebug(lcQpaScreenEvents) << "Qt enter, w=" << w;
551 }
552 }
553 m_lastMouseWindow = qnxWindow;
554
555 // offset touchId by screen index to avoid collision across displays
556 const auto &screens = QQnxIntegration::instance()->screens();
557 QPlatformScreen *platformScreen = w ? QPlatformScreen::platformScreenForWindow(w) : nullptr;
558 const int screenIndex = screens.indexOf(static_cast<QQnxScreen *>(platformScreen));
559 if (screenIndex < 0) {
560 qCDebug(lcQpaScreenEvents) << "Touch event: screen not found, dropping";
561 return;
562 }
563 const int uniqueTouchId = screenIndex * MaximumTouchPoints + touchId;
564 if (uniqueTouchId >= m_touchPoints.size()) {
565 qCWarning(lcQpaScreenEvents) << "Touch event dropped: uniqueTouchId" << uniqueTouchId
566 << "exceeds touch point array size" << m_touchPoints.size();
567 return;
568 }
569
570 if (w && platformScreen) {
571 if (qnxType == SCREEN_EVENT_MTOUCH_RELEASE)
572 (static_cast<QQnxWindow *>(w->handle()))->handleActivationEvent();
573
574 m_touchPointWindows[uniqueTouchId] = qnxWindow;
575
576 // get size of screen which contains window
577 QSizeF screenSize = platformScreen->geometry().size();
578
579 m_touchPoints[uniqueTouchId].id = touchId;
580
581 // update cached position of current touch point
582 m_touchPoints[uniqueTouchId].normalPosition =
583 QPointF(static_cast<qreal>(pos[0]) / screenSize.width(),
584 static_cast<qreal>(pos[1]) / screenSize.height());
585
586 m_touchPoints[uniqueTouchId].area = QRectF(w->geometry().left() + windowPos[0] - (touchArea[0]>>1),
587 w->geometry().top() + windowPos[1] - (touchArea[1]>>1),
588 (touchArea[0]>>1), (touchArea[1]>>1));
589 QWindow *parent = w->parent();
590 while (parent) {
591 m_touchPoints[uniqueTouchId].area.translate(parent->geometry().topLeft());
592 parent = parent->parent();
593 }
594
595 //Qt expects the pressure between 0 and 1. There is however no definite upper limit for
596 //the integer value of touch event pressure. The 200 was determined by experiment, it
597 //usually does not get higher than that.
598 m_touchPoints[uniqueTouchId].pressure = static_cast<qreal>(touchPressure)/200.0;
599 // Can happen, because there is no upper limit for pressure
600 if (m_touchPoints[uniqueTouchId].pressure > 1)
601 m_touchPoints[uniqueTouchId].pressure = 1;
602
603 // determine event type and update state of current touch point
604 QEvent::Type type = QEvent::None;
605 switch (qnxType) {
606 case SCREEN_EVENT_MTOUCH_TOUCH:
607 m_touchPoints[uniqueTouchId].state = QEventPoint::State::Pressed;
608 type = QEvent::TouchBegin;
609 break;
610 case SCREEN_EVENT_MTOUCH_MOVE:
611 m_touchPoints[uniqueTouchId].state = QEventPoint::State::Updated;
612 type = QEvent::TouchUpdate;
613 break;
614 case SCREEN_EVENT_MTOUCH_RELEASE:
615 m_touchPoints[uniqueTouchId].state = QEventPoint::State::Released;
616 type = QEvent::TouchEnd;
617 break;
618 }
619
620 // build list of active touch points
621 QList<QWindowSystemInterface::TouchPoint> pointList;
622 pointList.reserve(MaximumTouchPoints);
623 const int base = screenIndex * MaximumTouchPoints;
624 for (int i = base; i < base + MaximumTouchPoints; i++) {
625 if (i == uniqueTouchId) {
626 pointList.append(m_touchPoints[i]);
627 } else if (m_touchPoints[i].state != QEventPoint::State::Released
628 && m_touchPointWindows[i] == qnxWindow) {
629 m_touchPoints[i].state = QEventPoint::State::Stationary;
630 pointList.append(m_touchPoints[i]);
631 }
632 }
633
634 // inject event into Qt
635 if (Q_UNLIKELY(screenIndex >= m_touchDevices.size())) {
636 qCDebug(lcQpaScreenEvents) << "Touch event: screenIndex out of range, dropping";
637 return;
638 }
639 QPointingDevice *touchDevice = m_touchDevices[screenIndex];
640 QWindowSystemInterface::handleTouchEvent(w, touchDevice, pointList);
641 qCDebug(lcQpaScreenEvents) << "Qt touch, w =" << w
642 << ", p=" << m_touchPoints[uniqueTouchId].area.topLeft()
643 << ", t=" << type;
644 }
645}
646
647void QQnxScreenEventHandler::handleCloseEvent(screen_event_t event)
648{
649 screen_window_t window = 0;
651 screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, (void**)&window),
652 "Failed to query window property");
653
654 for (int i = 0; i < m_touchPointWindows.size(); ++i) {
655 if (m_touchPointWindows[i] == window) {
656 m_touchPointWindows[i] = nullptr;
657 m_touchPoints[i].state = QEventPoint::State::Released;
658 }
659 }
660
661 Q_EMIT windowClosed(window);
662
663 // Map window handle to top-level QWindow
664 QWindow *w = QQnxIntegration::instance()->window(window);
665 if (w != 0)
666 QWindowSystemInterface::handleCloseEvent(w);
667}
668
669void QQnxScreenEventHandler::handleCreateEvent(screen_event_t event)
670{
671 screen_window_t window = 0;
672 int object_type = -1;
673
675 screen_get_event_property_iv(event, SCREEN_PROPERTY_OBJECT_TYPE, &object_type),
676 "Failed to query object type for create event");
677
678 switch (object_type) {
679 // Other object types than window produces an unnessary warning, thus ignore
680 case SCREEN_OBJECT_TYPE_CONTEXT:
681 case SCREEN_OBJECT_TYPE_GROUP:
682 case SCREEN_OBJECT_TYPE_DISPLAY:
683 case SCREEN_OBJECT_TYPE_DEVICE:
684 case SCREEN_OBJECT_TYPE_PIXMAP:
685 case SCREEN_OBJECT_TYPE_SESSION:
686 case SCREEN_OBJECT_TYPE_STREAM:
687 break;
688 case SCREEN_OBJECT_TYPE_WINDOW:
689 {
691 screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, (void**)&window),
692 "Failed to query window property");
693
694 Q_EMIT newWindowCreated(window);
695 break;
696 }
697 default:
698 qCDebug(lcQpaScreenEvents) << "Ignore create event for object type: " << object_type;
699 break;
700 }
701}
702
703void QQnxScreenEventHandler::handleDisplayEvent(screen_event_t event)
704{
705 screen_display_t nativeDisplay = 0;
706 if (screen_get_event_property_pv(event, SCREEN_PROPERTY_DISPLAY, (void **)&nativeDisplay) != 0) {
707 qWarning("QQnx: failed to query display property, errno=%d", errno);
708 return;
709 }
710
711 int isAttached = 0;
712 if (screen_get_event_property_iv(event, SCREEN_PROPERTY_ATTACHED, &isAttached) != 0) {
713 qWarning("QQnx: failed to query display attached property, errno=%d", errno);
714 return;
715 }
716
717 qCDebug(lcQpaScreenEvents) << "display attachment is now:" << isAttached;
718
719 QQnxScreen *screen = m_qnxIntegration->screenForNative(nativeDisplay);
720
721 if (!screen) {
722 if (isAttached) {
723 int val[2];
724 screen_get_display_property_iv(nativeDisplay, SCREEN_PROPERTY_SIZE, val);
725 if (val[0] == 0 && val[1] == 0) //If screen size is invalid, wait for the next event
726 return;
727
728 qCDebug(lcQpaScreenEvents) << "Creating new QQnxScreen for newly attached display";
729 m_qnxIntegration->createDisplay(nativeDisplay, false /* not primary, we assume */);
730 qDeleteAll(m_touchDevices);
731 m_touchDevices.clear();
732 }
733 } else if (!isAttached) {
734 // We never remove the primary display, the qpa plugin doesn't support that and it crashes.
735 // To support it, this would be needed:
736 // - Adjust all qnx qpa code which uses screens
737 // - Make QWidgetRepaintManager not dereference a null paint device
738 // - Create platform resources ( QQnxWindow ) for all QWindow because they would be deleted
739 // when you delete the screen
740
741 if (!screen->isPrimaryScreen()) {
742 // libscreen display is deactivated, let's remove the QQnxScreen / QScreen
743 qCDebug(lcQpaScreenEvents) << "Removing display";
744 m_qnxIntegration->removeDisplay(screen);
745 qDeleteAll(m_touchDevices);
746 m_touchDevices.clear();
747 }
748 }
749}
750
751void QQnxScreenEventHandler::handlePropertyEvent(screen_event_t event)
752{
753 errno = 0;
754 int objectType;
756 screen_get_event_property_iv(event, SCREEN_PROPERTY_OBJECT_TYPE, &objectType),
757 "Failed to query object type property");
758
759 if (objectType != SCREEN_OBJECT_TYPE_WINDOW)
760 return;
761
762 errno = 0;
763 screen_window_t window = 0;
764 if (Q_UNLIKELY(screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, (void**)&window) != 0))
765 qFatal("QQnx: failed to query window property, errno=%d", errno);
766
767 if (window == 0) {
768 qCDebug(lcQpaScreenEvents) << "handlePositionEvent on NULL window";
769 return;
770 }
771
772 errno = 0;
773 int property;
774 if (Q_UNLIKELY(screen_get_event_property_iv(event, SCREEN_PROPERTY_NAME, &property) != 0))
775 qWarning("QQnx: failed to query window property, errno=%d", errno);
776
777 switch (property) {
778 case SCREEN_PROPERTY_FOCUS:
779 handleKeyboardFocusPropertyEvent(window);
780 break;
781 case SCREEN_PROPERTY_SIZE:
782 case SCREEN_PROPERTY_POSITION:
783 handleGeometryPropertyEvent(window);
784 break;
785 default:
786 // event ignored
787 qCDebug(lcQpaScreenEvents) << "Ignore property event for property: " << property;
788 }
789}
790
791void QQnxScreenEventHandler::handleKeyboardFocusPropertyEvent(screen_window_t window)
792{
793 errno = 0;
794 int focus = 0;
795 if (Q_UNLIKELY(window && screen_get_window_property_iv(window, SCREEN_PROPERTY_FOCUS, &focus) != 0))
796 qWarning("QQnx: failed to query keyboard focus property, errno=%d", errno);
797
798 QWindow *focusWindow = QQnxIntegration::instance()->window(window);
799
800 m_focusLostTimer.stop();
801
802 if (focus && focusWindow != QGuiApplication::focusWindow())
803 QWindowSystemInterface::handleFocusWindowChanged(focusWindow, Qt::ActiveWindowFocusReason);
804 else if (!focus && focusWindow == QGuiApplication::focusWindow())
805 m_focusLostTimer.start(50ms, this);
806}
807
808void QQnxScreenEventHandler::handleGeometryPropertyEvent(screen_window_t window)
809{
810 int pos[2];
811 if (screen_get_window_property_iv(window, SCREEN_PROPERTY_POSITION, pos) != 0) {
812 qWarning("QQnx: failed to query window property, errno=%d", errno);
813 return;
814 }
815
816 int size[2];
817 if (screen_get_window_property_iv(window, SCREEN_PROPERTY_SIZE, size) != 0) {
818 qWarning("QQnx: failed to query window property, errno=%d", errno);
819 return;
820 }
821
822 QRect rect(pos[0], pos[1], size[0], size[1]);
823 QWindow *qtWindow = QQnxIntegration::instance()->window(window);
824 if (qtWindow) {
825 // Only update if the geometry actually changed to avoid duplicate events.
826 // QQnxWindow::setGeometry() already calls handleGeometryChange() internally,
827 // so we must not call it again here.
828 if (qtWindow->handle() && qtWindow->handle()->geometry() != rect)
829 qtWindow->handle()->setGeometry(rect);
830 }
831
832 qCDebug(lcQpaScreenEvents) << qtWindow << "moved to" << rect;
833}
834
835void QQnxScreenEventHandler::timerEvent(QTimerEvent *event)
836{
837 if (event->id() == m_focusLostTimer.id()) {
838 m_focusLostTimer.stop();
839 event->accept();
840 } else {
841 QObject::timerEvent(event);
842 }
843}
844
845QT_END_NAMESPACE
846
847void QQnxScreenEventHandler::handleManagerEvent(screen_event_t event)
848{
849 errno = 0;
850 int subtype;
852 screen_get_event_property_iv(event, SCREEN_PROPERTY_SUBTYPE, &subtype),
853 "Failed to query object type property");
854
855 errno = 0;
856 screen_window_t window = 0;
857 if (screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, (void**)&window) != 0)
858 qFatal("QQnx: failed to query window property, errno=%d", errno);
859
860 switch (subtype) {
861 case SCREEN_EVENT_CLOSE: {
862 QWindow *closeWindow = QQnxIntegration::instance()->window(window);
863 closeWindow->close();
864 break;
865 }
866
867 default:
868 // event ignored
869 qCDebug(lcQpaScreenEvents) << "Ignore manager event for subtype: " << subtype;
870 }
871}
872
873void QQnxScreenEventHandler::processPostEvent(screen_window_t qnxWindow)
874{
875 QWindow *w = QQnxIntegration::instance()->window(qnxWindow);
876 if (!w)
877 return;
878 if (QQnxWindow *platformWindow = static_cast<QQnxWindow *>(w->handle()))
879 platformWindow->handlePostEvent();
880}
881
882#include "moc_qqnxscreeneventhandler.cpp"
static QQnxIntegration * instance()
void removeDisplay(QQnxScreen *screen)
void removeScreenEventFilter(QQnxScreenEventFilter *filter)
void setScreenEventThread(QQnxScreenEventThread *eventThread)
void timerEvent(QTimerEvent *event) override
This event handler can be reimplemented in a subclass to receive timer events for the object.
bool handleEvent(screen_event_t event)
static void injectKeyboardEvent(int flags, int sym, int mod, int scan, int cap)
void addScreenEventFilter(QQnxScreenEventFilter *filter)
bool handleEvent(screen_event_t event, int qnxType)
bool isPrimaryScreen() const
Definition qqnxscreen.h:60
The QQnxWindow is the base class of the various classes used as instances of QPlatformWindow in the Q...
Definition qqnxwindow.h:32
void handlePostEvent()
void handleActivationEvent()
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
#define Q_SCREEN_CHECKERROR(x, message)
Definition qqnxglobal.h:17
QT_BEGIN_NAMESPACE int qtKeyForPrivateUseQnxKey(int key)
const int SCREEN_PROPERTY_SYM
Definition qqnxscreen.h:29
#define _SCREEN_VERSION
Definition qqnxscreen.h:19
const int SCREEN_PROPERTY_SCAN
Definition qqnxscreen.h:28
const int SCREEN_PROPERTY_FOCUS
Definition qqnxscreen.h:26
const int SCREEN_PROPERTY_MODIFIERS
Definition qqnxscreen.h:27
#define _SCREEN_MAKE_VERSION(major, minor, patch)
Definition qqnxscreen.h:18
static int qtKey(int virtualKey, QChar::Category category)
static QString keyString(int sym, QChar::Category category)
static void finishCloseEvent(screen_event_t event)
static QString capKeyString(int cap, int modifiers, int key)
static void finishCloseEvent(screen_event_t event)