From 2f3fa80b96eab8a8130fcb6be580932c38e74f00 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 26 May 2016 09:52:22 +1200 Subject: [PATCH 01/31] Add Clipboard.getContentsDimensions() JavaScript method --- interface/src/scripting/ClipboardScriptingInterface.cpp | 4 ++++ interface/src/scripting/ClipboardScriptingInterface.h | 1 + libraries/entities/src/EntityTree.cpp | 7 +++++++ libraries/entities/src/EntityTree.h | 1 + 4 files changed, 13 insertions(+) diff --git a/interface/src/scripting/ClipboardScriptingInterface.cpp b/interface/src/scripting/ClipboardScriptingInterface.cpp index b0ef6c760d..b803080538 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.cpp +++ b/interface/src/scripting/ClipboardScriptingInterface.cpp @@ -14,6 +14,10 @@ ClipboardScriptingInterface::ClipboardScriptingInterface() { } +glm::vec3 ClipboardScriptingInterface::getContentsDimensions() { + return qApp->getEntityClipboard()->getContentsDimensions(); +} + float ClipboardScriptingInterface::getClipboardContentsLargestDimension() { return qApp->getEntityClipboard()->getContentsLargestDimension(); } diff --git a/interface/src/scripting/ClipboardScriptingInterface.h b/interface/src/scripting/ClipboardScriptingInterface.h index 73bebd4836..4737a194df 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.h +++ b/interface/src/scripting/ClipboardScriptingInterface.h @@ -22,6 +22,7 @@ signals: void readyToImport(); public slots: + glm::vec3 getContentsDimensions(); /// returns the overall dimensions of everything on the blipboard float getClipboardContentsLargestDimension(); /// returns the largest dimension of everything on the clipboard bool importEntities(const QString& filename); bool exportEntities(const QString& filename, const QVector& entityIDs); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index b85ee1dcf9..581e0a9568 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1284,6 +1284,7 @@ class ContentsDimensionOperator : public RecurseOctreeOperator { public: virtual bool preRecursion(OctreeElementPointer element); virtual bool postRecursion(OctreeElementPointer element) { return true; } + glm::vec3 getDimensions() const { return _contentExtents.size(); } float getLargestDimension() const { return _contentExtents.largestDimension(); } private: Extents _contentExtents; @@ -1295,6 +1296,12 @@ bool ContentsDimensionOperator::preRecursion(OctreeElementPointer element) { return true; } +glm::vec3 EntityTree::getContentsDimensions() { + ContentsDimensionOperator theOperator; + recurseTreeWithOperator(&theOperator); + return theOperator.getDimensions(); +} + float EntityTree::getContentsLargestDimension() { ContentsDimensionOperator theOperator; recurseTreeWithOperator(&theOperator); diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 03b8a9b55a..a85624c9ae 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -207,6 +207,7 @@ public: bool skipThoseWithBadParents) override; virtual bool readFromMap(QVariantMap& entityDescription) override; + glm::vec3 getContentsDimensions(); float getContentsLargestDimension(); virtual void resetEditStats() override { From 44fe7c11443ddab37f97ec8a85ffad17cc3831d9 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 2 Jun 2016 21:26:33 +1200 Subject: [PATCH 02/31] Add Entities.getChildrenIDs() method --- .../entities/src/EntityScriptingInterface.cpp | 21 +++++++++++++++++++ .../entities/src/EntityScriptingInterface.h | 1 + 2 files changed, 22 insertions(+) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 15c2bffd80..d09fc60d9b 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -1121,6 +1121,27 @@ QStringList EntityScriptingInterface::getJointNames(const QUuid& entityID) { return result; } +QVector EntityScriptingInterface::getChildrenIDs(const QUuid& parentID) { + QVector result; + if (!_entityTree) { + return result; + } + + EntityItemPointer entity = _entityTree->findEntityByEntityItemID(parentID); + if (!entity) { + qDebug() << "EntityScriptingInterface::getChildrenIDs - no entity with ID" << parentID; + return result; + } + + _entityTree->withReadLock([&] { + entity->forEachChild([&](SpatiallyNestablePointer child) { + result.push_back(child->getID()); + }); + }); + + return result; +} + QVector EntityScriptingInterface::getChildrenIDsOfJoint(const QUuid& parentID, int jointIndex) { QVector result; if (!_entityTree) { diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 2f5446874b..8ae6a77dab 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -171,6 +171,7 @@ public slots: Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name); Q_INVOKABLE QStringList getJointNames(const QUuid& entityID); + Q_INVOKABLE QVector getChildrenIDs(const QUuid& parentID); Q_INVOKABLE QVector getChildrenIDsOfJoint(const QUuid& parentID, int jointIndex); signals: From 8f9fc08226d3df4059f8f00403d588799815a060 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 3 Jun 2016 11:08:05 -0700 Subject: [PATCH 03/31] Add version number to avatar recording frame New recordings will have a version number of 1. A missing version field indicates the initial version of 0. Warn when playing back version 0 files which are no longer fully supported and fall back to default pose. Playback of version 1 files should work as expected. --- libraries/avatars/src/AvatarData.cpp | 47 +++++++++++++++++++++------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 16e4bd5437..2fa26a5f64 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1270,6 +1270,10 @@ static const QString JSON_AVATAR_DISPLAY_NAME = QStringLiteral("displayName"); static const QString JSON_AVATAR_ATTACHEMENTS = QStringLiteral("attachments"); static const QString JSON_AVATAR_ENTITIES = QStringLiteral("attachedEntities"); static const QString JSON_AVATAR_SCALE = QStringLiteral("scale"); +static const QString JSON_AVATAR_VERSION = QStringLiteral("version"); + +static const int JSON_AVATAR_JOINT_ROTATIONS_IN_RELATIVE_FRAME_VERSION = 0; +static const int JSON_AVATAR_JOINT_ROTATIONS_IN_ABSOLUTE_FRAME_VERSION = 1; QJsonValue toJsonValue(const JointData& joint) { QJsonArray result; @@ -1293,6 +1297,8 @@ JointData jointDataFromJsonValue(const QJsonValue& json) { QJsonObject AvatarData::toJson() const { QJsonObject root; + root[JSON_AVATAR_VERSION] = JSON_AVATAR_JOINT_ROTATIONS_IN_ABSOLUTE_FRAME_VERSION; + if (!getSkeletonModelURL().isEmpty()) { root[JSON_AVATAR_BODY_MODEL] = getSkeletonModelURL().toString(); } @@ -1359,6 +1365,15 @@ QJsonObject AvatarData::toJson() const { } void AvatarData::fromJson(const QJsonObject& json) { + + int version; + if (json.contains(JSON_AVATAR_VERSION)) { + version = json[JSON_AVATAR_VERSION].toInt(); + } else { + // initial data did not have a version field. + version = JSON_AVATAR_JOINT_ROTATIONS_IN_RELATIVE_FRAME_VERSION; + } + // The head setOrientation likes to overwrite the avatar orientation, // so lets do the head first // Most head data is relative to the avatar, and needs no basis correction, @@ -1424,20 +1439,28 @@ void AvatarData::fromJson(const QJsonObject& json) { // } // } - // Joint rotations are relative to the avatar, so they require no basis correction if (json.contains(JSON_AVATAR_JOINT_ARRAY)) { - QVector jointArray; - QJsonArray jointArrayJson = json[JSON_AVATAR_JOINT_ARRAY].toArray(); - jointArray.reserve(jointArrayJson.size()); - int i = 0; - for (const auto& jointJson : jointArrayJson) { - auto joint = jointDataFromJsonValue(jointJson); - jointArray.push_back(joint); - setJointData(i, joint.rotation, joint.translation); - _jointData[i].rotationSet = true; // Have to do that to broadcast the avatar new pose - i++; + if (version == JSON_AVATAR_JOINT_ROTATIONS_IN_RELATIVE_FRAME_VERSION) { + // because we don't have the full joint hierarchy skeleton of the model, + // we can't properly convert from relative rotations into absolute rotations. + quint64 now = usecTimestampNow(); + if (shouldLogError(now)) { + qCWarning(avatars) << "Version 0 avatar recordings not supported. using default rotations"; + } + } else { + QVector jointArray; + QJsonArray jointArrayJson = json[JSON_AVATAR_JOINT_ARRAY].toArray(); + jointArray.reserve(jointArrayJson.size()); + int i = 0; + for (const auto& jointJson : jointArrayJson) { + auto joint = jointDataFromJsonValue(jointJson); + jointArray.push_back(joint); + setJointData(i, joint.rotation, joint.translation); + _jointData[i].rotationSet = true; // Have to do that to broadcast the avatar new pose + i++; + } + setRawJointData(jointArray); } - setRawJointData(jointArray); } } From 3a5d5aab0175667cd48901f5a80e3bdb25fc2f30 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 3 Jun 2016 14:33:50 -0700 Subject: [PATCH 04/31] Removed innocuous "AvatarData packet size mismatch" warning This should not have been a warning, it is expected behavior when a BulkAvatarData packet is filled with data from more then one avatar. --- libraries/avatars/src/AvatarData.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 16e4bd5437..283177c93c 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -632,13 +632,6 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { #endif int numBytesRead = sourceBuffer - startPosition; - - if (numBytesRead != buffer.size()) { - if (shouldLogError(now)) { - qCWarning(avatars) << "AvatarData packet size mismatch: expected " << numBytesRead << " received " << buffer.size(); - } - } - _averageBytesReceived.updateAverage(numBytesRead); return numBytesRead; } From bc81f00dc76e45a29f79800a5949a5fe7c0515ca Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sat, 4 Jun 2016 20:47:10 -0700 Subject: [PATCH 05/31] Eliminate extraneous writes for unchanged values --- libraries/shared/src/SettingHandle.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/SettingHandle.cpp b/libraries/shared/src/SettingHandle.cpp index cad2a0286f..b2f23f5a04 100644 --- a/libraries/shared/src/SettingHandle.cpp +++ b/libraries/shared/src/SettingHandle.cpp @@ -28,7 +28,9 @@ Settings::~Settings() { } void Settings::remove(const QString& key) { - _manager->remove(key); + if (key == "" || _manager->contains(key)) { + _manager->remove(key); + } } QStringList Settings::childGroups() const { @@ -72,7 +74,9 @@ void Settings::endGroup() { } void Settings::setValue(const QString& name, const QVariant& value) { - _manager->setValue(name, value); + if (_manager->value(name) != value) { + _manager->setValue(name, value); + } } QVariant Settings::value(const QString& name, const QVariant& defaultValue) const { From 49c835b6fc72707cedc9c8a66708daaeabe28a95 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sat, 4 Jun 2016 20:53:30 -0700 Subject: [PATCH 06/31] use camera twist for walk steering --- interface/src/avatar/MyAvatar.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 6fdcd8f797..ca9bbec6ff 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1214,7 +1214,10 @@ void MyAvatar::updateMotors() { if (_characterController.getState() == CharacterController::State::Hover) { motorRotation = getHead()->getCameraOrientation(); } else { - motorRotation = getOrientation(); + // non-hovering = walking: follow camera twist about vertical but not lift + // so we decompose camera's rotation and store the twist part in motorRotation + glm::quat liftRotation; + swingTwistDecomposition(getHead()->getCameraOrientation(), getHead()->getUpDirection(), liftRotation, motorRotation); } const float DEFAULT_MOTOR_TIMESCALE = 0.2f; const float INVALID_MOTOR_TIMESCALE = 1.0e6f; From e6844e246884a5181e016746b7df2c41771e71f8 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sat, 4 Jun 2016 21:11:31 -0700 Subject: [PATCH 07/31] use world-UP rather than head-UP --- interface/src/avatar/MyAvatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index ca9bbec6ff..074cef865e 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1217,7 +1217,7 @@ void MyAvatar::updateMotors() { // non-hovering = walking: follow camera twist about vertical but not lift // so we decompose camera's rotation and store the twist part in motorRotation glm::quat liftRotation; - swingTwistDecomposition(getHead()->getCameraOrientation(), getHead()->getUpDirection(), liftRotation, motorRotation); + swingTwistDecomposition(getHead()->getCameraOrientation(), _worldUpDirection, liftRotation, motorRotation); } const float DEFAULT_MOTOR_TIMESCALE = 0.2f; const float INVALID_MOTOR_TIMESCALE = 1.0e6f; From 3dadb515f37615803b21543add98784c78d23d59 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 1 Jun 2016 20:30:43 -0700 Subject: [PATCH 08/31] Add plugins name to their metadata file --- plugins/hifiNeuron/src/plugin.json | 2 +- plugins/hifiSdl2/src/plugin.json | 2 +- plugins/hifiSixense/src/plugin.json | 2 +- plugins/hifiSpacemouse/src/plugin.json | 2 +- plugins/oculus/src/oculus.json | 2 +- plugins/oculusLegacy/src/oculus.json | 2 +- plugins/openvr/src/plugin.json | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/hifiNeuron/src/plugin.json b/plugins/hifiNeuron/src/plugin.json index 0967ef424b..d153b5cebd 100644 --- a/plugins/hifiNeuron/src/plugin.json +++ b/plugins/hifiNeuron/src/plugin.json @@ -1 +1 @@ -{} +{"name":"Neuron"} diff --git a/plugins/hifiSdl2/src/plugin.json b/plugins/hifiSdl2/src/plugin.json index 0967ef424b..a65846ecab 100644 --- a/plugins/hifiSdl2/src/plugin.json +++ b/plugins/hifiSdl2/src/plugin.json @@ -1 +1 @@ -{} +{"name":"SDL2"} diff --git a/plugins/hifiSixense/src/plugin.json b/plugins/hifiSixense/src/plugin.json index 0967ef424b..9e6e15a354 100644 --- a/plugins/hifiSixense/src/plugin.json +++ b/plugins/hifiSixense/src/plugin.json @@ -1 +1 @@ -{} +{"name":"Sixense"} diff --git a/plugins/hifiSpacemouse/src/plugin.json b/plugins/hifiSpacemouse/src/plugin.json index 0967ef424b..294f436039 100644 --- a/plugins/hifiSpacemouse/src/plugin.json +++ b/plugins/hifiSpacemouse/src/plugin.json @@ -1 +1 @@ -{} +{"name":"Spacemouse"} diff --git a/plugins/oculus/src/oculus.json b/plugins/oculus/src/oculus.json index 0967ef424b..86546c8dd5 100644 --- a/plugins/oculus/src/oculus.json +++ b/plugins/oculus/src/oculus.json @@ -1 +1 @@ -{} +{"name":"Oculus Rift"} diff --git a/plugins/oculusLegacy/src/oculus.json b/plugins/oculusLegacy/src/oculus.json index 0967ef424b..4cd9a136b3 100644 --- a/plugins/oculusLegacy/src/oculus.json +++ b/plugins/oculusLegacy/src/oculus.json @@ -1 +1 @@ -{} +{"name":"Oculus Rift (0.5) (Legacy)"} diff --git a/plugins/openvr/src/plugin.json b/plugins/openvr/src/plugin.json index 0967ef424b..d68c8e68d3 100644 --- a/plugins/openvr/src/plugin.json +++ b/plugins/openvr/src/plugin.json @@ -1 +1 @@ -{} +{"name":"OpenVR (Vive)"} From d8493f960a32d0d6d0db83cbfe8c38dfedd4a27b Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 1 Jun 2016 20:50:24 -0700 Subject: [PATCH 09/31] Add command line option to enable/disable plugins --- interface/src/Application.cpp | 29 +++++++- interface/src/Application.h | 2 +- interface/src/main.cpp | 28 ++++---- .../plugins/src/plugins/PluginManager.cpp | 66 ++++++++++++++++++- libraries/plugins/src/plugins/PluginManager.h | 15 +++-- 5 files changed, 117 insertions(+), 23 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e789b7c508..62f3a3a9c5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -4936,7 +4937,33 @@ void Application::postLambdaEvent(std::function f) { } } -void Application::initPlugins() { +void Application::initPlugins(const QStringList& arguments) { + QCommandLineOption display("display", "Default display", "display"); + QCommandLineOption disableDisplays("disable-displays", "Displays to disable", "display"); + QCommandLineOption disableInputs("disable-inputs", "Inputs to disable", "input"); + + QCommandLineParser parser; + parser.addOption(display); + parser.addOption(disableDisplays); + parser.addOption(disableInputs); + parser.parse(arguments); + + if (parser.isSet(display)) { + auto defaultDisplay = parser.value(display); + qInfo() << "Setting prefered display plugin:" << defaultDisplay; + } + + if (parser.isSet(disableDisplays)) { + auto disabledDisplays = parser.value(disableDisplays).split(',', QString::SkipEmptyParts); + qInfo() << "Disabling following display plugins:" << disabledDisplays; + PluginManager::getInstance()->disableDisplays(disabledDisplays); + } + + if (parser.isSet(disableInputs)) { + auto disabledInputs = parser.value(disableInputs).split(',', QString::SkipEmptyParts); + qInfo() << "Disabling following input plugins:" << disabledInputs; + PluginManager::getInstance()->disableInputs(disabledInputs); + } } void Application::shutdownPlugins() { diff --git a/interface/src/Application.h b/interface/src/Application.h index a17250a58e..ed7b582bfc 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -101,7 +101,7 @@ public: }; // FIXME? Empty methods, do we still need them? - static void initPlugins(); + static void initPlugins(const QStringList& arguments); static void shutdownPlugins(); Application(int& argc, char** argv, QElapsedTimer& startup_time); diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 13f9470fda..6866d5637c 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -8,6 +8,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include #include #include @@ -17,6 +19,12 @@ #include #include +#ifdef HAS_BUGSPLAT +#include +#include +#include +#endif + #include #include @@ -25,13 +33,7 @@ #include "InterfaceLogging.h" #include "UserActivityLogger.h" #include "MainWindow.h" -#include -#ifdef HAS_BUGSPLAT -#include -#include -#include -#endif int main(int argc, const char* argv[]) { #if HAS_BUGSPLAT @@ -46,6 +48,12 @@ int main(int argc, const char* argv[]) { bool instanceMightBeRunning = true; + QStringList arguments; + for (int i = 0; i < argc; ++i) { + arguments << argv[i]; + } + + #ifdef Q_OS_WIN // Try to create a shared memory block - if it can't be created, there is an instance of // interface already running. We only do this on Windows for now because of the potential @@ -64,12 +72,6 @@ int main(int argc, const char* argv[]) { // Try to connect - if we can't connect, interface has probably just gone down if (socket.waitForConnected(LOCAL_SERVER_TIMEOUT_MS)) { - - QStringList arguments; - for (int i = 0; i < argc; ++i) { - arguments << argv[i]; - } - QCommandLineParser parser; QCommandLineOption urlOption("url", "", "value"); parser.addOption(urlOption); @@ -135,7 +137,7 @@ int main(int argc, const char* argv[]) { // Oculus initialization MUST PRECEDE OpenGL context creation. // The nature of the Application constructor means this has to be either here, // or in the main window ctor, before GL startup. - Application::initPlugins(); + Application::initPlugins(arguments); int exitCode; { diff --git a/libraries/plugins/src/plugins/PluginManager.cpp b/libraries/plugins/src/plugins/PluginManager.cpp index eb6465aab2..9047b1c271 100644 --- a/libraries/plugins/src/plugins/PluginManager.cpp +++ b/libraries/plugins/src/plugins/PluginManager.cpp @@ -25,6 +25,49 @@ PluginManager* PluginManager::getInstance() { return &_manager; } +QString getPluginNameFromMetaData(QJsonObject object) { + static const char* METADATA_KEY = "MetaData"; + static const char* NAME_KEY = "name"; + + if (!object.contains(METADATA_KEY) || !object[METADATA_KEY].isObject()) { + return QString(); + } + + auto metaDataObject = object[METADATA_KEY].toObject(); + + if (!metaDataObject.contains(NAME_KEY) || !metaDataObject[NAME_KEY].isString()) { + return QString(); + } + + return metaDataObject[NAME_KEY].toString(); +} + +QString getPluginIIDFromMetaData(QJsonObject object) { + static const char* IID_KEY = "IID"; + + if (!object.contains(IID_KEY) || !object[IID_KEY].isString()) { + return QString(); + } + + return object[IID_KEY].toString(); +} + +QStringList disabledDisplays; +QStringList disabledInputs; + +bool isDisabled(QJsonObject metaData) { + auto name = getPluginNameFromMetaData(metaData); + auto iid = getPluginIIDFromMetaData(metaData); + + if (iid == DisplayProvider_iid) { + return disabledDisplays.contains(name); + } else if (iid == InputProvider_iid) { + return disabledInputs.contains(name); + } + + return false; +} + using Loader = QSharedPointer; using LoaderList = QList; @@ -43,11 +86,21 @@ const LoaderList& getLoadedPlugins() { qDebug() << "Loading runtime plugins from " << pluginPath; auto candidates = pluginDir.entryList(); for (auto plugin : candidates) { - qDebug() << "Attempting plugins " << plugin; + qDebug() << "Attempting plugin" << qPrintable(plugin); QSharedPointer loader(new QPluginLoader(pluginPath + plugin)); + + if (isDisabled(loader->metaData())) { + qWarning() << "Plugin" << qPrintable(plugin) << "is disabled"; + // Skip this one, it's disabled + continue; + } + if (loader->load()) { - qDebug() << "Plugins " << plugin << " success"; + qDebug() << "Plugin" << qPrintable(plugin) << "loaded successfully"; loadedPlugins.push_back(loader); + } else { + qDebug() << "Plugin" << qPrintable(plugin) << "failed to load:"; + qDebug() << " " << qPrintable(loader->errorString()); } } } @@ -124,6 +177,15 @@ const InputPluginList& PluginManager::getInputPlugins() { return inputPlugins; } + +void PluginManager::disableDisplays(const QStringList& displays) { + disabledDisplays << displays; +} + +void PluginManager::disableInputs(const QStringList& inputs) { + disabledInputs << inputs; +} + void PluginManager::saveSettings() { saveInputPluginSettings(getInputPlugins()); } diff --git a/libraries/plugins/src/plugins/PluginManager.h b/libraries/plugins/src/plugins/PluginManager.h index cf0b8efe64..351087dce8 100644 --- a/libraries/plugins/src/plugins/PluginManager.h +++ b/libraries/plugins/src/plugins/PluginManager.h @@ -13,11 +13,14 @@ class PluginManager : public QObject { public: - static PluginManager* getInstance(); - PluginManager(); + static PluginManager* getInstance(); + PluginManager(); - const DisplayPluginList& getDisplayPlugins(); - void disableDisplayPlugin(const QString& name); - const InputPluginList& getInputPlugins(); - void saveSettings(); + const DisplayPluginList& getDisplayPlugins(); + const InputPluginList& getInputPlugins(); + + void disableDisplayPlugin(const QString& name); + void disableDisplays(const QStringList& displays); + void disableInputs(const QStringList& inputs); + void saveSettings(); }; From 932838b1e377efc97d4d965de63b3fd1388b9ca5 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 1 Jun 2016 22:16:16 -0700 Subject: [PATCH 10/31] Setup preferred display plugin --- interface/src/Application.cpp | 14 ++++++++--- .../plugins/src/plugins/PluginManager.cpp | 24 +++++++++++++++++++ libraries/plugins/src/plugins/PluginManager.h | 3 +++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 62f3a3a9c5..9463b41404 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2957,6 +2957,13 @@ void Application::loadSettings() { //DependencyManager::get()->setAutomaticLODAdjust(false); Menu::getInstance()->loadSettings(); + + // If there is a preferred plugin, we probably messed it up with the menu settings, so fix it. + if (auto plugin = PluginManager::getInstance()->getPreferredDisplayPlugin()) { + Q_ASSERT(plugin == getActiveDisplayPlugin()); + Menu::getInstance()->setIsOptionChecked(plugin->getName(), true); + } + getMyAvatar()->loadData(); _settingsLoaded = true; @@ -4938,7 +4945,7 @@ void Application::postLambdaEvent(std::function f) { } void Application::initPlugins(const QStringList& arguments) { - QCommandLineOption display("display", "Default display", "display"); + QCommandLineOption display("display", "Preferred display", "display"); QCommandLineOption disableDisplays("disable-displays", "Displays to disable", "display"); QCommandLineOption disableInputs("disable-inputs", "Inputs to disable", "input"); @@ -4949,8 +4956,9 @@ void Application::initPlugins(const QStringList& arguments) { parser.parse(arguments); if (parser.isSet(display)) { - auto defaultDisplay = parser.value(display); - qInfo() << "Setting prefered display plugin:" << defaultDisplay; + auto preferredDisplay = parser.value(display); + qInfo() << "Setting prefered display plugin:" << preferredDisplay; + PluginManager::getInstance()->setPreferredDisplayPlugin(preferredDisplay); } if (parser.isSet(disableDisplays)) { diff --git a/libraries/plugins/src/plugins/PluginManager.cpp b/libraries/plugins/src/plugins/PluginManager.cpp index 9047b1c271..0c9b58cffa 100644 --- a/libraries/plugins/src/plugins/PluginManager.cpp +++ b/libraries/plugins/src/plugins/PluginManager.cpp @@ -52,6 +52,7 @@ QString getPluginIIDFromMetaData(QJsonObject object) { return object[IID_KEY].toString(); } +QString preferredDisplayPluginName; QStringList disabledDisplays; QStringList disabledInputs; @@ -177,6 +178,29 @@ const InputPluginList& PluginManager::getInputPlugins() { return inputPlugins; } +void PluginManager::setPreferredDisplayPlugin(const QString& display) { + preferredDisplayPluginName = display; +} + +DisplayPluginPointer PluginManager::getPreferredDisplayPlugin() { + static DisplayPluginPointer displayPlugin; + + static std::once_flag once; + std::call_once(once, [&] { + // Grab the built in plugins + auto plugins = getDisplayPlugins(); + + auto it = std::find_if(plugins.begin(), plugins.end(), [](DisplayPluginPointer plugin) { + return plugin->getName() == preferredDisplayPluginName; + }); + if (it != plugins.end()) { + displayPlugin = *it; + } + }); + + return displayPlugin; +} + void PluginManager::disableDisplays(const QStringList& displays) { disabledDisplays << displays; diff --git a/libraries/plugins/src/plugins/PluginManager.h b/libraries/plugins/src/plugins/PluginManager.h index 351087dce8..d44ca2c28e 100644 --- a/libraries/plugins/src/plugins/PluginManager.h +++ b/libraries/plugins/src/plugins/PluginManager.h @@ -19,6 +19,9 @@ public: const DisplayPluginList& getDisplayPlugins(); const InputPluginList& getInputPlugins(); + DisplayPluginPointer getPreferredDisplayPlugin(); + + void setPreferredDisplayPlugin(const QString& display); void disableDisplayPlugin(const QString& name); void disableDisplays(const QStringList& displays); void disableInputs(const QStringList& inputs); From 992fa639326ea4b74d3c554a6104b9b28c9bcef4 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 2 Jun 2016 14:37:35 -0700 Subject: [PATCH 11/31] Allow ordered list of preferred plugins --- interface/src/Application.cpp | 24 ++++++++++++------- .../plugins/src/plugins/PluginManager.cpp | 24 ++++++++++--------- libraries/plugins/src/plugins/PluginManager.h | 4 ++-- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9463b41404..52d9fdf64a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2959,9 +2959,15 @@ void Application::loadSettings() { Menu::getInstance()->loadSettings(); // If there is a preferred plugin, we probably messed it up with the menu settings, so fix it. - if (auto plugin = PluginManager::getInstance()->getPreferredDisplayPlugin()) { - Q_ASSERT(plugin == getActiveDisplayPlugin()); - Menu::getInstance()->setIsOptionChecked(plugin->getName(), true); + auto plugins = PluginManager::getInstance()->getPreferredDisplayPlugins(); + for (auto plugin : plugins) { + auto menu = Menu::getInstance(); + if (auto action = menu->getActionForOption(plugin->getName())) { + action->setChecked(true); + action->trigger(); + // Find and activat5ed highest priority plugin, bail for the rest + break; + } } getMyAvatar()->loadData(); @@ -4945,9 +4951,9 @@ void Application::postLambdaEvent(std::function f) { } void Application::initPlugins(const QStringList& arguments) { - QCommandLineOption display("display", "Preferred display", "display"); - QCommandLineOption disableDisplays("disable-displays", "Displays to disable", "display"); - QCommandLineOption disableInputs("disable-inputs", "Inputs to disable", "input"); + QCommandLineOption display("display", "Preferred displays", "displays"); + QCommandLineOption disableDisplays("disable-displays", "Displays to disable", "displays"); + QCommandLineOption disableInputs("disable-inputs", "Inputs to disable", "inputs"); QCommandLineParser parser; parser.addOption(display); @@ -4956,9 +4962,9 @@ void Application::initPlugins(const QStringList& arguments) { parser.parse(arguments); if (parser.isSet(display)) { - auto preferredDisplay = parser.value(display); - qInfo() << "Setting prefered display plugin:" << preferredDisplay; - PluginManager::getInstance()->setPreferredDisplayPlugin(preferredDisplay); + auto preferredDisplays = parser.value(display).split(',', QString::SkipEmptyParts); + qInfo() << "Setting prefered display plugins:" << preferredDisplays; + PluginManager::getInstance()->setPreferredDisplayPlugins(preferredDisplays); } if (parser.isSet(disableDisplays)) { diff --git a/libraries/plugins/src/plugins/PluginManager.cpp b/libraries/plugins/src/plugins/PluginManager.cpp index 0c9b58cffa..ee5fb509b2 100644 --- a/libraries/plugins/src/plugins/PluginManager.cpp +++ b/libraries/plugins/src/plugins/PluginManager.cpp @@ -52,7 +52,7 @@ QString getPluginIIDFromMetaData(QJsonObject object) { return object[IID_KEY].toString(); } -QString preferredDisplayPluginName; +QStringList preferredDisplayPlugins; QStringList disabledDisplays; QStringList disabledInputs; @@ -178,27 +178,29 @@ const InputPluginList& PluginManager::getInputPlugins() { return inputPlugins; } -void PluginManager::setPreferredDisplayPlugin(const QString& display) { - preferredDisplayPluginName = display; +void PluginManager::setPreferredDisplayPlugins(const QStringList& displays) { + preferredDisplayPlugins = displays; } -DisplayPluginPointer PluginManager::getPreferredDisplayPlugin() { - static DisplayPluginPointer displayPlugin; +DisplayPluginList PluginManager::getPreferredDisplayPlugins() { + static DisplayPluginList displayPlugins; static std::once_flag once; std::call_once(once, [&] { // Grab the built in plugins auto plugins = getDisplayPlugins(); - auto it = std::find_if(plugins.begin(), plugins.end(), [](DisplayPluginPointer plugin) { - return plugin->getName() == preferredDisplayPluginName; - }); - if (it != plugins.end()) { - displayPlugin = *it; + for (auto pluginName : preferredDisplayPlugins) { + auto it = std::find_if(plugins.begin(), plugins.end(), [&](DisplayPluginPointer plugin) { + return plugin->getName() == pluginName; + }); + if (it != plugins.end()) { + displayPlugins.push_back(*it); + } } }); - return displayPlugin; + return displayPlugins; } diff --git a/libraries/plugins/src/plugins/PluginManager.h b/libraries/plugins/src/plugins/PluginManager.h index d44ca2c28e..2a94e6490b 100644 --- a/libraries/plugins/src/plugins/PluginManager.h +++ b/libraries/plugins/src/plugins/PluginManager.h @@ -19,9 +19,9 @@ public: const DisplayPluginList& getDisplayPlugins(); const InputPluginList& getInputPlugins(); - DisplayPluginPointer getPreferredDisplayPlugin(); + DisplayPluginList getPreferredDisplayPlugins(); + void setPreferredDisplayPlugins(const QStringList& displays); - void setPreferredDisplayPlugin(const QString& display); void disableDisplayPlugin(const QString& name); void disableDisplays(const QStringList& displays); void disableInputs(const QStringList& inputs); From ee62a211ac230c93b12047b4e29b5ab75836a8c8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 2 Jun 2016 15:36:11 -0700 Subject: [PATCH 12/31] Remove "Input Devices" menu --- interface/src/Application.cpp | 76 ----------------------------------- interface/src/Application.h | 1 - interface/src/Menu.cpp | 6 --- interface/src/Menu.h | 1 - 4 files changed, 84 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 52d9fdf64a..d41c971896 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1477,7 +1477,6 @@ void Application::initializeUi() { } } _window->setMenuBar(new Menu()); - updateInputModes(); auto compositorHelper = DependencyManager::get(); connect(compositorHelper.data(), &CompositorHelper::allowMouseCaptureChanged, [=] { @@ -5247,81 +5246,6 @@ void Application::updateDisplayMode() { Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin"); } -static void addInputPluginToMenu(InputPluginPointer inputPlugin) { - auto menu = Menu::getInstance(); - QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName(); - Q_ASSERT(!menu->menuItemExists(MenuOption::InputMenu, name)); - - static QActionGroup* inputPluginGroup = nullptr; - if (!inputPluginGroup) { - inputPluginGroup = new QActionGroup(menu); - inputPluginGroup->setExclusive(false); - } - - auto parent = menu->getMenu(MenuOption::InputMenu); - auto action = menu->addCheckableActionToQMenuAndActionHash(parent, - name, 0, true, qApp, - SLOT(updateInputModes())); - - inputPluginGroup->addAction(action); - Q_ASSERT(menu->menuItemExists(MenuOption::InputMenu, name)); -} - - -void Application::updateInputModes() { - auto menu = Menu::getInstance(); - auto inputPlugins = PluginManager::getInstance()->getInputPlugins(); - static std::once_flag once; - std::call_once(once, [&] { - foreach(auto inputPlugin, inputPlugins) { - addInputPluginToMenu(inputPlugin); - } - }); - auto offscreenUi = DependencyManager::get(); - - InputPluginList newInputPlugins; - InputPluginList removedInputPlugins; - foreach(auto inputPlugin, inputPlugins) { - QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName(); - QAction* action = menu->getActionForOption(name); - - auto it = std::find(std::begin(_activeInputPlugins), std::end(_activeInputPlugins), inputPlugin); - if (action->isChecked() && it == std::end(_activeInputPlugins)) { - _activeInputPlugins.push_back(inputPlugin); - newInputPlugins.push_back(inputPlugin); - } else if (!action->isChecked() && it != std::end(_activeInputPlugins)) { - _activeInputPlugins.erase(it); - removedInputPlugins.push_back(inputPlugin); - } - } - - // A plugin was checked - if (newInputPlugins.size() > 0) { - foreach(auto newInputPlugin, newInputPlugins) { - newInputPlugin->activate(); - //newInputPlugin->installEventFilter(qApp); - //newInputPlugin->installEventFilter(offscreenUi.data()); - } - } - if (removedInputPlugins.size() > 0) { // A plugin was unchecked - foreach(auto removedInputPlugin, removedInputPlugins) { - removedInputPlugin->deactivate(); - //removedInputPlugin->removeEventFilter(qApp); - //removedInputPlugin->removeEventFilter(offscreenUi.data()); - } - } - - //if (newInputPlugins.size() > 0 || removedInputPlugins.size() > 0) { - // if (!_currentInputPluginActions.isEmpty()) { - // auto menu = Menu::getInstance(); - // foreach(auto itemInfo, _currentInputPluginActions) { - // menu->removeMenuItem(itemInfo.first, itemInfo.second); - // } - // _currentInputPluginActions.clear(); - // } - //} -} - mat4 Application::getEyeProjection(int eye) const { QMutexLocker viewLocker(&_viewMutex); if (isHMDMode()) { diff --git a/interface/src/Application.h b/interface/src/Application.h index ed7b582bfc..f93434f581 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -327,7 +327,6 @@ private slots: void nodeKilled(SharedNodePointer node); static void packetSent(quint64 length); void updateDisplayMode(); - void updateInputModes(); void domainConnectionRefused(const QString& reasonMessage, int reason); private: diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index a21aa71753..031564fa7a 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -403,12 +403,6 @@ Menu::Menu() { // Developer > Avatar >>> MenuWrapper* avatarDebugMenu = developerMenu->addMenu("Avatar"); - // Settings > Input Devices - MenuWrapper* inputModeMenu = addMenu(MenuOption::InputMenu, "Advanced"); - QActionGroup* inputModeGroup = new QActionGroup(inputModeMenu); - inputModeGroup->setExclusive(false); - - // Developer > Avatar > Face Tracking MenuWrapper* faceTrackingMenu = avatarDebugMenu->addMenu("Face Tracking"); { diff --git a/interface/src/Menu.h b/interface/src/Menu.h index fcaf8e6caa..8081e27eb8 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -113,7 +113,6 @@ namespace MenuOption { const QString Help = "Help..."; const QString IncreaseAvatarSize = "Increase Avatar Size"; const QString IndependentMode = "Independent Mode"; - const QString InputMenu = "Developer>Avatar>Input Devices"; const QString ActionMotorControl = "Enable Default Motor Control"; const QString LeapMotionOnHMD = "Leap Motion on HMD"; const QString LoadScript = "Open and Run Script File..."; From b635e32933835c497b98eefbff3e0bb3243be5fc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 2 Jun 2016 17:44:39 -0700 Subject: [PATCH 13/31] Rename Mac only Oculus display plugin --- plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp | 2 +- plugins/oculusLegacy/src/oculus.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp index f89e71b829..8e044fbc16 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp @@ -31,7 +31,7 @@ using namespace oglplus; -const QString OculusLegacyDisplayPlugin::NAME("Oculus Rift (0.5) (Legacy)"); +const QString OculusLegacyDisplayPlugin::NAME("Oculus Rift"); OculusLegacyDisplayPlugin::OculusLegacyDisplayPlugin() { } diff --git a/plugins/oculusLegacy/src/oculus.json b/plugins/oculusLegacy/src/oculus.json index 4cd9a136b3..86546c8dd5 100644 --- a/plugins/oculusLegacy/src/oculus.json +++ b/plugins/oculusLegacy/src/oculus.json @@ -1 +1 @@ -{"name":"Oculus Rift (0.5) (Legacy)"} +{"name":"Oculus Rift"} From 6f75fab2980958d78718f090f356864d91341933 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 2 Jun 2016 18:02:30 -0700 Subject: [PATCH 14/31] Revert header changes --- interface/src/main.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 6866d5637c..8fc0384aee 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -8,8 +8,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include - #include #include #include @@ -19,12 +17,6 @@ #include #include -#ifdef HAS_BUGSPLAT -#include -#include -#include -#endif - #include #include @@ -33,7 +25,13 @@ #include "InterfaceLogging.h" #include "UserActivityLogger.h" #include "MainWindow.h" +#include +#ifdef HAS_BUGSPLAT +#include +#include +#include +#endif int main(int argc, const char* argv[]) { #if HAS_BUGSPLAT From 24bbb8db3f663f73b8659a3a317bc24fcfa84c94 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 3 Jun 2016 11:51:35 -0700 Subject: [PATCH 15/31] Remove input plugin menu dependency --- interface/src/Application.cpp | 33 ++++++++----------- .../src/input-plugins/InputPlugin.cpp | 1 - .../plugins/src/plugins/PluginManager.cpp | 5 ++- 3 files changed, 17 insertions(+), 22 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d41c971896..6dcb64a07d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -198,7 +198,6 @@ static const float PHYSICS_READY_RANGE = 3.0f; // how far from avatar to check f static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); -static const QString INPUT_DEVICE_MENU_PREFIX = "Device: "; Setting::Handle maxOctreePacketsPerSecond("maxOctreePPS", DEFAULT_MAX_OCTREE_PPS); const QHash Application::_acceptedExtensions { @@ -1000,7 +999,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : RenderableWebEntityItem* webEntity = dynamic_cast(entity.get()); if (webEntity) { webEntity->setProxyWindow(_window->windowHandle()); - if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { + if (_keyboardMouseDevice->isActive()) { _keyboardMouseDevice->pluginFocusOutEvent(); } _keyboardFocusedItem = entityItemID; @@ -1153,9 +1152,7 @@ void Application::aboutToQuit() { emit beforeAboutToQuit(); foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) { - QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName(); - QAction* action = Menu::getInstance()->getActionForOption(name); - if (action->isChecked()) { + if (inputPlugin->isActive()) { inputPlugin->deactivate(); } } @@ -2024,7 +2021,7 @@ void Application::keyPressEvent(QKeyEvent* event) { } if (hasFocus()) { - if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { + if (_keyboardMouseDevice->isActive()) { _keyboardMouseDevice->keyPressEvent(event); } @@ -2358,7 +2355,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) { return; } - if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { + if (_keyboardMouseDevice->isActive()) { _keyboardMouseDevice->keyReleaseEvent(event); } @@ -2390,9 +2387,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) { void Application::focusOutEvent(QFocusEvent* event) { auto inputPlugins = PluginManager::getInstance()->getInputPlugins(); foreach(auto inputPlugin, inputPlugins) { - QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName(); - QAction* action = Menu::getInstance()->getActionForOption(name); - if (action && action->isChecked()) { + if (inputPlugin->isActive()) { inputPlugin->pluginFocusOutEvent(); } } @@ -2477,7 +2472,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) { return; } - if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { + if (_keyboardMouseDevice->isActive()) { _keyboardMouseDevice->mouseMoveEvent(event); } @@ -2514,7 +2509,7 @@ void Application::mousePressEvent(QMouseEvent* event) { if (hasFocus()) { - if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { + if (_keyboardMouseDevice->isActive()) { _keyboardMouseDevice->mousePressEvent(event); } @@ -2559,7 +2554,7 @@ void Application::mouseReleaseEvent(QMouseEvent* event) { } if (hasFocus()) { - if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { + if (_keyboardMouseDevice->isActive()) { _keyboardMouseDevice->mouseReleaseEvent(event); } @@ -2586,7 +2581,7 @@ void Application::touchUpdateEvent(QTouchEvent* event) { return; } - if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { + if (_keyboardMouseDevice->isActive()) { _keyboardMouseDevice->touchUpdateEvent(event); } } @@ -2604,7 +2599,7 @@ void Application::touchBeginEvent(QTouchEvent* event) { return; } - if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { + if (_keyboardMouseDevice->isActive()) { _keyboardMouseDevice->touchBeginEvent(event); } @@ -2621,7 +2616,7 @@ void Application::touchEndEvent(QTouchEvent* event) { return; } - if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { + if (_keyboardMouseDevice->isActive()) { _keyboardMouseDevice->touchEndEvent(event); } @@ -2637,7 +2632,7 @@ void Application::wheelEvent(QWheelEvent* event) const { return; } - if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) { + if (_keyboardMouseDevice->isActive()) { _keyboardMouseDevice->wheelEvent(event); } } @@ -2770,9 +2765,7 @@ void Application::idle(float nsecsElapsed) { getActiveDisplayPlugin()->idle(); auto inputPlugins = PluginManager::getInstance()->getInputPlugins(); foreach(auto inputPlugin, inputPlugins) { - QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName(); - QAction* action = Menu::getInstance()->getActionForOption(name); - if (action && action->isChecked()) { + if (inputPlugin->isActive()) { inputPlugin->idle(); } } diff --git a/libraries/input-plugins/src/input-plugins/InputPlugin.cpp b/libraries/input-plugins/src/input-plugins/InputPlugin.cpp index 4d59adb602..32c28af2ef 100644 --- a/libraries/input-plugins/src/input-plugins/InputPlugin.cpp +++ b/libraries/input-plugins/src/input-plugins/InputPlugin.cpp @@ -25,7 +25,6 @@ InputPluginList getInputPlugins() { for (int i = 0; PLUGIN_POOL[i]; ++i) { InputPlugin* plugin = PLUGIN_POOL[i]; if (plugin->isSupported()) { - plugin->init(); result.push_back(InputPluginPointer(plugin)); } } diff --git a/libraries/plugins/src/plugins/PluginManager.cpp b/libraries/plugins/src/plugins/PluginManager.cpp index ee5fb509b2..6bff5a36f3 100644 --- a/libraries/plugins/src/plugins/PluginManager.cpp +++ b/libraries/plugins/src/plugins/PluginManager.cpp @@ -164,7 +164,9 @@ const InputPluginList& PluginManager::getInputPlugins() { InputProvider* inputProvider = qobject_cast(loader->instance()); if (inputProvider) { for (auto inputPlugin : inputProvider->getInputPlugins()) { - inputPlugins.push_back(inputPlugin); + if (inputPlugin->isSupported()) { + inputPlugins.push_back(inputPlugin); + } } } } @@ -173,6 +175,7 @@ const InputPluginList& PluginManager::getInputPlugins() { for (auto plugin : inputPlugins) { plugin->setContainer(&container); plugin->init(); + plugin->activate(); } }); return inputPlugins; From 26acc6fd8b8b99e02a01e34f39c38ab4261f0228 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 3 Jun 2016 12:45:27 -0700 Subject: [PATCH 16/31] Typo --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6dcb64a07d..ed212dade5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2957,7 +2957,7 @@ void Application::loadSettings() { if (auto action = menu->getActionForOption(plugin->getName())) { action->setChecked(true); action->trigger(); - // Find and activat5ed highest priority plugin, bail for the rest + // Find and activated highest priority plugin, bail for the rest break; } } From 399517fcbd54ab7a6c6825bd9360528421b32023 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 6 Jun 2016 13:27:58 -0700 Subject: [PATCH 17/31] Activate Inputs after menus are setup --- interface/src/Application.cpp | 10 +++++++++- libraries/plugins/src/plugins/PluginManager.cpp | 1 - 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ed212dade5..68e916c29e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2951,7 +2951,8 @@ void Application::loadSettings() { Menu::getInstance()->loadSettings(); // If there is a preferred plugin, we probably messed it up with the menu settings, so fix it. - auto plugins = PluginManager::getInstance()->getPreferredDisplayPlugins(); + auto pluginManager = PluginManager::getInstance(); + auto plugins = pluginManager->getPreferredDisplayPlugins(); for (auto plugin : plugins) { auto menu = Menu::getInstance(); if (auto action = menu->getActionForOption(plugin->getName())) { @@ -2962,6 +2963,13 @@ void Application::loadSettings() { } } + auto inputs = pluginManager->getInputPlugins(); + for (auto plugin : inputs) { + if (!plugin->isActive()) { + plugin->activate(); + } + } + getMyAvatar()->loadData(); _settingsLoaded = true; diff --git a/libraries/plugins/src/plugins/PluginManager.cpp b/libraries/plugins/src/plugins/PluginManager.cpp index 6bff5a36f3..7161132c5e 100644 --- a/libraries/plugins/src/plugins/PluginManager.cpp +++ b/libraries/plugins/src/plugins/PluginManager.cpp @@ -175,7 +175,6 @@ const InputPluginList& PluginManager::getInputPlugins() { for (auto plugin : inputPlugins) { plugin->setContainer(&container); plugin->init(); - plugin->activate(); } }); return inputPlugins; From c9f440a49ddc59b357b807af6e81addd1255196a Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 1 Jun 2016 09:53:06 -0700 Subject: [PATCH 18/31] handControllerGrab: initial rendering of equip hot-spots * When trigger is depressed, any entities that are marked with a wearable equip-point will become highlighted by a wireframe box (temporary art). * The grab state machine is now defined by the CONTROLLER_STATE_MACHINE object. this includes each state's name and updateMethod name. * Support was added for entry and exit methods when changing states, this functionality is used to draw and delete the hot spots when entering and exiting the searching state. --- .../system/controllers/handControllerGrab.js | 280 +++++++++++------- 1 file changed, 181 insertions(+), 99 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index be4bffe58c..0561e73e1f 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -92,6 +92,7 @@ var EQUIP_SPRING_TIMEFRAME = 0.4; // how quickly objects move to their new posit // other constants // +var HOTSPOT_DRAW_DISTANCE = 10; var RIGHT_HAND = 1; var LEFT_HAND = 0; @@ -179,47 +180,85 @@ var COLLIDES_WITH_WHILE_MULTI_GRABBED = "dynamic"; var HEART_BEAT_INTERVAL = 5 * MSECS_PER_SEC; var HEART_BEAT_TIMEOUT = 15 * MSECS_PER_SEC; -function stateToName(state) { - switch (state) { - case STATE_OFF: - return "off"; - case STATE_SEARCHING: - return "searching"; - case STATE_HOLD_SEARCHING: - return "hold_searching"; - case STATE_DISTANCE_HOLDING: - return "distance_holding"; - case STATE_CONTINUE_DISTANCE_HOLDING: - return "continue_distance_holding"; - case STATE_NEAR_GRABBING: - return "near_grabbing"; - case STATE_CONTINUE_NEAR_GRABBING: - return "continue_near_grabbing"; - case STATE_NEAR_TRIGGER: - return "near_trigger"; - case STATE_CONTINUE_NEAR_TRIGGER: - return "continue_near_trigger"; - case STATE_FAR_TRIGGER: - return "far_trigger"; - case STATE_CONTINUE_FAR_TRIGGER: - return "continue_far_trigger"; - case STATE_RELEASE: - return "release"; - case STATE_EQUIP: - return "equip"; - case STATE_HOLD: - return "hold"; - case STATE_CONTINUE_HOLD: - return "continue_hold"; - case STATE_CONTINUE_EQUIP: - return "continue_equip"; - case STATE_WAITING_FOR_EQUIP_THUMB_RELEASE: - return "waiting_for_equip_thumb_release"; - case STATE_WAITING_FOR_RELEASE_THUMB_RELEASE: - return "waiting_for_release_thumb_release"; - } +var CONTROLLER_STATE_MACHINE = {}; - return "unknown"; +CONTROLLER_STATE_MACHINE[STATE_OFF] = { + name: "off", + updateMethod: "off" +}; +CONTROLLER_STATE_MACHINE[STATE_SEARCHING] = { + name: "searching", + updateMethod: "search", + enterMethod: "searchEnter", + exitMethod: "searchExit" +}; +CONTROLLER_STATE_MACHINE[STATE_HOLD_SEARCHING] = { + name: "hold_searching", + updateMethod: "search" +}; +CONTROLLER_STATE_MACHINE[STATE_DISTANCE_HOLDING] = { + name: "distance_holding", + updateMethod: "distanceHolding" +}; +CONTROLLER_STATE_MACHINE[STATE_CONTINUE_DISTANCE_HOLDING] = { + name: "continue_distance_holding", + updateMethod: "continueDistanceHolding" +}; +CONTROLLER_STATE_MACHINE[STATE_NEAR_GRABBING] = { + name: "near_grabbing", + updateMethod: "nearGrabbing" +}; +CONTROLLER_STATE_MACHINE[STATE_EQUIP] = { + name: "equip", + updateMethod: "nearGrabbing" +}; +CONTROLLER_STATE_MACHINE[STATE_HOLD] = { + name: "hold", + updateMethod: "nearGrabbing" +}; +CONTROLLER_STATE_MACHINE[STATE_CONTINUE_NEAR_GRABBING] = { + name: "continue_near_grabbing", + updateMethod: "continueNearGrabbing" +}; +CONTROLLER_STATE_MACHINE[STATE_CONTINUE_HOLD] = { + name: "continue_hold", + updateMethod: "continueNearGrabbing" +}; +CONTROLLER_STATE_MACHINE[STATE_CONTINUE_EQUIP] = { + name: "continue_equip", + updateMethod: "continueNearGrabbing" +}; +CONTROLLER_STATE_MACHINE[STATE_NEAR_TRIGGER] = { + name: "near_trigger", + updateMethod: "nearTrigger" +}; +CONTROLLER_STATE_MACHINE[STATE_CONTINUE_NEAR_TRIGGER] = { + name: "continue_near_trigger", + updateMethod: "continueNearTrigger" +}; +CONTROLLER_STATE_MACHINE[STATE_FAR_TRIGGER] = { + name: "far_trigger", + updateMethod: "farTrigger" +}; +CONTROLLER_STATE_MACHINE[STATE_CONTINUE_FAR_TRIGGER] = { + name: "continue_far_trigger", + updateMethod: "continueFarTrigger" +}; +CONTROLLER_STATE_MACHINE[STATE_RELEASE] = { + name: "release", + updateMethod: "release" +}; +CONTROLLER_STATE_MACHINE[STATE_WAITING_FOR_EQUIP_THUMB_RELEASE] = { + name: "waiting_for_equip_thumb_release", + updateMethod: "waitingForEquipThumbRelease" +}; +CONTROLLER_STATE_MACHINE[STATE_WAITING_FOR_RELEASE_THUMB_RELEASE] = { + name: "waiting_for_release_thumb_release", + updateMethod: "waitingForReleaseThumbRelease" +}; + +function stateToName(state) { + return CONTROLLER_STATE_MACHINE[state] ? CONTROLLER_STATE_MACHINE[state].name : "???"; } function getTag() { @@ -249,6 +288,14 @@ function entityIsGrabbedByOther(entityID) { return false; } +function propsArePhysical(props) { + if (!props.dynamic) { + return false; + } + var isPhysical = (props.shapeType && props.shapeType != 'none'); + return isPhysical; +} + // If another script is managing the reticle (as is done by HandControllerPointer), we should not be setting it here, // and we should not be showing lasers when someone else is using the Reticle to indicate a 2D minor mode. var EXTERNALLY_MANAGED_2D_MINOR_MODE = true; @@ -314,55 +361,22 @@ function MyController(hand) { this.update = function() { this.updateSmoothedTrigger(); + if (isIn2DMode()) { _this.turnOffVisualizations(); return; } - switch (this.state) { - case STATE_OFF: - this.off(); - break; - case STATE_SEARCHING: - case STATE_HOLD_SEARCHING: - this.search(); - break; - case STATE_DISTANCE_HOLDING: - this.distanceHolding(); - break; - case STATE_CONTINUE_DISTANCE_HOLDING: - this.continueDistanceHolding(); - break; - case STATE_NEAR_GRABBING: - case STATE_EQUIP: - case STATE_HOLD: - this.nearGrabbing(); - break; - case STATE_WAITING_FOR_EQUIP_THUMB_RELEASE: - this.waitingForEquipThumbRelease(); - break; - case STATE_WAITING_FOR_RELEASE_THUMB_RELEASE: - this.waitingForReleaseThumbRelease(); - break; - case STATE_CONTINUE_NEAR_GRABBING: - case STATE_CONTINUE_HOLD: - case STATE_CONTINUE_EQUIP: - this.continueNearGrabbing(); - break; - case STATE_NEAR_TRIGGER: - this.nearTrigger(); - break; - case STATE_CONTINUE_NEAR_TRIGGER: - this.continueNearTrigger(); - break; - case STATE_FAR_TRIGGER: - this.farTrigger(); - break; - case STATE_CONTINUE_FAR_TRIGGER: - this.continueFarTrigger(); - break; - case STATE_RELEASE: - this.release(); - break; + + if (CONTROLLER_STATE_MACHINE[this.state]) { + var updateMethodName = CONTROLLER_STATE_MACHINE[this.state].updateMethod; + var updateMethod = this[updateMethodName]; + if (updateMethod) { + updateMethod.call(this); + } else { + print("WARNING: could not find updateMethod for state " + stateToName(this.state)); + } + } else { + print("WARNING: could not find state " + this.state + " " + CONTROLLER_STATE_MACHINE[this.state]); } }; @@ -374,9 +388,33 @@ function MyController(hand) { this.setState = function(newState) { this.grabSphereOff(); if (WANT_DEBUG || WANT_DEBUG_STATE) { - print("STATE (" + this.hand + "): " + stateToName(this.state) + " --> " + - stateToName(newState) + ", hand: " + this.hand); + var oldStateName = stateToName(this.state); + var newStateName = stateToName(newState); + print("STATE (" + this.hand + "): " + oldStateName + " --> " + newStateName); } + + // exit the old state + if (CONTROLLER_STATE_MACHINE[this.state]) { + var exitMethodName = CONTROLLER_STATE_MACHINE[this.state].exitMethod; + var exitMethod = this[exitMethodName]; + if (exitMethod) { + exitMethod.call(this); + } + } else { + print("WARNING: could not find this.state " + this.state); + } + + // enter the new state + if (CONTROLLER_STATE_MACHINE[newState]) { + var enterMethodName = CONTROLLER_STATE_MACHINE[newState].enterMethod; + var enterMethod = this[enterMethodName]; + if (enterMethod) { + enterMethod.call(this); + } + } else { + print("WARNING: could not find newState " + newState); + } + this.state = newState; }; @@ -759,14 +797,6 @@ function MyController(hand) { } }; - this.propsArePhysical = function(props) { - if (!props.dynamic) { - return false; - } - var isPhysical = (props.shapeType && props.shapeType != 'none'); - return isPhysical; - } - this.turnOffVisualizations = function() { if (USE_ENTITY_LINES_FOR_SEARCHING === true || USE_ENTITY_LINES_FOR_MOVING === true) { this.lineOff(); @@ -852,6 +882,58 @@ function MyController(hand) { } }; + this.searchEnter = function() { + this.equipHotspotOverlays = []; + + // find entities near the avatar that might be equipable. + var entities = Entities.findEntities(MyAvatar.position, HOTSPOT_DRAW_DISTANCE); + var i, l = entities.length; + for (i = 0; i < l; i++) { + + // is this entity equipable? + var grabData = getEntityCustomData(GRABBABLE_DATA_KEY, entities[i], undefined); + var grabProps = Entities.getEntityProperties(entities[i], GRABBABLE_PROPERTIES); + if (grabData) { + + var hotspotPos = grabProps.position; + + // does this entity have an equip point? + var wearableData = getEntityCustomData("wearable", entities[i], undefined); + if (wearableData) { + var handJointName = this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"; + if (wearableData[handJointName]) { + // draw the hotspot around the equip point. + hotspotPos = wearableData[handJointName][0]; + } + } + + // draw a hotspot! + this.equipHotspotOverlays.push(Overlays.addOverlay("cube", { + position: hotspotPos, + size: 0.1, + color: { red: 90, green: 255, blue: 90 }, + alpha: 1, + solid: false, + visible: true, + dashed: false, + lineWidth: 2.0, + ignoreRayIntersection: true, // this never ray intersects + drawInFront: true + })); + } + } + }; + + this.searchExit = function() { + + // delete all equip hotspots + var i, l = this.equipHotspotOverlays.length; + for (i = 0; i < l; i++) { + Overlays.deleteOverlay(this.equipHotspotOverlays[i]); + } + this.equipHotspotOverlays = []; + }; + this.search = function() { this.grabbedEntity = null; this.isInitialGrab = false; @@ -951,7 +1033,7 @@ function MyController(hand) { var propsForCandidate = Entities.getEntityProperties(candidateEntities[i], GRABBABLE_PROPERTIES); var near = (nearPickedCandidateEntities.indexOf(candidateEntities[i]) >= 0); - var isPhysical = this.propsArePhysical(propsForCandidate); + var isPhysical = propsArePhysical(propsForCandidate); var grabbable; if (isPhysical) { // physical things default to grabbable @@ -1030,7 +1112,7 @@ function MyController(hand) { if ((this.grabbedEntity !== null) && (this.triggerSmoothedGrab() || this.bumperSqueezed())) { // We are squeezing enough to grab, and we've found an entity that we'll try to do something with. var near = (nearPickedCandidateEntities.indexOf(this.grabbedEntity) >= 0) || minDistance <= NEAR_PICK_MAX_DISTANCE; - var isPhysical = this.propsArePhysical(props); + var isPhysical = propsArePhysical(props); // near or far trigger if (grabbableData.wantsTrigger) { @@ -1462,7 +1544,7 @@ function MyController(hand) { } } - var isPhysical = this.propsArePhysical(grabbedProperties) || entityHasActions(this.grabbedEntity); + var isPhysical = propsArePhysical(grabbedProperties) || entityHasActions(this.grabbedEntity); if (isPhysical && this.state == STATE_NEAR_GRABBING) { // grab entity via action if (!this.setupHoldAction()) { @@ -1879,7 +1961,7 @@ function MyController(hand) { var forceVelocity = false; var doSetVelocity = false; - if (parentID != NULL_UUID && deactiveProps.parentID == NULL_UUID && this.propsArePhysical(props)) { + if (parentID != NULL_UUID && deactiveProps.parentID == NULL_UUID && propsArePhysical(props)) { // TODO: EntityScriptingInterface::convertLocationToScriptSemantics should be setting up // props.velocity to be a world-frame velocity and localVelocity to be vs parent. Until that // is done, we use a measured velocity here so that things held via a bumper-grab / parenting-grab From 6d462a477dd3620ddc81efb6355af7df6dd1522e Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 1 Jun 2016 16:54:14 -0700 Subject: [PATCH 19/31] Change equip-hotspot to a green sphere. --- .../system/controllers/handControllerGrab.js | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 0561e73e1f..4163b07c6d 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -897,28 +897,26 @@ function MyController(hand) { var hotspotPos = grabProps.position; - // does this entity have an equip point? + // does this entity have an attach point? var wearableData = getEntityCustomData("wearable", entities[i], undefined); if (wearableData) { var handJointName = this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"; if (wearableData[handJointName]) { - // draw the hotspot around the equip point. + // draw the hotspot around the attach point. hotspotPos = wearableData[handJointName][0]; } } // draw a hotspot! - this.equipHotspotOverlays.push(Overlays.addOverlay("cube", { + this.equipHotspotOverlays.push(Overlays.addOverlay("sphere", { position: hotspotPos, - size: 0.1, + size: 0.2, color: { red: 90, green: 255, blue: 90 }, - alpha: 1, - solid: false, + alpha: 0.7, + solid: true, visible: true, - dashed: false, - lineWidth: 2.0, - ignoreRayIntersection: true, // this never ray intersects - drawInFront: true + ignoreRayIntersection: false, + drawInFront: false })); } } From b836a580ffda8b2625e64ec404d3520cfcf13ed5 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 6 Jun 2016 14:39:14 -0700 Subject: [PATCH 20/31] Updated some debug print information --- scripts/system/controllers/handControllerGrab.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 4163b07c6d..8a96e9d80c 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -376,7 +376,7 @@ function MyController(hand) { print("WARNING: could not find updateMethod for state " + stateToName(this.state)); } } else { - print("WARNING: could not find state " + this.state + " " + CONTROLLER_STATE_MACHINE[this.state]); + print("WARNING: could not find state " + this.state + " in state machine"); } }; @@ -390,7 +390,7 @@ function MyController(hand) { if (WANT_DEBUG || WANT_DEBUG_STATE) { var oldStateName = stateToName(this.state); var newStateName = stateToName(newState); - print("STATE (" + this.hand + "): " + oldStateName + " --> " + newStateName); + print("STATE (" + this.hand + "): " + newStateName + " <-- " + oldStateName); } // exit the old state @@ -401,7 +401,7 @@ function MyController(hand) { exitMethod.call(this); } } else { - print("WARNING: could not find this.state " + this.state); + print("WARNING: could not find state " + this.state + " in state machine"); } // enter the new state @@ -412,7 +412,7 @@ function MyController(hand) { enterMethod.call(this); } } else { - print("WARNING: could not find newState " + newState); + print("WARNING: could not find newState " + newState + " in state machine"); } this.state = newState; @@ -943,6 +943,7 @@ function MyController(hand) { this.setState(STATE_RELEASE); return; } + if (this.state == STATE_HOLD_SEARCHING && this.bumperReleased()) { this.setState(STATE_RELEASE); return; From b6af46cac9ab316187eec143610dd333b4f43e7b Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 7 Jun 2016 11:30:07 +1200 Subject: [PATCH 21/31] Add "Load Defaults" button to Running Scripts dialog And rename "Stop All" to "Remove All". --- .../qml/hifi/dialogs/RunningScripts.qml | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/hifi/dialogs/RunningScripts.qml b/interface/resources/qml/hifi/dialogs/RunningScripts.qml index 31bb553809..cbbbec5bff 100644 --- a/interface/resources/qml/hifi/dialogs/RunningScripts.qml +++ b/interface/resources/qml/hifi/dialogs/RunningScripts.qml @@ -23,9 +23,9 @@ Window { title: "Running Scripts" resizable: true destroyOnInvisible: true - implicitWidth: 400 + implicitWidth: 424 implicitHeight: isHMD ? 695 : 728 - minSize: Qt.vector2d(200, 300) + minSize: Qt.vector2d(424, 300) HifiConstants { id: hifi } @@ -83,6 +83,11 @@ Window { scripts.reloadAllScripts(); } + function loadDefaults() { + console.log("Load default scripts"); + scripts.loadOneScript(scripts.defaultScriptsPath + "/defaultScripts.js"); + } + function stopAll() { console.log("Stop all scripts"); scripts.stopAllScripts(); @@ -101,13 +106,13 @@ Window { spacing: hifi.dimensions.contentSpacing.x HifiControls.Button { - text: "Reload all" + text: "Reload All" color: hifi.buttons.black onClicked: reloadAll() } HifiControls.Button { - text: "Stop all" + text: "Remove All" color: hifi.buttons.red onClicked: stopAll() } @@ -215,7 +220,6 @@ Window { Row { spacing: hifi.dimensions.contentSpacing.x - anchors.right: parent.right HifiControls.Button { text: "from URL" @@ -253,6 +257,12 @@ Window { onTriggered: ApplicationInterface.loadDialog(); } } + + HifiControls.Button { + text: "Load Defaults" + color: hifi.buttons.black + onClicked: loadDefaults() + } } HifiControls.VerticalSpacer {} From 509f889c0d33394b58e24ba416639e946081d9fb Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 6 Jun 2016 18:40:12 -0700 Subject: [PATCH 22/31] fixed constant turn of 22.5 degrees --- interface/resources/controllers/standard.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json index f25e0cc3c4..5c0ea09939 100644 --- a/interface/resources/controllers/standard.json +++ b/interface/resources/controllers/standard.json @@ -9,6 +9,8 @@ "to": "Actions.StepYaw", "filters": [ + { "type": "deadZone", "min": 0.15 }, + "constrainToInteger", { "type": "pulse", "interval": 0.5 }, { "type": "scale", "scale": 22.5 } ] From b9ee0c087e6f79b36850799bf476e80ab93c5938 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 7 Jun 2016 13:45:23 -0700 Subject: [PATCH 23/31] Add a constant hud toggle button to the UI --- interface/resources/icons/hud-01.svg | 105 ++++++++++++++++++++ interface/resources/qml/desktop/Desktop.qml | 2 +- interface/resources/qml/hifi/Desktop.qml | 21 ++++ tests/ui/qml/main.qml | 2 +- 4 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 interface/resources/icons/hud-01.svg diff --git a/interface/resources/icons/hud-01.svg b/interface/resources/icons/hud-01.svg new file mode 100644 index 0000000000..4929389268 --- /dev/null +++ b/interface/resources/icons/hud-01.svg @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interface/resources/qml/desktop/Desktop.qml b/interface/resources/qml/desktop/Desktop.qml index 241cd91611..e269a63cde 100644 --- a/interface/resources/qml/desktop/Desktop.qml +++ b/interface/resources/qml/desktop/Desktop.qml @@ -299,7 +299,7 @@ FocusScope { if (pinned) { // recalculate our non-pinned children hiddenChildren = d.findMatchingChildren(desktop, function(child){ - return !d.isTopLevelWindow(child) && child.visible; + return !d.isTopLevelWindow(child) && child.visible && !child.pinned; }); hiddenChildren.forEach(function(child){ diff --git a/interface/resources/qml/hifi/Desktop.qml b/interface/resources/qml/hifi/Desktop.qml index 59278a17b4..f1c1aeb4d1 100644 --- a/interface/resources/qml/hifi/Desktop.qml +++ b/interface/resources/qml/hifi/Desktop.qml @@ -47,6 +47,27 @@ Desktop { } } + Item { + id: hudToggleButton + clip: true + width: 50 + height: 50 + anchors.bottom: parent.bottom + anchors.bottomMargin: 32 + anchors.horizontalCenter: parent.horizontalCenter + property bool pinned: true + Image { + y: desktop.pinned ? -50 : 0 + id: hudToggleImage + source: "../../icons/hud-01.svg" + } + MouseArea { + anchors.fill: parent + onClicked: desktop.togglePinned() + } + } + + } diff --git a/tests/ui/qml/main.qml b/tests/ui/qml/main.qml index d752734de4..33408fb821 100644 --- a/tests/ui/qml/main.qml +++ b/tests/ui/qml/main.qml @@ -51,7 +51,7 @@ ApplicationWindow { Button { text: "toggle desktop" - onClicked: desktop.toggleVisible() + onClicked: desktop.togglePinned() } // Error alerts From ba61491ee605d44fd5c39babb134cf85f07e8331 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 7 Jun 2016 15:33:00 -0700 Subject: [PATCH 24/31] PR feedback --- interface/resources/qml/hifi/Desktop.qml | 22 +++--------- .../resources/qml/hifi/ToggleHudButton.qml | 36 +++++++++++++++++++ 2 files changed, 40 insertions(+), 18 deletions(-) create mode 100644 interface/resources/qml/hifi/ToggleHudButton.qml diff --git a/interface/resources/qml/hifi/Desktop.qml b/interface/resources/qml/hifi/Desktop.qml index f1c1aeb4d1..e127a235e6 100644 --- a/interface/resources/qml/hifi/Desktop.qml +++ b/interface/resources/qml/hifi/Desktop.qml @@ -4,11 +4,13 @@ import QtWebEngine 1.1; import "../desktop" import ".." +import "." Desktop { id: desktop MouseArea { + id: hoverWatch anchors.fill: parent hoverEnabled: true propagateComposedEvents: true @@ -47,28 +49,12 @@ Desktop { } } - Item { - id: hudToggleButton - clip: true - width: 50 - height: 50 + + ToggleHudButton { anchors.bottom: parent.bottom anchors.bottomMargin: 32 anchors.horizontalCenter: parent.horizontalCenter - property bool pinned: true - Image { - y: desktop.pinned ? -50 : 0 - id: hudToggleImage - source: "../../icons/hud-01.svg" - } - MouseArea { - anchors.fill: parent - onClicked: desktop.togglePinned() - } } - - } - diff --git a/interface/resources/qml/hifi/ToggleHudButton.qml b/interface/resources/qml/hifi/ToggleHudButton.qml new file mode 100644 index 0000000000..6454f42305 --- /dev/null +++ b/interface/resources/qml/hifi/ToggleHudButton.qml @@ -0,0 +1,36 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 + +import "../windows" + +Window { + //frame: HiddenFrame {} + hideBackground: true + resizable: false + destroyOnCloseButton: false + destroyOnHidden: false + closable: false + shown: true + pinned: true + width: 50 + height: 50 + clip: true + visible: true + + Item { + width: 50 + height: 50 + Image { + y: desktop.pinned ? -50 : 0 + id: hudToggleImage + source: "../../icons/hud-01.svg" + } + MouseArea { + readonly property string overlayMenuItem: "Overlays" + anchors.fill: parent + onClicked: MenuInterface.setIsOptionChecked(overlayMenuItem, !MenuInterface.isOptionChecked(overlayMenuItem)) + } + } +} + + From 29d9f51b584e205d62bf944af6400cf0beebc1a3 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 7 Jun 2016 16:46:17 -0700 Subject: [PATCH 25/31] Adding missed file --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8f4d80a86f..c0a7857c95 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1418,7 +1418,7 @@ void Application::initializeUi() { rootContext->setContextProperty("Overlays", &_overlays); rootContext->setContextProperty("Window", DependencyManager::get().data()); - rootContext->setContextProperty("Menu", MenuScriptingInterface::getInstance()); + rootContext->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance()); rootContext->setContextProperty("Stats", Stats::getInstance()); rootContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance()); rootContext->setContextProperty("ScriptDiscoveryService", DependencyManager::get().data()); From 71fb0e665ffbb92e18dc092934b62d3dba1298a5 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 7 Jun 2016 16:46:08 -0700 Subject: [PATCH 26/31] Fix OSX warning --- libraries/entities/src/EntityTreeElement.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 37a0f36d2f..a7baeb361b 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -55,7 +55,7 @@ void EntityTreeElement::debugExtraEncodeData(EncodeBitstreamParams& params) cons if (extraEncodeData->contains(this)) { EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData - = static_cast(extraEncodeData->value(this)); + = static_cast((*extraEncodeData)[this]); qCDebug(entities) << " encode data:" << entityTreeElementExtraEncodeData; } else { qCDebug(entities) << " encode data: MISSING!!"; @@ -97,7 +97,7 @@ bool EntityTreeElement::shouldIncludeChildData(int childIndex, EncodeBitstreamPa if (extraEncodeData->contains(this)) { EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData - = static_cast(extraEncodeData->value(this)); + = static_cast((*extraEncodeData)[this]); bool childCompleted = entityTreeElementExtraEncodeData->childCompleted[childIndex]; @@ -126,7 +126,7 @@ bool EntityTreeElement::alreadyFullyEncoded(EncodeBitstreamParams& params) const if (extraEncodeData->contains(this)) { EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData - = static_cast(extraEncodeData->value(this)); + = static_cast((*extraEncodeData)[this]); // If we know that ALL subtrees below us have already been recursed, then we don't // need to recurse this child. @@ -140,7 +140,7 @@ void EntityTreeElement::updateEncodedData(int childIndex, AppendState childAppen assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes if (extraEncodeData->contains(this)) { EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData - = static_cast(extraEncodeData->value(this)); + = static_cast((*extraEncodeData)[this]); if (childAppendState == OctreeElement::COMPLETED) { entityTreeElementExtraEncodeData->childCompleted[childIndex] = true; @@ -165,7 +165,7 @@ void EntityTreeElement::elementEncodeComplete(EncodeBitstreamParams& params) con assert(extraEncodeData->contains(this)); EntityTreeElementExtraEncodeData* thisExtraEncodeData - = static_cast(extraEncodeData->value(this)); + = static_cast((*extraEncodeData)[this]); // Note: this will be called when OUR element has finished running through encodeTreeBitstreamRecursion() // which means, it's possible that our parent element hasn't finished encoding OUR data... so @@ -241,7 +241,7 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData bool hadElementExtraData = false; if (extraEncodeData && extraEncodeData->contains(this)) { entityTreeElementExtraEncodeData = - static_cast(extraEncodeData->value(this)); + static_cast((*extraEncodeData)[this]); hadElementExtraData = true; } else { // if there wasn't one already, then create one @@ -268,7 +268,7 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData //assert(extraEncodeData); //assert(extraEncodeData->contains(this)); - //entityTreeElementExtraEncodeData = static_cast(extraEncodeData->value(this)); + //entityTreeElementExtraEncodeData = static_cast((*extraEncodeData)[this]); LevelDetails elementLevel = packetData->startLevel(); From eab611acc072d443ab7fccb2dfaed6b4b370046c Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 18 May 2016 21:46:30 -0700 Subject: [PATCH 27/31] Enable Steam VR text input --- libraries/gl/src/gl/OffscreenQmlSurface.cpp | 41 ++++++++++++++++++++ libraries/gl/src/gl/OffscreenQmlSurface.h | 8 +++- plugins/openvr/src/OpenVrDisplayPlugin.cpp | 3 ++ plugins/openvr/src/ViveControllerManager.cpp | 34 +++++++++++++++- 4 files changed, 84 insertions(+), 2 deletions(-) diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index 388ca26482..fa9cb62b7c 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -396,6 +396,8 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) { _renderer->_renderControl->_renderWindow = _proxyWindow; + connect(_renderer->_quickWindow, &QQuickWindow::focusObjectChanged, this, &OffscreenQmlSurface::onFocusObjectChanged); + // Create a QML engine. _qmlEngine = new QQmlEngine; if (!_qmlEngine->incubationController()) { @@ -742,3 +744,42 @@ QVariant OffscreenQmlSurface::returnFromUiThread(std::function funct return function(); } + +void OffscreenQmlSurface::onFocusObjectChanged(QObject* object) { + if (!object) { + setFocusText(false); + return; + } + + QVariant result; +#if 1 + auto invokeResult = QMetaObject::invokeMethod(object, "inputMethodQuery", Q_RETURN_ARG(QVariant, result), + Q_ARG(Qt::InputMethodQuery, Qt::ImEnabled), + Q_ARG(QVariant, QVariant())); +#else + + //static const char* INPUT_METHOD_QUERY_METHOD_NAME = "inputMethodQuery(Qt::InputMethodQuery, QVariant)"; + static const char* INPUT_METHOD_QUERY_METHOD_NAME = "inputMethodQuery"; + auto meta = object->metaObject(); + qDebug() << "new focus " << object; + auto index = meta->indexOfMethod(INPUT_METHOD_QUERY_METHOD_NAME); + if (index < 0 || index >= meta->methodCount()) { + setFocusText(false); + return; + } + + auto method = meta->method(index); + auto invokeResult = method.invoke(object, + Q_RETURN_ARG(QVariant, result), + Q_ARG(Qt::InputMethodQuery, Qt::ImEnabled), + Q_ARG(QVariant, QVariant())); +#endif + setFocusText(invokeResult && result.toBool()); +} + +void OffscreenQmlSurface::setFocusText(bool newFocusText) { + if (newFocusText != _focusText) { + _focusText = newFocusText; + emit focusTextChanged(_focusText); + } +} diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.h b/libraries/gl/src/gl/OffscreenQmlSurface.h index 22a1b99fe6..1ce7276877 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.h +++ b/libraries/gl/src/gl/OffscreenQmlSurface.h @@ -30,7 +30,7 @@ class OffscreenQmlRenderThread; class OffscreenQmlSurface : public QObject { Q_OBJECT - + Q_PROPERTY(bool focusText READ isFocusText NOTIFY focusTextChanged) public: OffscreenQmlSurface(); virtual ~OffscreenQmlSurface(); @@ -55,6 +55,7 @@ public: _mouseTranslator = mouseTranslator; } + bool isFocusText() const { return _focusText; } void pause(); void resume(); bool isPaused() const; @@ -70,6 +71,8 @@ public: signals: void textureUpdated(unsigned int texture); + void focusObjectChanged(QObject* newFocus); + void focusTextChanged(bool focusText); public slots: void requestUpdate(); @@ -78,6 +81,7 @@ public slots: protected: bool filterEnabled(QObject* originalDestination, QEvent* event) const; + void setFocusText(bool newFocusText); private: QObject* finishQmlLoad(std::function f); @@ -85,6 +89,7 @@ private: private slots: void updateQuick(); + void onFocusObjectChanged(QObject* newFocus); private: friend class OffscreenQmlRenderThread; @@ -97,6 +102,7 @@ private: bool _render{ false }; bool _polish{ true }; bool _paused{ true }; + bool _focusText { false }; uint8_t _maxFps{ 60 }; MouseTranslator _mouseTranslator{ [](const QPointF& p) { return p.toPoint(); } }; QWindow* _proxyWindow { nullptr }; diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp index fe406cc29a..fbade9fd68 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp +++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp @@ -36,12 +36,14 @@ vec3 _trackedDeviceLinearVelocities[vr::k_unMaxTrackedDeviceCount]; vec3 _trackedDeviceAngularVelocities[vr::k_unMaxTrackedDeviceCount]; static mat4 _sensorResetMat; static std::array VR_EYES { { vr::Eye_Left, vr::Eye_Right } }; +bool _openVrDisplayActive { false }; bool OpenVrDisplayPlugin::isSupported() const { return openVrSupported(); } bool OpenVrDisplayPlugin::internalActivate() { + _openVrDisplayActive = true; _container->setIsOptionChecked(StandingHMDSensorMode, true); if (!_system) { @@ -94,6 +96,7 @@ bool OpenVrDisplayPlugin::internalActivate() { void OpenVrDisplayPlugin::internalDeactivate() { Parent::internalDeactivate(); + _openVrDisplayActive = false; _container->setIsOptionChecked(StandingHMDSensorMode, false); if (_system) { // Invalidate poses. It's fine if someone else sets these shared values, but we're about to stop updating them, and diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 739d3cde10..8d6c661ae6 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -12,6 +12,7 @@ #include "ViveControllerManager.h" #include +#include #include #include @@ -22,6 +23,7 @@ #include #include #include +#include #include @@ -55,6 +57,9 @@ bool ViveControllerManager::isSupported() const { return openVrSupported(); } +QMetaObject::Connection _focusConnection; +extern bool _openVrDisplayActive; + bool ViveControllerManager::activate() { InputPlugin::activate(); @@ -67,7 +72,20 @@ bool ViveControllerManager::activate() { _system = acquireOpenVrSystem(); } Q_ASSERT(_system); - + auto offscreenUi = DependencyManager::get(); + _focusConnection = connect(offscreenUi.data(), &OffscreenUi::focusTextChanged, [this](bool focusText) { + if (_openVrDisplayActive) { + auto overlay = vr::VROverlay(); + if (overlay) { + if (focusText) { + //virtual EVROverlayError ShowKeyboard( eInputMode, EGamepadTextInputLineMode eLineInputMode, const char *pchDescription, uint32_t unCharMax, const char *pchExistingText, bool bUseMinimalMode, uint64_t uUserValue) = 0; + overlay->ShowKeyboard(vr::EGamepadTextInputMode::k_EGamepadTextInputModeNormal, vr::k_EGamepadTextInputLineModeSingleLine, "Test", 1024, "", false, 0); + } else { + overlay->HideKeyboard(); + } + } + } + }); // OpenVR provides 3d mesh representations of the controllers // Disabled controller rendering code /* @@ -132,6 +150,8 @@ bool ViveControllerManager::activate() { void ViveControllerManager::deactivate() { InputPlugin::deactivate(); + disconnect(_focusConnection); + _container->removeMenuItem(MENU_NAME, RENDER_CONTROLLERS); _container->removeMenu(MENU_PATH); @@ -220,6 +240,18 @@ void ViveControllerManager::pluginUpdate(float deltaTime, const controller::Inpu return; } + vr::VREvent_t vrEvent; + static char textArray[8192]; + while (vr::VRSystem()->PollNextEvent(&vrEvent, sizeof(vrEvent))) { + if (vrEvent.eventType == vr::VREvent_KeyboardDone) { + auto chars = vr::VROverlay()->GetKeyboardText(textArray, 8192); + QInputMethodEvent* event = new QInputMethodEvent(); + event->setCommitString(QString(QByteArray(textArray, chars)), 0, 0); + auto focusObject = DependencyManager::get()->getWindow()->focusObject(); + qApp->postEvent(focusObject, event); + } + } + // because update mutates the internal state we need to lock userInputMapper->withLock([&, this]() { _inputDevice->update(deltaTime, inputCalibrationData); From c2aa9e7f61f71fd3fd53acf3f9ecdec94d34ce06 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 6 Jun 2016 15:14:10 -0700 Subject: [PATCH 28/31] Update SteamVR keyboard behavior --- libraries/gl/src/gl/OffscreenQmlSurface.cpp | 27 +------ plugins/openvr/src/OpenVrHelpers.cpp | 85 ++++++++++++++++++++ plugins/openvr/src/OpenVrHelpers.h | 3 + plugins/openvr/src/ViveControllerManager.cpp | 37 +-------- 4 files changed, 95 insertions(+), 57 deletions(-) diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index fa9cb62b7c..14518ac37a 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -751,30 +751,9 @@ void OffscreenQmlSurface::onFocusObjectChanged(QObject* object) { return; } - QVariant result; -#if 1 - auto invokeResult = QMetaObject::invokeMethod(object, "inputMethodQuery", Q_RETURN_ARG(QVariant, result), - Q_ARG(Qt::InputMethodQuery, Qt::ImEnabled), - Q_ARG(QVariant, QVariant())); -#else - - //static const char* INPUT_METHOD_QUERY_METHOD_NAME = "inputMethodQuery(Qt::InputMethodQuery, QVariant)"; - static const char* INPUT_METHOD_QUERY_METHOD_NAME = "inputMethodQuery"; - auto meta = object->metaObject(); - qDebug() << "new focus " << object; - auto index = meta->indexOfMethod(INPUT_METHOD_QUERY_METHOD_NAME); - if (index < 0 || index >= meta->methodCount()) { - setFocusText(false); - return; - } - - auto method = meta->method(index); - auto invokeResult = method.invoke(object, - Q_RETURN_ARG(QVariant, result), - Q_ARG(Qt::InputMethodQuery, Qt::ImEnabled), - Q_ARG(QVariant, QVariant())); -#endif - setFocusText(invokeResult && result.toBool()); + QInputMethodQueryEvent query(Qt::ImEnabled); + qApp->sendEvent(object, &query); + setFocusText(query.value(Qt::ImEnabled).toBool()); } void OffscreenQmlSurface::setFocusText(bool newFocusText) { diff --git a/plugins/openvr/src/OpenVrHelpers.cpp b/plugins/openvr/src/OpenVrHelpers.cpp index 155bc9f079..b13a60d388 100644 --- a/plugins/openvr/src/OpenVrHelpers.cpp +++ b/plugins/openvr/src/OpenVrHelpers.cpp @@ -14,9 +14,13 @@ #include #include #include +#include +#include #include +#include + Q_DECLARE_LOGGING_CATEGORY(displayplugins) Q_LOGGING_CATEGORY(displayplugins, "hifi.plugins.display") @@ -90,6 +94,82 @@ void releaseOpenVrSystem() { } } +static char textArray[8192]; + +static QMetaObject::Connection _focusConnection, _focusTextConnection; +extern bool _openVrDisplayActive; +static vr::IVROverlay* _overlay { nullptr }; +static QObject* _focusObject { nullptr }; +static QString _existingText; +static Qt::InputMethodHints _currentHints; + +void showOpenVrKeyboard(bool show = true) { + if (_overlay) { + if (show) { + auto offscreenUi = DependencyManager::get(); + _focusObject = offscreenUi->getWindow()->focusObject(); + + QInputMethodQueryEvent query(Qt::ImQueryInput | Qt::ImHints); + qApp->sendEvent(_focusObject, &query); + _currentHints = Qt::InputMethodHints(query.value(Qt::ImHints).toUInt()); + vr::EGamepadTextInputMode inputMode = vr::k_EGamepadTextInputModeNormal; + if (_currentHints & Qt::ImhHiddenText) { + inputMode = vr::k_EGamepadTextInputModePassword; + } + vr::EGamepadTextInputLineMode lineMode = vr::k_EGamepadTextInputLineModeSingleLine; + if (_currentHints & Qt::ImhMultiLine) { + lineMode = vr::k_EGamepadTextInputLineModeMultipleLines; + } + _existingText = query.value(Qt::ImSurroundingText).toString(); + _overlay->ShowKeyboard(inputMode, lineMode, "Keyboard", 1024, _existingText.toLocal8Bit().toStdString().c_str(), false, (uint64_t)(void*)_focusObject); + } else { + _focusObject = nullptr; + _overlay->HideKeyboard(); + } + } +} + +void finishOpenVrKeyboardInput() { + auto offscreenUi = DependencyManager::get(); + auto chars = _overlay->GetKeyboardText(textArray, 8192); + auto newText = QString(QByteArray(textArray, chars)); + // TODO modify the new text to match the possible input hints: + // ImhDigitsOnly ImhFormattedNumbersOnly ImhUppercaseOnly ImhLowercaseOnly + // ImhDialableCharactersOnly ImhEmailCharactersOnly ImhUrlCharactersOnly ImhLatinOnly + QInputMethodEvent event(_existingText, QList()); + event.setCommitString(newText, 0, _existingText.size()); + qApp->sendEvent(_focusObject, &event); + // Simulate an enter press on the top level window to trigger the action + if (0 == (_currentHints & Qt::ImhMultiLine)) { + qApp->sendEvent(offscreenUi->getWindow(), &QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::KeyboardModifiers(), QString("\n"))); + qApp->sendEvent(offscreenUi->getWindow(), &QKeyEvent(QEvent::KeyRelease, Qt::Key_Return, Qt::KeyboardModifiers())); + } +} + +void enableOpenVrKeyboard() { + auto offscreenUi = DependencyManager::get(); + _overlay = vr::VROverlay(); + + _focusConnection = QObject::connect(offscreenUi->getWindow(), &QQuickWindow::focusObjectChanged, [](QObject* object) { + if (object != _focusObject && _overlay) { + showOpenVrKeyboard(false); + } + }); + + _focusTextConnection = QObject::connect(offscreenUi.data(), &OffscreenUi::focusTextChanged, [](bool focusText) { + if (_openVrDisplayActive) { + showOpenVrKeyboard(focusText); + } + }); +} + + +void disableOpenVrKeyboard() { + QObject::disconnect(_focusTextConnection); + QObject::disconnect(_focusConnection); +} + + void handleOpenVrEvents() { if (!activeHmd) { return; @@ -107,6 +187,10 @@ void handleOpenVrEvents() { activeHmd->AcknowledgeQuit_Exiting(); break; + case vr::VREvent_KeyboardDone: + finishOpenVrKeyboardInput(); + break; + default: break; } @@ -114,3 +198,4 @@ void handleOpenVrEvents() { } } + diff --git a/plugins/openvr/src/OpenVrHelpers.h b/plugins/openvr/src/OpenVrHelpers.h index 1e5914844c..41e7dcb27d 100644 --- a/plugins/openvr/src/OpenVrHelpers.h +++ b/plugins/openvr/src/OpenVrHelpers.h @@ -18,6 +18,9 @@ vr::IVRSystem* acquireOpenVrSystem(); void releaseOpenVrSystem(); void handleOpenVrEvents(); bool openVrQuitRequested(); +void enableOpenVrKeyboard(); +void disableOpenVrKeyboard(); + template void openvr_for_each_eye(F f) { diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 8d6c661ae6..6d3ce46e82 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -11,9 +11,6 @@ #include "ViveControllerManager.h" -#include -#include - #include #include #include @@ -57,9 +54,6 @@ bool ViveControllerManager::isSupported() const { return openVrSupported(); } -QMetaObject::Connection _focusConnection; -extern bool _openVrDisplayActive; - bool ViveControllerManager::activate() { InputPlugin::activate(); @@ -72,20 +66,9 @@ bool ViveControllerManager::activate() { _system = acquireOpenVrSystem(); } Q_ASSERT(_system); - auto offscreenUi = DependencyManager::get(); - _focusConnection = connect(offscreenUi.data(), &OffscreenUi::focusTextChanged, [this](bool focusText) { - if (_openVrDisplayActive) { - auto overlay = vr::VROverlay(); - if (overlay) { - if (focusText) { - //virtual EVROverlayError ShowKeyboard( eInputMode, EGamepadTextInputLineMode eLineInputMode, const char *pchDescription, uint32_t unCharMax, const char *pchExistingText, bool bUseMinimalMode, uint64_t uUserValue) = 0; - overlay->ShowKeyboard(vr::EGamepadTextInputMode::k_EGamepadTextInputModeNormal, vr::k_EGamepadTextInputLineModeSingleLine, "Test", 1024, "", false, 0); - } else { - overlay->HideKeyboard(); - } - } - } - }); + + enableOpenVrKeyboard(); + // OpenVR provides 3d mesh representations of the controllers // Disabled controller rendering code /* @@ -150,7 +133,7 @@ bool ViveControllerManager::activate() { void ViveControllerManager::deactivate() { InputPlugin::deactivate(); - disconnect(_focusConnection); + disableOpenVrKeyboard(); _container->removeMenuItem(MENU_NAME, RENDER_CONTROLLERS); _container->removeMenu(MENU_PATH); @@ -240,18 +223,6 @@ void ViveControllerManager::pluginUpdate(float deltaTime, const controller::Inpu return; } - vr::VREvent_t vrEvent; - static char textArray[8192]; - while (vr::VRSystem()->PollNextEvent(&vrEvent, sizeof(vrEvent))) { - if (vrEvent.eventType == vr::VREvent_KeyboardDone) { - auto chars = vr::VROverlay()->GetKeyboardText(textArray, 8192); - QInputMethodEvent* event = new QInputMethodEvent(); - event->setCommitString(QString(QByteArray(textArray, chars)), 0, 0); - auto focusObject = DependencyManager::get()->getWindow()->focusObject(); - qApp->postEvent(focusObject, event); - } - } - // because update mutates the internal state we need to lock userInputMapper->withLock([&, this]() { _inputDevice->update(deltaTime, inputCalibrationData); From 79c68b2ecb203cb09453e53179eb22e7689d00df Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 7 Jun 2016 21:49:29 -0700 Subject: [PATCH 29/31] Working on positioning of the keyboard --- plugins/openvr/src/OpenVrHelpers.cpp | 11 ++++++++++- plugins/openvr/src/OpenVrHelpers.h | 10 ++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/plugins/openvr/src/OpenVrHelpers.cpp b/plugins/openvr/src/OpenVrHelpers.cpp index b13a60d388..6533371db8 100644 --- a/plugins/openvr/src/OpenVrHelpers.cpp +++ b/plugins/openvr/src/OpenVrHelpers.cpp @@ -102,6 +102,7 @@ static vr::IVROverlay* _overlay { nullptr }; static QObject* _focusObject { nullptr }; static QString _existingText; static Qt::InputMethodHints _currentHints; +extern vr::TrackedDevicePose_t _trackedDevicePose[vr::k_unMaxTrackedDeviceCount]; void showOpenVrKeyboard(bool show = true) { if (_overlay) { @@ -121,7 +122,15 @@ void showOpenVrKeyboard(bool show = true) { lineMode = vr::k_EGamepadTextInputLineModeMultipleLines; } _existingText = query.value(Qt::ImSurroundingText).toString(); - _overlay->ShowKeyboard(inputMode, lineMode, "Keyboard", 1024, _existingText.toLocal8Bit().toStdString().c_str(), false, (uint64_t)(void*)_focusObject); + + auto showKeyboardResult = _overlay->ShowKeyboard(inputMode, lineMode, "Keyboard", 1024, + _existingText.toLocal8Bit().toStdString().c_str(), false, 0); + + mat4 headPose = toGlm(_trackedDevicePose[0].mDeviceToAbsoluteTracking); + mat4 keyboardTransform = glm::translate(headPose, vec3(0, -0.5, -1)); + keyboardTransform = keyboardTransform * glm::rotate(mat4(), 3.14159f / 4.0f, vec3(-1, 0, 0)); + auto keyboardTransformVr = toOpenVr(keyboardTransform); + _overlay->SetKeyboardTransformAbsolute(vr::ETrackingUniverseOrigin::TrackingUniverseStanding, &keyboardTransformVr); } else { _focusObject = nullptr; _overlay->HideKeyboard(); diff --git a/plugins/openvr/src/OpenVrHelpers.h b/plugins/openvr/src/OpenVrHelpers.h index 41e7dcb27d..426178cd65 100644 --- a/plugins/openvr/src/OpenVrHelpers.h +++ b/plugins/openvr/src/OpenVrHelpers.h @@ -44,3 +44,13 @@ inline mat4 toGlm(const vr::HmdMatrix34_t& m) { m.m[0][3], m.m[1][3], m.m[2][3], 1.0f); return result; } + +inline vr::HmdMatrix34_t toOpenVr(const mat4& m) { + vr::HmdMatrix34_t result; + for (uint8_t i = 0; i < 3; ++i) { + for (uint8_t j = 0; j < 4; ++j) { + result.m[i][j] = m[j][i]; + } + } + return result; +} From 40778d7f299777d5c395e0e742532f214ee5c799 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 8 Jun 2016 10:41:19 -0700 Subject: [PATCH 30/31] Allow env disabling of the keyboard. Show keyboard after short delay to avoid flickers --- plugins/openvr/src/OpenVrHelpers.cpp | 64 ++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 17 deletions(-) diff --git a/plugins/openvr/src/OpenVrHelpers.cpp b/plugins/openvr/src/OpenVrHelpers.cpp index 6533371db8..1ff1c65ef8 100644 --- a/plugins/openvr/src/OpenVrHelpers.cpp +++ b/plugins/openvr/src/OpenVrHelpers.cpp @@ -99,19 +99,33 @@ static char textArray[8192]; static QMetaObject::Connection _focusConnection, _focusTextConnection; extern bool _openVrDisplayActive; static vr::IVROverlay* _overlay { nullptr }; -static QObject* _focusObject { nullptr }; +static QObject* _keyboardFocusObject { nullptr }; static QString _existingText; static Qt::InputMethodHints _currentHints; extern vr::TrackedDevicePose_t _trackedDevicePose[vr::k_unMaxTrackedDeviceCount]; +static bool _keyboardShown { false }; +static const uint32_t SHOW_KEYBOARD_DELAY_MS = 100; void showOpenVrKeyboard(bool show = true) { - if (_overlay) { - if (show) { - auto offscreenUi = DependencyManager::get(); - _focusObject = offscreenUi->getWindow()->focusObject(); + if (!_overlay) { + return; + } - QInputMethodQueryEvent query(Qt::ImQueryInput | Qt::ImHints); - qApp->sendEvent(_focusObject, &query); + if (show) { + // To avoid flickering the keyboard when a text element is only briefly selected, + // show the keyboard asynchrnously after a very short delay, but only after we check + // that the current focus object is still one that is text enabled + QTimer::singleShot(SHOW_KEYBOARD_DELAY_MS, [] { + auto offscreenUi = DependencyManager::get(); + auto currentFocus = offscreenUi->getWindow()->focusObject(); + QInputMethodQueryEvent query(Qt::ImEnabled | Qt::ImQueryInput | Qt::ImHints); + qApp->sendEvent(currentFocus, &query); + // Current focus isn't text enabled, bail early. + if (!query.value(Qt::ImEnabled).toBool()) { + return; + } + // We're going to show the keyboard now... + _keyboardFocusObject = currentFocus; _currentHints = Qt::InputMethodHints(query.value(Qt::ImHints).toUInt()); vr::EGamepadTextInputMode inputMode = vr::k_EGamepadTextInputModeNormal; if (_currentHints & Qt::ImhHiddenText) { @@ -123,17 +137,24 @@ void showOpenVrKeyboard(bool show = true) { } _existingText = query.value(Qt::ImSurroundingText).toString(); - auto showKeyboardResult = _overlay->ShowKeyboard(inputMode, lineMode, "Keyboard", 1024, + auto showKeyboardResult = _overlay->ShowKeyboard(inputMode, lineMode, "Keyboard", 1024, _existingText.toLocal8Bit().toStdString().c_str(), false, 0); - mat4 headPose = toGlm(_trackedDevicePose[0].mDeviceToAbsoluteTracking); - mat4 keyboardTransform = glm::translate(headPose, vec3(0, -0.5, -1)); - keyboardTransform = keyboardTransform * glm::rotate(mat4(), 3.14159f / 4.0f, vec3(-1, 0, 0)); - auto keyboardTransformVr = toOpenVr(keyboardTransform); - _overlay->SetKeyboardTransformAbsolute(vr::ETrackingUniverseOrigin::TrackingUniverseStanding, &keyboardTransformVr); - } else { - _focusObject = nullptr; + if (vr::VROverlayError_None == showKeyboardResult) { + _keyboardShown = true; + // Try to position the keyboard slightly below where the user is looking. + mat4 headPose = toGlm(_trackedDevicePose[0].mDeviceToAbsoluteTracking); + mat4 keyboardTransform = glm::translate(headPose, vec3(0, -0.5, -1)); + keyboardTransform = keyboardTransform * glm::rotate(mat4(), 3.14159f / 4.0f, vec3(-1, 0, 0)); + auto keyboardTransformVr = toOpenVr(keyboardTransform); + _overlay->SetKeyboardTransformAbsolute(vr::ETrackingUniverseOrigin::TrackingUniverseStanding, &keyboardTransformVr); + } + }); + } else { + _keyboardFocusObject = nullptr; + if (_keyboardShown) { _overlay->HideKeyboard(); + _keyboardShown = false; } } } @@ -147,7 +168,7 @@ void finishOpenVrKeyboardInput() { // ImhDialableCharactersOnly ImhEmailCharactersOnly ImhUrlCharactersOnly ImhLatinOnly QInputMethodEvent event(_existingText, QList()); event.setCommitString(newText, 0, _existingText.size()); - qApp->sendEvent(_focusObject, &event); + qApp->sendEvent(_keyboardFocusObject, &event); // Simulate an enter press on the top level window to trigger the action if (0 == (_currentHints & Qt::ImhMultiLine)) { qApp->sendEvent(offscreenUi->getWindow(), &QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::KeyboardModifiers(), QString("\n"))); @@ -155,12 +176,18 @@ void finishOpenVrKeyboardInput() { } } +static const QString DEBUG_FLAG("HIFI_DISABLE_STEAM_VR_KEYBOARD"); +bool disableSteamVrKeyboard = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG); + void enableOpenVrKeyboard() { + if (disableSteamVrKeyboard) { + return; + } auto offscreenUi = DependencyManager::get(); _overlay = vr::VROverlay(); _focusConnection = QObject::connect(offscreenUi->getWindow(), &QQuickWindow::focusObjectChanged, [](QObject* object) { - if (object != _focusObject && _overlay) { + if (object != _keyboardFocusObject) { showOpenVrKeyboard(false); } }); @@ -174,6 +201,9 @@ void enableOpenVrKeyboard() { void disableOpenVrKeyboard() { + if (disableSteamVrKeyboard) { + return; + } QObject::disconnect(_focusTextConnection); QObject::disconnect(_focusConnection); } From f8353fb082c875ec56cb094853cba9730a005610 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 8 Jun 2016 11:11:18 -0700 Subject: [PATCH 31/31] New button content and initial positions. --- .../assets/images/tools/hmd-switch-01.svg | 198 ++++++++++-------- scripts/system/edit.js | 2 +- scripts/system/examples.js | 4 +- scripts/system/goto.js | 2 +- scripts/system/hmd.js | 2 +- 5 files changed, 115 insertions(+), 93 deletions(-) diff --git a/scripts/system/assets/images/tools/hmd-switch-01.svg b/scripts/system/assets/images/tools/hmd-switch-01.svg index 15ecb02b6b..31389d355c 100644 --- a/scripts/system/assets/images/tools/hmd-switch-01.svg +++ b/scripts/system/assets/images/tools/hmd-switch-01.svg @@ -4,99 +4,121 @@ viewBox="0 0 50 150" style="enable-background:new 0 0 50 150;" xml:space="preserve"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + diff --git a/scripts/system/edit.js b/scripts/system/edit.js index afbc679ec4..38d596f83e 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -181,7 +181,7 @@ var toolBar = (function() { function initialize() { toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.edit.toolbar", function(windowDimensions, toolbar) { return { - x: windowDimensions.x / 2, + x: (windowDimensions.x / 2) + (Tool.IMAGE_WIDTH * 2), y: windowDimensions.y }; }, { diff --git a/scripts/system/examples.js b/scripts/system/examples.js index 9d33e473af..6f4268182c 100644 --- a/scripts/system/examples.js +++ b/scripts/system/examples.js @@ -60,7 +60,7 @@ var toolBar = (function() { function initialize() { toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.examples.toolbar", function(windowDimensions, toolbar) { return { - x: windowDimensions.x / 2, + x: (windowDimensions.x / 2) + (Tool.IMAGE_WIDTH * 2), y: windowDimensions.y }; }, { @@ -135,4 +135,4 @@ var toolBar = (function() { }()); Controller.mousePressEvent.connect(toolBar.mousePressEvent) -Script.scriptEnding.connect(toolBar.cleanup); \ No newline at end of file +Script.scriptEnding.connect(toolBar.cleanup); diff --git a/scripts/system/goto.js b/scripts/system/goto.js index 75d9829905..00b5e912c0 100644 --- a/scripts/system/goto.js +++ b/scripts/system/goto.js @@ -13,7 +13,7 @@ Script.include("libraries/toolBars.js"); function initialPosition(windowDimensions, toolbar) { return { - x: windowDimensions.x / 2 - Tool.IMAGE_WIDTH, + x: (windowDimensions.x / 2) - (Tool.IMAGE_WIDTH * 1), y: windowDimensions.y }; } diff --git a/scripts/system/hmd.js b/scripts/system/hmd.js index 277af68315..8b91e45676 100644 --- a/scripts/system/hmd.js +++ b/scripts/system/hmd.js @@ -22,7 +22,7 @@ var desktopMenuItemName = "Desktop"; function initialPosition(windowDimensions, toolbar) { return { - x: windowDimensions.x / 2 + (2 * Tool.IMAGE_WIDTH), + x: (windowDimensions.x / 2) - (Tool.IMAGE_WIDTH * 2.5), y: windowDimensions.y }; }