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) {
print("-----------------------------------");
var mapping = NewControllers.newMapping("Default");
var mapping = Controller.newMapping("Test");
var standard = Controller.Standard;
print("standard:" + standard);
mapping.from(hydra.LeftButton1).to(standard.A);
mapping.from(hydra.LeftButton2).to(standard.B);
mapping.from(hydra.LeftButton3).to(standard.X);
NewControllers.enableMapping("Default");
mapping.from(hydra.L1).to(standard.A);
mapping.from(hydra.L2).to(standard.B);
mapping.from(hydra.L3).to(function (newValue, oldValue, source) {
print("hydra.L3 newValue:" + newValue + ", oldValue:" + oldValue + ", source:" + source);
});
Controller.enableMapping("Test");
print("-----------------------------------");
} else {
print("couldn't find hydra");
}
Object.keys(Controller.Standard).forEach(function (input) {

View file

@ -11,3 +11,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
//static int EndpointPointerMetaTypeId = qRegisterMetaType<controller::Endpoint::Pointer>("controller::Endpoint::Pointer");

View file

@ -23,7 +23,8 @@ namespace controller {
* Encapsulates a particular input / output,
* i.e. Hydra.Button0, Standard.X, Action.Yaw
*/
class Endpoint {
class Endpoint : public QObject {
Q_OBJECT;
public:
using Pointer = std::shared_ptr<Endpoint>;
using List = std::list<Pointer>;
@ -31,12 +32,12 @@ namespace controller {
using ReadLambda = std::function<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 void apply(float newValue, float oldValue, const Pointer& source) = 0;
const UserInputMapper::Input& getId() { return _id; }
const UserInputMapper::Input& getInput() { return _input; }
protected:
UserInputMapper::Input _id;
UserInputMapper::Input _input;
};
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

View file

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

View file

@ -21,6 +21,7 @@
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <QThread>
#include <QtCore/QObject>
#include <QtCore/QVariant>
@ -138,6 +139,25 @@ namespace controller {
MappingMap _mappingsByName;
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;
};
}