From b70ee63225c340889a20932f8ebc8d76fb484226 Mon Sep 17 00:00:00 2001 From: Karol Suprynowicz Date: Fri, 5 Jul 2024 21:24:32 +0200 Subject: [PATCH] Add mouse wheel event injection from script engine --- interface/src/Application.cpp | 4 ++++ interface/src/Application.h | 3 +++ .../controllers/AbstractInputEventInterface.h | 23 ++++++++++++++++++ .../src/controllers/ScriptingInterface.cpp | 24 +++++++++++++++++++ .../src/controllers/ScriptingInterface.h | 16 +++++++++++++ 5 files changed, 70 insertions(+) create mode 100644 libraries/controllers/src/controllers/AbstractInputEventInterface.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6c09bf32e07..b79478aa37f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -7516,6 +7516,10 @@ int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer return statsMessageLength; } +void Application::postEventToOverlayUI(QEvent *event) { + QCoreApplication::postEvent(getPrimaryWidget(), event); +} + void Application::registerScriptEngineWithApplicationServices(ScriptManagerPointer& scriptManager) { auto scriptEngine = scriptManager->engine(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 53b827fdb85..a1e9a8aa74e 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -112,6 +113,7 @@ class Application; #define qApp (static_cast(QCoreApplication::instance())) class Application : public QApplication, + public AbstractInputEventInterface, public AbstractViewStateInterface, public AbstractScriptingServicesInterface, public AbstractUriHandler, @@ -277,6 +279,7 @@ class Application : public QApplication, NodeToOctreeSceneStats* getOcteeSceneStats() { return &_octreeServerSceneStats; } virtual controller::ScriptingInterface* getControllerScriptingInterface() { return _controllerScriptingInterface; } + void postEventToOverlayUI(QEvent *event) override; virtual void registerScriptEngineWithApplicationServices(ScriptManagerPointer& scriptManager) override; virtual void copyCurrentViewFrustum(ViewFrustum& viewOut) const override { copyDisplayViewFrustum(viewOut); } diff --git a/libraries/controllers/src/controllers/AbstractInputEventInterface.h b/libraries/controllers/src/controllers/AbstractInputEventInterface.h new file mode 100644 index 00000000000..817b92fbcb3 --- /dev/null +++ b/libraries/controllers/src/controllers/AbstractInputEventInterface.h @@ -0,0 +1,23 @@ +// AbstractInputEventInterface.h +// libraries/controllers/src/controllers +// +// Created by dr Karol Suprynowicz on 2024.07.04. +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#ifndef overte_AbstractInputEventInterface_h +#define overte_AbstractInputEventInterface_h + +#include + +/// Used by the libraries to post events into overlay UI. +class AbstractInputEventInterface { +public: + virtual void postEventToOverlayUI(QEvent *event) = 0; +}; + +#endif // overte_AbstractInputEventInterface_h diff --git a/libraries/controllers/src/controllers/ScriptingInterface.cpp b/libraries/controllers/src/controllers/ScriptingInterface.cpp index 0c8869c8956..2d29ed3c376 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.cpp +++ b/libraries/controllers/src/controllers/ScriptingInterface.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -32,6 +33,8 @@ #include #include +#include "AbstractInputEventInterface.h" + ScriptValue inputControllerToScriptValue(ScriptEngine* engine, controller::InputController* const& in) { return engine->newQObject(in, ScriptEngine::QtOwnership); @@ -214,6 +217,27 @@ namespace controller { return DependencyManager::get()->triggerHapticPulseOnDevice(device, strength, SHORT_HAPTIC_DURATION_MS, index); } + void ScriptingInterface::emitMouseWheelEvent(glm::vec2 position, glm::vec2 globalPosition, glm::vec2 angleDelta, bool sendToHUDUI) { + auto wheelEvent = new QWheelEvent(QPointF(position.x, position.y), + QPointF(globalPosition.x, globalPosition.y), + QPoint(0,0), + QPoint((int)(angleDelta.x), (int)(angleDelta.y)), + Qt::NoButton, + Qt::NoModifier, Qt::NoScrollPhase, + false); + if (sendToHUDUI) { + auto abstractViewStateInterface = dynamic_cast(QCoreApplication::instance()); + if (abstractViewStateInterface) { + abstractViewStateInterface->postEventToOverlayUI(wheelEvent); + } else { + // This should never happen. + Q_ASSERT(false); + } + } else { + QCoreApplication::postEvent(QCoreApplication::instance(), wheelEvent); + } + } + void ScriptingInterface::updateMaps() { QVariantMap newHardware; auto userInputMapper = DependencyManager::get(); diff --git a/libraries/controllers/src/controllers/ScriptingInterface.h b/libraries/controllers/src/controllers/ScriptingInterface.h index 96680dd28c2..9e22d616619 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.h +++ b/libraries/controllers/src/controllers/ScriptingInterface.h @@ -249,6 +249,22 @@ namespace controller { */ Q_INVOKABLE bool triggerShortHapticPulseOnDevice(unsigned int device, float strength, uint16_t index = 2) const; + /*@jsdoc + * Emits a mouse wheel scroll event. + * @function Controller.emitMouseWheelEvent + * @param {Vec2} position - Event position relative to the UI element. + * @param {Vec2} globalPosition - Global position of the event. + * @param {Vec2} delta - Amount to scroll horizontally and vertically. + * @param {boolean} sendToHUDUI - If true, the event will be sent to HUD UI first, and only if it + * is not used there it will go to other UI elements. If false the mouse wheel event will skip HUD UI. + * @example Emit a sideways scroll event every 1 second. + * Script.setInterval(function () { + * Controller.emitMouseWheelEvent({x:50,y:50}, {x:50,y:50}, {x:50,y:50}, true); + * print("Wheel event emitted."); + * }, 1000); + */ + Q_INVOKABLE void emitMouseWheelEvent(glm::vec2 position, glm::vec2 globalPosition, glm::vec2 delta, bool sendToHUDUI); + /*@jsdoc * Creates a new controller mapping. Routes can then be added to the mapping using {@link MappingObject} methods and * routed to Standard controls, Actions, or script functions using {@link RouteObject}