From 21bf9315599d2889ed559e393a404db5a3cff11a Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 1 Sep 2016 16:32:06 -0700 Subject: [PATCH] eventBridge for web entities. --- interface/resources/qml/controls/WebView.qml | 11 ++++++ .../src/RenderableWebEntityItem.cpp | 36 ++++++++++++++++--- .../src/RenderableWebEntityItem.h | 14 ++++++-- libraries/entities/src/EntityItem.h | 2 ++ .../entities/src/EntityScriptingInterface.cpp | 12 +++++++ .../entities/src/EntityScriptingInterface.h | 4 +++ 6 files changed, 73 insertions(+), 6 deletions(-) diff --git a/interface/resources/qml/controls/WebView.qml b/interface/resources/qml/controls/WebView.qml index 99dc9c21c9..71353932cf 100644 --- a/interface/resources/qml/controls/WebView.qml +++ b/interface/resources/qml/controls/WebView.qml @@ -1,8 +1,16 @@ import QtQuick 2.5 import QtWebEngine 1.1 +import QtWebChannel 1.0 Item { property alias url: root.url + property alias eventBridge: eventBridgeWrapper.eventBridge + + QtObject { + id: eventBridgeWrapper + WebChannel.id: "eventBridgeWrapper" + property var eventBridge; + } WebEngineView { id: root @@ -16,6 +24,8 @@ Item { profile.httpUserAgent: "Mozilla/5.0 Chrome (HighFidelityInterface)" + webChannel.registeredObjects: [eventBridgeWrapper] + Component.onCompleted: { console.log("Connecting JS messaging to Hifi Logging") // Ensure the JS from the web-engine makes it to our logging @@ -76,6 +86,7 @@ Item { //profile: desktop.browserProfile } + // virtual keyboard Keyboard { id: keyboard1 x: 197 diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 426fd20e02..fb4f020a1b 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -37,12 +37,28 @@ static uint64_t MAX_NO_RENDER_INTERVAL = 30 * USECS_PER_SECOND; static int MAX_WINDOW_SIZE = 4096; static float OPAQUE_ALPHA_THRESHOLD = 0.99f; -void WebEntityQMLAPIHelper::synthesizeKeyPress(QString key) { +void WebEntityAPIHelper::synthesizeKeyPress(QString key) { if (_ptr) { _ptr->synthesizeKeyPress(key); } } +void WebEntityAPIHelper::emitScriptEvent(const QVariant& message) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "emitScriptEvent", Qt::QueuedConnection, Q_ARG(QVariant, message)); + } else { + emit scriptEventReceived(message); + } +} + +void WebEntityAPIHelper::emitWebEvent(const QVariant& message) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "emitWebEvent", Qt::QueuedConnection, Q_ARG(QVariant, message)); + } else { + emit webEventReceived(message); + } +} + EntityItemPointer RenderableWebEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { EntityItemPointer entity{ new RenderableWebEntityItem(entityID) }; entity->setProperties(properties); @@ -58,11 +74,18 @@ RenderableWebEntityItem::RenderableWebEntityItem(const EntityItemID& entityItemI _touchDevice.setName("RenderableWebEntityItemTouchDevice"); _touchDevice.setMaximumTouchPoints(4); - _webEntityQMLAPIHelper.setPtr(this); + _webEntityAPIHelper.setPtr(this); + _webEntityAPIHelper.moveToThread(qApp->thread()); + + // forward web events to EntityScriptingInterface + auto entities = DependencyManager::get(); + QObject::connect(&_webEntityAPIHelper, &WebEntityAPIHelper::webEventReceived, [=](const QVariant& message) { + emit entities->webEventReceived(entityItemID, message); + }); } RenderableWebEntityItem::~RenderableWebEntityItem() { - _webEntityQMLAPIHelper.setPtr(nullptr); + _webEntityAPIHelper.setPtr(nullptr); destroyWebSurface(); qDebug() << "Destroyed web entity " << getID(); } @@ -83,9 +106,10 @@ bool RenderableWebEntityItem::buildWebSurface(EntityTreeRenderer* renderer) { _webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/controls/")); _webSurface->load("WebView.qml"); _webSurface->resume(); + _webSurface->getRootItem()->setProperty("eventBridge", QVariant::fromValue(&_webEntityAPIHelper)); _webSurface->getRootItem()->setProperty("url", _sourceUrl); _webSurface->getRootContext()->setContextProperty("desktop", QVariant()); - _webSurface->getRootContext()->setContextProperty("webEntity", &_webEntityQMLAPIHelper); + _webSurface->getRootContext()->setContextProperty("webEntity", &_webEntityAPIHelper); _connection = QObject::connect(_webSurface, &OffscreenQmlSurface::textureUpdated, [&](GLuint textureId) { _texture = textureId; }); @@ -329,3 +353,7 @@ void RenderableWebEntityItem::synthesizeKeyPress(QString key) { QCoreApplication::postEvent(getEventHandler(), pressEvent); QCoreApplication::postEvent(getEventHandler(), releaseEvent); } + +void RenderableWebEntityItem::emitScriptEvent(const QVariant& message) { + _webEntityAPIHelper.emitScriptEvent(message); +} diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.h b/libraries/entities-renderer/src/RenderableWebEntityItem.h index ec8223432c..6a19bd12cd 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.h +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.h @@ -24,7 +24,7 @@ class QObject; class EntityTreeRenderer; class RenderableWebEntityItem; -class WebEntityQMLAPIHelper : public QObject { +class WebEntityAPIHelper : public QObject { Q_OBJECT public: void setPtr(RenderableWebEntityItem* ptr) { @@ -32,6 +32,14 @@ public: } Q_INVOKABLE void synthesizeKeyPress(QString key); + // event bridge +public slots: + void emitScriptEvent(const QVariant& scriptMessage); + void emitWebEvent(const QVariant& webMessage); +signals: + void scriptEventReceived(const QVariant& message); + void webEventReceived(const QVariant& message); + protected: RenderableWebEntityItem* _ptr{ nullptr }; }; @@ -55,6 +63,8 @@ public: void update(const quint64& now) override; bool needsToCallUpdate() const override { return _webSurface != nullptr; } + void emitScriptEvent(const QVariant& message); + SIMPLE_RENDERABLE(); virtual bool isTransparent() override; @@ -75,7 +85,7 @@ private: QTouchEvent _lastTouchEvent { QEvent::TouchUpdate }; uint64_t _lastRenderTime{ 0 }; QTouchDevice _touchDevice; - WebEntityQMLAPIHelper _webEntityQMLAPIHelper; + WebEntityAPIHelper _webEntityAPIHelper; QMetaObject::Connection _mousePressConnection; QMetaObject::Connection _mouseReleaseConnection; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index e572bf4de8..a751d76b2a 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -446,6 +446,8 @@ public: virtual void setProxyWindow(QWindow* proxyWindow) {} virtual QObject* getEventHandler() { return nullptr; } + virtual void emitScriptEvent(const QVariant& message) {} + protected: void setSimulated(bool simulated) { _simulated = simulated; } diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 2dca21ac73..12b9e2fa79 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -1289,6 +1289,17 @@ bool EntityScriptingInterface::wantsHandControllerPointerEvents(QUuid id) { return result; } +void EntityScriptingInterface::emitScriptEvent(const EntityItemID& entityID, const QVariant& message) { + if (_entityTree) { + _entityTree->withReadLock([&] { + EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(entityID)); + if (entity) { + entity->emitScriptEvent(message); + } + }); + } +} + float EntityScriptingInterface::calculateCost(float mass, float oldVelocity, float newVelocity) { return std::abs(mass * (newVelocity - oldVelocity)); } @@ -1305,3 +1316,4 @@ float EntityScriptingInterface::getCostMultiplier() { void EntityScriptingInterface::setCostMultiplier(float value) { costMultiplier = value; } + diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index be9b1d27e7..cb69cebe6b 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -205,6 +205,8 @@ public slots: Q_INVOKABLE bool wantsHandControllerPointerEvents(QUuid id); + Q_INVOKABLE void emitScriptEvent(const EntityItemID& entityID, const QVariant& message); + signals: void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); @@ -232,6 +234,8 @@ signals: void clearingEntities(); void debitEnergySource(float value); + void webEventReceived(const EntityItemID& entityItemID, const QVariant& message); + private: bool actionWorker(const QUuid& entityID, std::function actor); bool setVoxels(QUuid entityID, std::function actor);