From d38cd8cd2d913f30b0e23c8d6b9a274f4f47036d Mon Sep 17 00:00:00 2001 From: Colin Ogilvie Date: Fri, 15 Jan 2016 13:40:10 +0000 Subject: Aggregate action functionality Change-Id: Iac5e6bfd2ad67b3c1c9a794ea528204eff238d20 Reviewed-by: Sean Harmer --- src/input/backend/inputchord.cpp | 36 +++++++++++++++- src/input/backend/inputchord_p.h | 7 ++- src/input/backend/inputsequence.cpp | 60 +++++++++++++++++++++++++- src/input/backend/inputsequence_p.h | 9 ++++ src/input/backend/updateaxisactionjob.cpp | 72 ++++++++++++++++++++++++++----- src/input/backend/updateaxisactionjob_p.h | 5 ++- src/input/frontend/qinputaspect.cpp | 2 +- 7 files changed, 173 insertions(+), 18 deletions(-) diff --git a/src/input/backend/inputchord.cpp b/src/input/backend/inputchord.cpp index b788a13f5..5d3d13e91 100644 --- a/src/input/backend/inputchord.cpp +++ b/src/input/backend/inputchord.cpp @@ -47,7 +47,9 @@ namespace Input { InputChord::InputChord() : Qt3DCore::QBackendNode() , m_inputs() + , m_inputsToTrigger() , m_tolerance(0) + , m_startTime(0) , m_enabled(false) { } @@ -65,7 +67,33 @@ void InputChord::cleanup() { m_enabled = false; m_tolerance = 0; + m_startTime = 0; m_inputs.clear(); + m_inputsToTrigger.clear(); +} + +void InputChord::reset() +{ + m_startTime = 0; + m_inputsToTrigger.clear(); + Q_FOREACH (Qt3DCore::QNodeId input, m_inputs) + m_inputsToTrigger.push_back(input); +} + +bool InputChord::actionTriggered(Qt3DCore::QNodeId input) +{ + m_inputsToTrigger.removeOne(input); + if (m_inputsToTrigger.isEmpty()) { + //All Triggered + reset(); + return true; + } + return false; +} + +void InputChord::setStartTime(qint64 time) +{ + m_startTime = time; } void InputChord::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) @@ -78,11 +106,15 @@ void InputChord::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) m_tolerance = propertyChange->value().toInt(); } } else if (e->type() == Qt3DCore::NodeAdded) { - if (propertyChange->propertyName() == QByteArrayLiteral("input")) + if (propertyChange->propertyName() == QByteArrayLiteral("input")) { m_inputs.push_back(propertyChange->value().value()); + m_inputsToTrigger.push_back(propertyChange->value().value()); + } } else if (e->type() == Qt3DCore::NodeRemoved) { - if (propertyChange->propertyName() == QByteArrayLiteral("input")) + if (propertyChange->propertyName() == QByteArrayLiteral("input")) { m_inputs.removeOne(propertyChange->value().value()); + m_inputsToTrigger.removeOne(propertyChange->value().value()); + } } } diff --git a/src/input/backend/inputchord_p.h b/src/input/backend/inputchord_p.h index a8870e531..633a66489 100644 --- a/src/input/backend/inputchord_p.h +++ b/src/input/backend/inputchord_p.h @@ -66,12 +66,17 @@ public: inline QVector inputs() const { return m_inputs; } inline int tolerance() const { return m_tolerance; } + inline qint64 startTime() const { return m_startTime; } + void setStartTime(qint64 time); inline bool isEnabled() const { return m_enabled; } + void reset(); + bool actionTriggered(Qt3DCore::QNodeId input); void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; - private: QVector m_inputs; + QVector m_inputsToTrigger; int m_tolerance; + qint64 m_startTime; bool m_enabled; }; diff --git a/src/input/backend/inputsequence.cpp b/src/input/backend/inputsequence.cpp index 43847d3d4..aa854bdb1 100644 --- a/src/input/backend/inputsequence.cpp +++ b/src/input/backend/inputsequence.cpp @@ -38,6 +38,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -48,9 +49,12 @@ namespace Input { InputSequence::InputSequence() : Qt3DCore::QBackendNode() , m_inputs() + , m_inputsToTrigger() , m_timeout(0) , m_interval(0) , m_sequential(true) + , m_startTime(0) + , m_lastInputTime(0) , m_enabled(false) { } @@ -71,8 +75,56 @@ void InputSequence::cleanup() m_enabled = false; m_timeout = 0; m_interval = 0; + m_startTime = 0; + m_lastInputTime = 0; + m_lastInputId = Qt3DCore::QNodeId(); m_sequential = true; m_inputs.clear(); + m_inputsToTrigger.clear(); +} + +void InputSequence::setStartTime(qint64 time) +{ + m_startTime = time; +} + +void InputSequence::reset() +{ + m_startTime = 0; + m_lastInputTime = 0; + m_inputsToTrigger = m_inputs; + m_lastInputId = Qt3DCore::QNodeId(); +} + +bool InputSequence::actionTriggered(Qt3DCore::QNodeId input, const qint64 currentTime) +{ + // If we are running the root of a sequence and input is not the first element of the sequence + // reset and return false + if (m_sequential && (!m_inputs.empty() && m_inputsToTrigger.first() != input)) { + if (!(input == m_lastInputId && ((currentTime - m_lastInputTime) < 200))) + reset(); + return false; + } + + // Otherwise save the last input + m_lastInputId = input; + // Return false if we've spent too much time in between two sequences + if ((m_lastInputTime != 0) && ((currentTime - m_lastInputTime) > m_interval)) { + reset(); + return false; + } + + // Update lastInputTime and remove the inputs to trigger from the sequence + m_lastInputTime = currentTime; + m_inputsToTrigger.removeOne(input); + + // If we have no more remaining inputs in the sequences of inputs + if (m_inputsToTrigger.isEmpty()) { + // All Triggered + reset(); + return true; + } + return false; } void InputSequence::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) @@ -89,11 +141,15 @@ void InputSequence::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) m_sequential = propertyChange->value().toBool(); } } else if (e->type() == Qt3DCore::NodeAdded) { - if (propertyChange->propertyName() == QByteArrayLiteral("input")) + if (propertyChange->propertyName() == QByteArrayLiteral("input")) { m_inputs.push_back(propertyChange->value().value()); + m_inputsToTrigger.push_back(propertyChange->value().value()); + } } else if (e->type() == Qt3DCore::NodeRemoved) { - if (propertyChange->propertyName() == QByteArrayLiteral("input")) + if (propertyChange->propertyName() == QByteArrayLiteral("input")) { m_inputs.removeOne(propertyChange->value().value()); + m_inputsToTrigger.removeOne(propertyChange->value().value()); + } } } diff --git a/src/input/backend/inputsequence_p.h b/src/input/backend/inputsequence_p.h index ef916aa7c..c44c0dcfe 100644 --- a/src/input/backend/inputsequence_p.h +++ b/src/input/backend/inputsequence_p.h @@ -67,15 +67,24 @@ public: inline QVector inputs() const { return m_inputs; } inline int timeout() const { return m_timeout; } inline int interval() const { return m_interval; } + inline qint64 startTime() const { return m_startTime; } + void setStartTime(qint64 time); inline bool isSequential() const { return m_sequential; } inline bool isEnabled() const { return m_enabled; } + bool sequenceTriggered() const; + void reset(); + bool actionTriggered(Qt3DCore::QNodeId input, const qint64 currentTime); void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; private: QVector m_inputs; + QVector m_inputsToTrigger; int m_timeout; int m_interval; bool m_sequential; + qint64 m_startTime; + qint64 m_lastInputTime; + Qt3DCore::QNodeId m_lastInputId; bool m_enabled; }; diff --git a/src/input/backend/updateaxisactionjob.cpp b/src/input/backend/updateaxisactionjob.cpp index 406aa952c..6b7f0f457 100644 --- a/src/input/backend/updateaxisactionjob.cpp +++ b/src/input/backend/updateaxisactionjob.cpp @@ -62,8 +62,9 @@ bool anyOfRequiredKeysPressed(const QVector &keys, QAbstractPhysicalDeviceB } // anonymous -UpdateAxisActionJob::UpdateAxisActionJob(InputHandler *handler, HLogicalDevice handle) +UpdateAxisActionJob::UpdateAxisActionJob(qint64 currentTime, InputHandler *handler, HLogicalDevice handle) : Qt3DCore::QAspectJob() + , m_currentTime(currentTime) , m_handler(handler) , m_handle(handle) { @@ -85,21 +86,70 @@ void UpdateAxisActionJob::updateAction(LogicalDevice *device) Action *action = m_handler->actionManager()->lookupResource(actionId); Q_FOREACH (const Qt3DCore::QNodeId actionInputId, action->inputs()) { - ActionInput *actionInput = m_handler->actionInputManager()->lookupResource(actionInputId); - QAbstractPhysicalDeviceBackendNode *physicalDeviceBackend = Q_NULLPTR; + actionTriggered |= processActionInput(actionInputId); + } + action->setActionTriggered(actionTriggered); + } +} - Q_FOREACH (QInputDeviceIntegration *integration, m_handler->inputDeviceIntegrations()) { - if ((physicalDeviceBackend = integration->physicalDevice(actionInput->sourceDevice())) != Q_NULLPTR) - break; - } +bool UpdateAxisActionJob::processActionInput(const Qt3DCore::QNodeId actionInputId) +{ - if (physicalDeviceBackend != Q_NULLPTR) { - // Update the value - actionTriggered |= anyOfRequiredKeysPressed(actionInput->keys(), physicalDeviceBackend); + if (m_handler->actionInputManager()->lookupResource(actionInputId)) { + ActionInput *actionInput = m_handler->actionInputManager()->lookupResource(actionInputId); + QAbstractPhysicalDeviceBackendNode *physicalDeviceBackend = Q_NULLPTR; + + Q_FOREACH (QInputDeviceIntegration *integration, m_handler->inputDeviceIntegrations()) { + if ((physicalDeviceBackend = integration->physicalDevice(actionInput->sourceDevice())) != Q_NULLPTR) + break; + } + + if (physicalDeviceBackend != Q_NULLPTR) { + // Update the value + return anyOfRequiredKeysPressed(actionInput->keys(), physicalDeviceBackend); + } + } else if (m_handler->inputSequenceManager()->lookupResource(actionInputId)) { + InputSequence *inputSequence = m_handler->inputSequenceManager()->lookupResource(actionInputId); + const qint64 startTime = inputSequence->startTime(); + if (startTime != 0) { + // Check if we are still inside the time limit for the chord + if ((m_currentTime - startTime) > inputSequence->timeout()) { + inputSequence->reset(); + return false; } } - action->setActionTriggered(actionTriggered); + bool actionTriggered = false; + Q_FOREACH (const Qt3DCore::QNodeId actionInputId, inputSequence->inputs()) { + if (processActionInput(actionInputId)){ + actionTriggered |= inputSequence->actionTriggered(actionInputId, m_currentTime); + // Set the start time if it wasn't set before + if (startTime == 0) + inputSequence->setStartTime(m_currentTime); + } + } + return actionTriggered; + } else if (m_handler->inputChordManager()->lookupResource(actionInputId)) { + InputChord *inputChord = m_handler->inputChordManager()->lookupResource(actionInputId); + const qint64 startTime = inputChord->startTime(); + if (startTime != 0) { + // Check if we are still inside the time limit for the chord + if ((m_currentTime - startTime) > inputChord->tolerance()) { + inputChord->reset(); + return false; + } + } + bool actionTriggered = false; + Q_FOREACH (const Qt3DCore::QNodeId actionInputId, inputChord->inputs()) { + if (processActionInput(actionInputId)){ + actionTriggered |= inputChord->actionTriggered(actionInputId); + if (startTime == 0) + inputChord->setStartTime(m_currentTime); + } + } + return actionTriggered; } + //Should Never reach this point + return false; } void UpdateAxisActionJob::updateAxis(LogicalDevice *device) diff --git a/src/input/backend/updateaxisactionjob_p.h b/src/input/backend/updateaxisactionjob_p.h index 7d2aa5ec6..15356284c 100644 --- a/src/input/backend/updateaxisactionjob_p.h +++ b/src/input/backend/updateaxisactionjob_p.h @@ -49,6 +49,7 @@ // #include +#include #include QT_BEGIN_NAMESPACE @@ -62,13 +63,15 @@ class InputHandler; class UpdateAxisActionJob : public Qt3DCore::QAspectJob { public: - explicit UpdateAxisActionJob(InputHandler *handler, HLogicalDevice handle); + explicit UpdateAxisActionJob(qint64 currentTime, InputHandler *handler, HLogicalDevice handle); void run() Q_DECL_FINAL; private: void updateAction(LogicalDevice *device); + bool processActionInput(const Qt3DCore::QNodeId actionInputId); void updateAxis(LogicalDevice *device); + const qint64 m_currentTime; InputHandler *m_handler; HLogicalDevice m_handle; }; diff --git a/src/input/frontend/qinputaspect.cpp b/src/input/frontend/qinputaspect.cpp index b1889be66..aba2fbba3 100644 --- a/src/input/frontend/qinputaspect.cpp +++ b/src/input/frontend/qinputaspect.cpp @@ -175,7 +175,7 @@ QVector QInputAspect::jobsToExecute(qint64 time) QHash logicalDeviceJobs; Q_FOREACH (Input::HLogicalDevice devHandle, d->m_inputHandler->logicalDeviceManager()->activeDevices()) { - QAspectJobPtr updateAxisActionJob(new Input::UpdateAxisActionJob(d->m_inputHandler.data(), devHandle)); + QAspectJobPtr updateAxisActionJob(new Input::UpdateAxisActionJob(time, d->m_inputHandler.data(), devHandle)); logicalDeviceJobs.insert(devHandle, updateAxisActionJob); Q_FOREACH (const QAspectJobPtr job, jobs) -- cgit v1.2.3