fix thread safety issue on JS based fliters

This commit is contained in:
Brad Hefta-Gaub 2015-10-17 14:08:21 -07:00
parent 7d48fe9187
commit 7956d737ab
5 changed files with 75 additions and 27 deletions

View file

@ -23,17 +23,21 @@ function findAction(name) {
} }
var hydra = Controller.Hardware.Hydra2; var hydra = Controller.Hardware.Hydra;
if (hydra !== undefined) { if (hydra !== undefined) {
print("-----------------------------------"); print("-----------------------------------");
var mapping = NewControllers.newMapping("Default"); var mapping = Controller.newMapping("Test");
var standard = Controller.Standard; var standard = Controller.Standard;
print("standard:" + standard); print("standard:" + standard);
mapping.from(hydra.LeftButton1).to(standard.A); mapping.from(hydra.L1).to(standard.A);
mapping.from(hydra.LeftButton2).to(standard.B); mapping.from(hydra.L2).to(standard.B);
mapping.from(hydra.LeftButton3).to(standard.X); mapping.from(hydra.L3).to(function (newValue, oldValue, source) {
NewControllers.enableMapping("Default"); print("hydra.L3 newValue:" + newValue + ", oldValue:" + oldValue + ", source:" + source);
});
Controller.enableMapping("Test");
print("-----------------------------------"); print("-----------------------------------");
} else {
print("couldn't find hydra");
} }
Object.keys(Controller.Standard).forEach(function (input) { Object.keys(Controller.Standard).forEach(function (input) {

View file

@ -11,3 +11,8 @@
namespace controller { namespace controller {
} }
// FIXME - do we want to include the source Endpoint::Pointer in our calls to JS? If
// so we need to marshall this across the invokeMethod() properly
//static int EndpointPointerMetaTypeId = qRegisterMetaType<controller::Endpoint::Pointer>("controller::Endpoint::Pointer");

View file

@ -23,7 +23,8 @@ namespace controller {
* Encapsulates a particular input / output, * Encapsulates a particular input / output,
* i.e. Hydra.Button0, Standard.X, Action.Yaw * i.e. Hydra.Button0, Standard.X, Action.Yaw
*/ */
class Endpoint { class Endpoint : public QObject {
Q_OBJECT;
public: public:
using Pointer = std::shared_ptr<Endpoint>; using Pointer = std::shared_ptr<Endpoint>;
using List = std::list<Pointer>; using List = std::list<Pointer>;
@ -31,12 +32,12 @@ namespace controller {
using ReadLambda = std::function<float()>; using ReadLambda = std::function<float()>;
using WriteLambda = std::function<void(float)>; using WriteLambda = std::function<void(float)>;
Endpoint(const UserInputMapper::Input& id) : _id(id) {} Endpoint(const UserInputMapper::Input& input) : _input(input) {}
virtual float value() = 0; virtual float value() = 0;
virtual void apply(float newValue, float oldValue, const Pointer& source) = 0; virtual void apply(float newValue, float oldValue, const Pointer& source) = 0;
const UserInputMapper::Input& getId() { return _id; } const UserInputMapper::Input& getInput() { return _input; }
protected: protected:
UserInputMapper::Input _id; UserInputMapper::Input _input;
}; };
class LambdaEndpoint : public Endpoint { class LambdaEndpoint : public Endpoint {
@ -53,4 +54,8 @@ namespace controller {
}; };
} }
// FIXME - do we want to include the source Endpoint::Pointer in our calls to JS? If
// so we need to marshall this across the invokeMethod() properly
//Q_DECLARE_METATYPE(controller::Endpoint::Pointer);
#endif #endif

View file

@ -15,6 +15,7 @@
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
#include <QEventLoop> #include <QEventLoop>
#include <QThread>
#include <GLMHelpers.h> #include <GLMHelpers.h>
#include <DependencyManager.h> #include <DependencyManager.h>
@ -60,24 +61,37 @@ namespace controller {
QJSValue _callable; QJSValue _callable;
}; };
class ScriptEndpoint : public Endpoint { float ScriptEndpoint::value() {
public: if (QThread::currentThread() == thread()) {
ScriptEndpoint(const QScriptValue& callable) updateValue();
: Endpoint(UserInputMapper::Input::INVALID_INPUT), _callable(callable) { }
return _lastValue;
}
void ScriptEndpoint::updateValue() {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "updateValue", Qt::QueuedConnection);
return;
} }
virtual float value() { _lastValue = (float)_callable.call().toNumber();
float result = (float)_callable.call().toNumber(); }
return result;
}
virtual void apply(float newValue, float oldValue, const Pointer& source) { void ScriptEndpoint::apply(float newValue, float oldValue, const Pointer& source) {
_callable.call(QScriptValue(), QScriptValueList({ QScriptValue(newValue) })); internalApply(newValue, oldValue, source->getInput().getID());
} }
private: void ScriptEndpoint::internalApply(float newValue, float oldValue, int sourceID) {
QScriptValue _callable; if (QThread::currentThread() != thread()) {
}; QMetaObject::invokeMethod(this, "internalApply", Qt::QueuedConnection,
Q_ARG(float, newValue),
Q_ARG(float, oldValue),
Q_ARG(int, sourceID));
return;
}
_callable.call(QScriptValue(),
QScriptValueList({ QScriptValue(newValue), QScriptValue(oldValue), QScriptValue(sourceID) }));
}
class CompositeEndpoint : public Endpoint, Endpoint::Pair { class CompositeEndpoint : public Endpoint, Endpoint::Pair {
public: public:
@ -108,9 +122,9 @@ namespace controller {
virtual void apply(float newValue, float oldValue, const Pointer& source) override { virtual void apply(float newValue, float oldValue, const Pointer& source) override {
_currentValue += newValue; _currentValue += newValue;
if (!(_id == UserInputMapper::Input::INVALID_INPUT)) { if (!(_input == UserInputMapper::Input::INVALID_INPUT)) {
auto userInputMapper = DependencyManager::get<UserInputMapper>(); auto userInputMapper = DependencyManager::get<UserInputMapper>();
userInputMapper->deltaActionState(UserInputMapper::Action(_id.getChannel()), newValue); userInputMapper->deltaActionState(UserInputMapper::Action(_input.getChannel()), newValue);
} }
} }
@ -327,7 +341,7 @@ namespace controller {
} }
// Standard controller destinations can only be can only be used once. // Standard controller destinations can only be can only be used once.
if (userInputMapper->getStandardDeviceID() == destination->getId().getDevice()) { if (userInputMapper->getStandardDeviceID() == destination->getInput().getDevice()) {
writtenEndpoints.insert(destination); writtenEndpoints.insert(destination);
} }

View file

@ -21,6 +21,7 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp> #include <glm/gtc/quaternion.hpp>
#include <QThread>
#include <QtCore/QObject> #include <QtCore/QObject>
#include <QtCore/QVariant> #include <QtCore/QVariant>
@ -138,6 +139,25 @@ namespace controller {
MappingMap _mappingsByName; MappingMap _mappingsByName;
MappingStack _activeMappings; MappingStack _activeMappings;
}; };
class ScriptEndpoint : public Endpoint {
Q_OBJECT;
public:
ScriptEndpoint(const QScriptValue& callable)
: Endpoint(UserInputMapper::Input::INVALID_INPUT), _callable(callable) {
}
virtual float value();
virtual void apply(float newValue, float oldValue, const Pointer& source);
protected:
Q_INVOKABLE void updateValue();
Q_INVOKABLE virtual void internalApply(float newValue, float oldValue, int sourceID);
private:
QScriptValue _callable;
float _lastValue = 0.0f;
};
} }