diff options
| author | Jesus Fernandez <jesus.fernandez@qt.io> | 2017-06-07 11:13:52 +0200 |
|---|---|---|
| committer | Jesus Fernandez <Jesus.Fernandez@qt.io> | 2017-06-27 18:00:22 +0000 |
| commit | 91bc2d2f217507f20933b7caf65dc33701d2e9cd (patch) | |
| tree | fa214c2537fbbb18109f0309fc1f3c278c0154ba /src/plugins/platforms/webgl/qwebglintegration.cpp | |
| parent | 440a7710219674ed9e0e4d1396853fb1f7d35107 (diff) | |
Add Qt WebGL platform plugin
Done-with: Michael Winkelmann <michael.winkelmann@qt.io>
Change-Id: I6632475956393116af8885f42ba557e35d2b0985
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
Diffstat (limited to 'src/plugins/platforms/webgl/qwebglintegration.cpp')
| -rw-r--r-- | src/plugins/platforms/webgl/qwebglintegration.cpp | 645 |
1 files changed, 645 insertions, 0 deletions
diff --git a/src/plugins/platforms/webgl/qwebglintegration.cpp b/src/plugins/platforms/webgl/qwebglintegration.cpp new file mode 100644 index 0000000..85ec2f1 --- /dev/null +++ b/src/plugins/platforms/webgl/qwebglintegration.cpp @@ -0,0 +1,645 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt WebGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwebglintegration.h" +#include "qwebglintegration_p.h" + +#include "qwebglwindow.h" +#include "qwebglcontext.h" +#include "qwebglcontext.h" +#include "qwebglhttpserver.h" +#include "qwebglwebsocketserver.h" +#include "qwebglplatformservices.h" + +#include <QtCore/qjsonarray.h> +#include <QtCore/qjsondocument.h> +#include <QtCore/qjsonobject.h> +#include <QtCore/qloggingcategory.h> +#include <QtCore/qtextstream.h> +#include <QtCore/qtimer.h> +#include <QtCore/qstring.h> +#include <QtGui/qclipboard.h> +#include <QtGui/qscreen.h> +#include <QtGui/qwindow.h> +#include <QtGui/qsurfaceformat.h> +#include <QtGui/qopenglcontext.h> +#include <QtGui/qoffscreensurface.h> +#include <QtGui/qpa/qplatformwindow.h> +#include <QtGui/private/qguiapplication_p.h> +#include <QtGui/qpa/qwindowsysteminterface.h> +#include <QtPlatformCompositorSupport/private/qopenglcompositorbackingstore_p.h> +#include <QtThemeSupport/private/qgenericunixthemes_p.h> +#include <QtWebSockets/qwebsocket.h> + +#if defined(QT_QUICK_LIB) +#include <QtQuick/qquickwindow.h> +#endif + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(lcWebGL, "qt.qpa.webgl") + +QWebGLIntegrationPrivate *QWebGLIntegrationPrivate::instance() +{ + auto platformIntegration = QGuiApplicationPrivate::instance()->platformIntegration(); + return static_cast<QWebGLIntegration *>(platformIntegration)->d_ptr.data(); +} + +QWebGLIntegration::QWebGLIntegration(quint16 port) : + d_ptr(new QWebGLIntegrationPrivate) +{ + Q_D(QWebGLIntegration); + d->q_ptr = this; + d->httpPort = port; + d->touchDevice = new QTouchDevice; + d->touchDevice->setName("EmulatedTouchDevice"); + d->touchDevice->setType(QTouchDevice::TouchScreen); + d->touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Pressure | + QTouchDevice::MouseEmulation); + d->touchDevice->setMaximumTouchPoints(6); + QWindowSystemInterface::registerTouchDevice(d->touchDevice); + + qCDebug(lcWebGL, "WebGL QPA Plugin created"); + qRegisterMetaType<QWebSocket *>("QWebSocket *"); + qRegisterMetaType<QWebGLWebSocketServer::MessageType>("QWebGLWebSocketServer::MessageType"); +} + +QWebGLIntegration::~QWebGLIntegration() +{ + Q_D(QWebGLIntegration); + QWindowSystemInterface::unregisterTouchDevice(d->touchDevice); +} + +QWebGLIntegration *QWebGLIntegration::instance() +{ + return static_cast<QWebGLIntegration *>(qGuiApp->platformNativeInterface()); +} + +void QWebGLIntegration::initialize() +{ + Q_D(QWebGLIntegration); + d->inputContext = QPlatformInputContextFactory::create(); + d->screen = new QWebGLScreen; + screenAdded(d->screen, true); + + d->webSocketServer = new QWebGLWebSocketServer; + d->httpServer = new QWebGLHttpServer(d->webSocketServer, this); + bool ok = d->httpServer->listen(QHostAddress::Any, d->httpPort); + if (!ok) + qFatal("QWebGLIntegration::initialize: Failed to initialize"); + d->webSocketServerThread = new QThread(this); + d->webSocketServerThread->setObjectName("WebSocketServer"); + d->webSocketServer->moveToThread(d->webSocketServerThread); + connect(d->webSocketServerThread, &QThread::finished, + d->webSocketServer, &QObject::deleteLater); + QMetaObject::invokeMethod(d->webSocketServer, "create", Qt::QueuedConnection); + QMutexLocker lock(d->webSocketServer->mutex()); + d->webSocketServerThread->start(); + d->webSocketServer->waitCondition()->wait(d->webSocketServer->mutex()); + + qGuiApp->setQuitOnLastWindowClosed(false); +} + +void QWebGLIntegration::destroy() +{ + Q_D(QWebGLIntegration); + foreach (QWindow *w, qGuiApp->topLevelWindows()) + w->destroy(); + + destroyScreen(d->screen); + + d->screen = nullptr; + + d->webSocketServerThread->quit(); + d->webSocketServerThread->wait(); + delete d->webSocketServerThread; +} + +QAbstractEventDispatcher *QWebGLIntegration::createEventDispatcher() const +{ +#ifdef Q_OS_WIN + return new QWindowsGuiEventDispatcher; +#else + return createUnixEventDispatcher(); +#endif // Q_OS_WIN +} + +QPlatformServices *QWebGLIntegration::services() const +{ + Q_D(const QWebGLIntegration); + return &d->services; +} + +QPlatformInputContext *QWebGLIntegration::inputContext() const +{ + Q_D(const QWebGLIntegration); + return d->inputContext; +} + +QPlatformFontDatabase *QWebGLIntegration::fontDatabase() const +{ + Q_D(const QWebGLIntegration); + return &d->fontDatabase; +} + +QPlatformTheme *QWebGLIntegration::createPlatformTheme(const QString &name) const +{ +#ifdef Q_OS_WIN + return QPlatformIntegration::createPlatformTheme(name); +#else + return QGenericUnixTheme::createUnixTheme(name); +#endif // Q_OS_WIN +} + +QPlatformBackingStore *QWebGLIntegration::createPlatformBackingStore(QWindow *window) const +{ + Q_UNUSED(window); + return nullptr; +} + +QPlatformWindow *QWebGLIntegration::createPlatformWindow(QWindow *window) const +{ + Q_D(const QWebGLIntegration); + qCDebug(lcWebGL, "Creating platform window for: %p", window); + +#if defined(QT_QUICK_LIB) + if (window->inherits("QQuickWindow")) { + auto quickWindow = (QQuickWindow *)window; + quickWindow->setPersistentSceneGraph(false); + quickWindow->setPersistentOpenGLContext(false); + } +#endif + + d->windows.append(window); + QObject::connect(window, &QWindow::destroyed, [=] () + { + d->windows.removeAll(window); + }); + + QWindowSystemInterface::flushWindowSystemEvents(); + + QWebGLWindow *platformWindow = nullptr; + QWebSocket *socket = nullptr; + WId winId = -1; + { + QMutexLocker locker(&d->clients.mutex); + + if (d->clients.list.isEmpty()) { + QMetaObject::invokeMethod(window, "close", Qt::QueuedConnection); + return new QWebGLWindow(window); + } + + auto client = &d->clients.list.first(); + window->setScreen(client->platformScreen->screen()); + client->platformWindows.append(new QWebGLWindow(window)); + platformWindow = client->platformWindows.last(); + socket = client->socket; + platformWindow->create(); + platformWindow->requestActivateWindow(); + winId = platformWindow->winId(); + } + + const QVariantMap values { + { "x", platformWindow->geometry().x() }, + { "y", platformWindow->geometry().y() }, + { "width", platformWindow->geometry().width() }, + { "height", platformWindow->geometry().height() }, + { "winId", winId }, + { "title", qApp->applicationDisplayName() } + }; + d->sendMessage(socket, QWebGLWebSocketServer::MessageType::CreateCanvas, values); + + QObject::connect(window, &QWindow::windowTitleChanged, [=](const QString &title) + { + const QVariantMap values{{ "title", title }, { "winId", winId }}; + d->sendMessage(socket, QWebGLWebSocketServer::MessageType::ChangeTitle, values); + }); + qCDebug(lcWebGL, "Created platform window %p for: %p", platformWindow, window); + return platformWindow; +} + +QPlatformOpenGLContext *QWebGLIntegration::createPlatformOpenGLContext(QOpenGLContext *context) + const +{ + qCDebug(lcWebGL, "%p", context); + QVariant nativeHandle = context->nativeHandle(); + + const QSurfaceFormat adjustedFormat = context->format(); + QWebGLContext *ctx = new QWebGLContext(adjustedFormat); + context->setNativeHandle(nativeHandle); + return ctx; +} + +bool QWebGLIntegration::hasCapability(QPlatformIntegration::Capability cap) const +{ + // We assume that devices will have more and not less capabilities + switch (cap) { + case ThreadedPixmaps: return true; + case OpenGL: return true; + case ThreadedOpenGL: return true; + case WindowManagement: return false; + case RasterGLSurface: return true; + default: return QPlatformIntegration::hasCapability(cap); + } +} + +QPlatformNativeInterface *QWebGLIntegration::nativeInterface() const +{ + return const_cast<QWebGLIntegration *>(this); +} + +void QWebGLIntegration::openUrl(const QUrl &url) +{ + Q_D(QWebGLIntegration); + qCDebug(lcWebGL, "%s", qPrintable(url.toString())); + QMutexLocker locker(&d->clients.mutex); + for (auto &clientData : d->clients.list) { + const QVariantMap values { + { "url", url } + }; + d->sendMessage(clientData.socket, QWebGLWebSocketServer::MessageType::OpenUrl, values); + } +} + +QWebGLIntegrationPrivate::ClientData *QWebGLIntegrationPrivate::findClientData( + const QWebSocket *socket) +{ + QMutexLocker locker(&clients.mutex); + auto it = std::find_if(clients.list.begin(), clients.list.end(), [=](const ClientData &data) + { + return data.socket == socket; + }); + + return it != clients.list.end() ? &*it : nullptr; +} + +QWebGLIntegrationPrivate::ClientData *QWebGLIntegrationPrivate::findClientData( + const QPlatformSurface *surface) +{ + QMutexLocker locker(&clients.mutex); + auto it = std::find_if(clients.list.begin(), clients.list.end(), [=](const ClientData &data) + { + if (!data.platformWindows.isEmpty() && data.platformWindows.last()->surface()) + return surface == data.platformWindows.last()->surface()->surfaceHandle(); + return false; + }); + return it != clients.list.end() ? &*it : nullptr; +} + +QWebGLWindow *QWebGLIntegrationPrivate::findWindow(const ClientData &clientData, WId winId) +{ + auto &windows = clientData.platformWindows; + auto it = std::find_if(windows.begin(), windows.end(), [winId](QWebGLWindow *window) + { + return window->winId() == winId; + }); + Q_ASSERT(it != windows.end()); + return *it; +} + +void QWebGLIntegrationPrivate::clientConnected(QWebSocket *socket, + const int width, + const int height, + const double physicalWidth, + const double physicalHeight) +{ + Q_Q(QWebGLIntegration); + qCDebug(lcWebGL, "%p, Size: %dx%d. Physical Size: %fx%f", + socket, width, height, physicalWidth, physicalHeight); + QWebGLIntegrationPrivate::ClientData client; + client.socket = socket; + client.platformScreen = new QWebGLScreen(QSize(width, height), + QSizeF(physicalWidth, physicalHeight)); + clients.mutex.lock(); + clients.list.append(client); + clients.mutex.unlock(); + q->screenAdded(client.platformScreen, true); + connectNextClient(); +} + +void QWebGLIntegrationPrivate::clientDisconnected(QWebSocket *socket) +{ + qCDebug(lcWebGL, "%p", socket); + const auto predicate = [=](const QWebGLIntegrationPrivate::ClientData &item) + { + return socket == item.socket; + }; + + clients.mutex.lock(); + auto it = std::find_if(clients.list.begin(), clients.list.end(), predicate); + if (it != clients.list.end()) { + for (auto platformWindow : it->platformWindows) { + auto window = platformWindow->window(); + QTimer::singleShot(0, window, &QWindow::close); + } + clients.list.erase(it); + } + clients.mutex.unlock(); + connectNextClient(); +} + +void QWebGLIntegrationPrivate::connectNextClient() +{ + static QMutex connecting; + if (connecting.tryLock()) { + QTimer::singleShot(1000, [=]() { + clients.mutex.lock(); + if (!clients.list.isEmpty()) { + const auto clientData = clients.list.first(); + qCDebug(lcWebGL, "Connecting first client in the queue (%p)", + clientData.socket); + for (auto window : windows) + QMetaObject::invokeMethod(window, "showFullScreen", Qt::QueuedConnection); + } + clients.mutex.unlock(); + connecting.unlock(); + }); + }; +} + +void QWebGLIntegrationPrivate::sendMessage(QWebSocket *socket, + QWebGLWebSocketServer::MessageType type, + const QVariantMap &values) const +{ + const auto ok = QMetaObject::invokeMethod(webSocketServer, "sendMessage", + Q_ARG(QWebSocket*, socket), + Q_ARG(QWebGLWebSocketServer::MessageType, type), + Q_ARG(QVariantMap, values)); +#if defined(QT_DEBUG) + Q_ASSERT(ok); +#else + Q_UNUSED(ok); +#endif +} + +void QWebGLIntegrationPrivate::onTextMessageReceived(QWebSocket *socket, const QString &message) +{ + QJsonParseError parseError; + const auto document = QJsonDocument::fromJson(message.toUtf8(), &parseError); + Q_ASSERT(parseError.error == QJsonParseError::NoError); + Q_ASSERT(document.isObject()); + const auto object = document.object(); + Q_ASSERT(object.contains("type")); + const auto type = object[QStringLiteral("type")].toString(); + + auto integrationPrivate = QWebGLIntegrationPrivate::instance(); + const auto clientData = integrationPrivate->findClientData(socket); + + if (type == QStringLiteral("connect")) + clientConnected(socket, object["width"].toInt(), object["height"].toInt(), + object["physicalWidth"].toDouble(), object["physicalHeight"].toDouble()); + else if (!clientData || clientData->platformWindows.isEmpty()) + qCWarning(lcWebGL, "Message received before connect %s", qPrintable(message)); + else if (type == QStringLiteral("default_context_parameters")) + handleDefaultContextParameters(*clientData, object); + else if (type == QStringLiteral("gl_response")) + handleGlResponse(object); + else if (type == QStringLiteral("mouse")) + handleMouse(*clientData, object); + else if (type == QStringLiteral("wheel")) + handleWheel(*clientData, object); + else if (type == QStringLiteral("touch")) + handleTouch(*clientData, object); + else if (type.startsWith("key")) + handleKeyboard(*clientData, type, object); + else if (type == QStringLiteral("canvas_resize")) + handleCanvasResize(*clientData, object); +} + +void QWebGLIntegrationPrivate::handleDefaultContextParameters(const ClientData &clientData, + const QJsonObject &object) +{ + const auto winId = object.value("name").toInt(-1); + Q_ASSERT(winId != -1); + QWebGLWindow *platformWindow = findWindow(clientData, winId); + Q_ASSERT(platformWindow); + auto data = object.toVariantMap(); + data.remove("name"); + data.remove("type"); + QMap<GLenum, QVariant> result; + for (auto it = data.cbegin(), end = data.cend(); it != end; ++it) + result.insert(it.key().toInt(), *it); + platformWindow->setDefaults(result); +} + +void QWebGLIntegrationPrivate::handleGlResponse(const QJsonObject &object) +{ + qCDebug(lcWebGL, ) << "gl_response message received" << object; + QMutexLocker locker(&waitMutex); + const auto id = object["id"]; + const auto value = object["value"].toVariant(); + Q_ASSERT(pendingResponses.contains(id.toInt())); + receivedResponses.insert(id.toInt(), value); + pendingResponses.removeOne(id.toInt()); + waitCondition.wakeAll(); +} + +void QWebGLIntegrationPrivate::handleCanvasResize(const ClientData &clientData, + const QJsonObject &object) +{ + qCDebug(lcWebGL, ) << "canvas_resize message received" << object; + const auto width = object["width"].toInt(); + const auto height = object["height"].toInt(); + const auto physicalWidth = object["physicalWidth"].toDouble(); + const auto physicalHeight = object["physicalHeight"].toDouble(); + clientData.platformScreen->setGeometry(width, height, physicalWidth, physicalHeight); +} + +void QWebGLIntegrationPrivate::handleMouse(const ClientData &clientData, const QJsonObject &object) +{ + const auto winId = object.value("name").toInt(-1); + Q_ASSERT(winId != -1); + QPointF localPos(object.value("layerX").toDouble(), + object.value("layerY").toDouble()); + QPointF globalPos(object.value("clientX").toDouble(), + object.value("clientY").toDouble()); + auto buttons = static_cast<Qt::MouseButtons>(object.value("buttons").toInt()); + auto time = object.value("time").toDouble(); + auto platformWindow = findWindow(clientData, winId); + QWindowSystemInterface::handleMouseEvent(platformWindow->window(), + static_cast<ulong>(time), + localPos, + globalPos, + Qt::MouseButtons(buttons), + Qt::NoModifier, + Qt::MouseEventNotSynthesized); +} + +void QWebGLIntegrationPrivate::handleWheel(const ClientData &clientData, const QJsonObject &object) +{ + const auto winId = object.value("name").toInt(-1); + Q_ASSERT(winId != -1); + auto platformWindow = findWindow(clientData, winId); + auto time = object.value("time").toDouble(); + QPointF localPos(object.value("layerX").toDouble(), + object.value("layerY").toDouble()); + QPointF globalPos(object.value("clientX").toDouble(), + object.value("clientY").toDouble()); + const int deltaX = -object.value("deltaX").toInt(0); + const int deltaY = -object.value("deltaY").toInt(0); + auto orientation = deltaY != 0 ? Qt::Vertical : Qt::Horizontal; + QWindowSystemInterface::handleWheelEvent(platformWindow->window(), + time, + localPos, + globalPos, + orientation == Qt::Vertical ? deltaY : deltaX, + orientation); +} + +void QWebGLIntegrationPrivate::handleTouch(const ClientData &clientData, const QJsonObject &object) +{ + const auto winId = object.value("name").toInt(-1); + Q_ASSERT(winId != -1); + auto window = findWindow(clientData, winId)->window(); + const auto time = object.value("time").toDouble(); + const auto eventType = object.value("event").toString(); + const auto changedTouch = object.value("changedTouches").toArray().first().toObject(); + const auto clientX = changedTouch.value("clientX").toDouble(); + const auto clientY = changedTouch.value("clientY").toDouble(); + QList<QWindowSystemInterface::TouchPoint> points; + for (auto changedTouch : object.value("changedTouches").toArray()) { + QWindowSystemInterface::TouchPoint point; // support more than one + const auto pageX = changedTouch.toObject().value("pageX").toDouble(); + const auto pageY = changedTouch.toObject().value("pageY").toDouble(); + const auto radiousX = changedTouch.toObject().value("radiousX").toDouble(); + const auto radiousY = changedTouch.toObject().value("radiousY").toDouble(); + point.id = changedTouch.toObject().value("identifier").toInt(0); + point.pressure = changedTouch.toObject().value("force").toDouble(1.); + point.area.setX(pageX - radiousX); + point.area.setY(pageY - radiousY); + point.area.setWidth(radiousX * 2); + point.area.setHeight(radiousY * 2); + point.normalPosition.setX(changedTouch.toObject().value("normalPositionX").toDouble()); + point.normalPosition.setY(changedTouch.toObject().value("normalPositionY").toDouble()); + if (eventType == QStringLiteral("touchstart")) { + point.state = Qt::TouchPointPressed; + } else if (eventType == QStringLiteral("touchend")) { + qCDebug(lcWebGL, ) << "end" << object; + point.state = Qt::TouchPointReleased; + } else if (eventType == QStringLiteral("touchcancel")) { + QWindowSystemInterface::handleTouchCancelEvent(window, + time, + touchDevice, + Qt::NoModifier); + return; + } else { + point.state = Qt::TouchPointMoved; + } + point.rawPositions = {{ clientX, clientY }}; + points.append(point); + } + + QWindowSystemInterface::handleTouchEvent(window, + time, + touchDevice, + points, + Qt::NoModifier); +} + +void QWebGLIntegrationPrivate::handleKeyboard(const ClientData &clientData, + const QString &type, + const QJsonObject &object) +{ + const QHash<QString, Qt::Key> keyMap { + { "Alt", Qt::Key_Alt }, + { "ArrowDown", Qt::Key_Down }, + { "ArrowLeft", Qt::Key_Left }, + { "ArrowRight", Qt::Key_Right }, + { "ArrowUp", Qt::Key_Up }, + { "Backspace", Qt::Key_Backspace }, + { "Control", Qt::Key_Control }, + { "Delete", Qt::Key_Delete }, + { "End", Qt::Key_End }, + { "Enter", Qt::Key_Enter }, + { "F1", Qt::Key_F1 }, + { "F2", Qt::Key_F2 }, + { "F3", Qt::Key_F3 }, + { "F4", Qt::Key_F4 }, + { "F5", Qt::Key_F5 }, + { "F6", Qt::Key_F6 }, + { "F7", Qt::Key_F7 }, + { "F8", Qt::Key_F8 }, + { "F9", Qt::Key_F9 }, + { "F10", Qt::Key_F10 }, + { "F11", Qt::Key_F11 }, + { "F12", Qt::Key_F12 }, + { "Escape", Qt::Key_Escape }, + { "Home", Qt::Key_Home }, + { "Insert", Qt::Key_Insert }, + { "Meta", Qt::Key_Meta }, + { "PageDown", Qt::Key_PageDown }, + { "PageUp", Qt::Key_PageUp }, + { "Shift", Qt::Key_Shift }, + { "Space", Qt::Key_Space }, + { "AltGraph", Qt::Key_AltGr }, + { "Tab", Qt::Key_Tab }, + { "Unidentified", Qt::Key_F }, + { "OS", Qt::Key_Super_L } + }; + const auto timestamp = static_cast<ulong>(object.value("time").toDouble(-1)); + const auto keyName = object.value("key").toString(); + const auto specialKey = keyMap.find(keyName); + QEvent::Type eventType; + if (type == QStringLiteral("keydown")) + eventType = QEvent::KeyPress; + else if (type == QStringLiteral("keyup")) + eventType = QEvent::KeyRelease; + else + return; + QString string(object.value("key").toString()); + int key = object.value("which").toInt(0); + if (specialKey != keyMap.end()) { + key = *specialKey; + string.clear(); + } + + const auto window = clientData.platformWindows.last()->window(); + QWindowSystemInterface::handleKeyEvent(window, + timestamp, + eventType, + key, + convertKeyboardModifiers(object), + string); +} + +Qt::KeyboardModifiers QWebGLIntegrationPrivate::convertKeyboardModifiers(const QJsonObject &object) +{ + Qt::KeyboardModifiers modifiers = Qt::NoModifier; + if (object.value("ctrlKey").toBool()) + modifiers |= Qt::ControlModifier; + if (object.value("shiftKey").toBool()) + modifiers |= Qt::ShiftModifier; + if (object.value("altKey").toBool()) + modifiers |= Qt::AltModifier; + if (object.value("metaKey").toBool()) + modifiers |= Qt::MetaModifier; + return modifiers; +} + +QT_END_NAMESPACE |
