diff --git a/examples/tests/controllerInterfaceTest.js b/examples/tests/controllerInterfaceTest.js index 0dccd1209a..97ad9bbc38 100644 --- a/examples/tests/controllerInterfaceTest.js +++ b/examples/tests/controllerInterfaceTest.js @@ -4,8 +4,10 @@ ControllerTest = function() { var xbox = Controller.Hardware.GamePad; this.mappingEnabled = false; this.mapping = Controller.newMapping(); + this.mapping.from(standard.LX).when([standard.LB, standard.RB]).to(actions.Yaw); this.mapping.from(standard.RX).to(actions.StepYaw); this.mapping.from(standard.RY).invert().to(actions.Pitch); + this.mapping.from(standard.RY).invert().to(actions.Pitch); var testMakeAxis = false; diff --git a/libraries/controllers/src/controllers/UserInputMapper.cpp b/libraries/controllers/src/controllers/UserInputMapper.cpp index 19a4b78207..2579c7dbec 100755 --- a/libraries/controllers/src/controllers/UserInputMapper.cpp +++ b/libraries/controllers/src/controllers/UserInputMapper.cpp @@ -738,6 +738,47 @@ Endpoint::Pointer UserInputMapper::parseEndpoint(const QJsonValue& value) { return result; } + +Conditional::Pointer UserInputMapper::conditionalFor(const QJSValue& condition) { + return Conditional::Pointer(); +} + +Conditional::Pointer UserInputMapper::conditionalFor(const QScriptValue& condition) { + if (condition.isArray()) { + int length = condition.property("length").toInteger(); + Conditional::List children; + for (int i = 0; i < length; i++) { + Conditional::Pointer destination = conditionalFor(condition.property(i)); + if (!destination) { + return Conditional::Pointer(); + } + children.push_back(destination); + } + return std::make_shared(children); + } + + if (condition.isNumber()) { + return conditionalFor(Input(condition.toInt32())); + } + + if (condition.isFunction()) { + return std::make_shared(condition); + } + + qWarning() << "Unsupported conditional type " << condition.toString(); + return Conditional::Pointer(); +} + +Conditional::Pointer UserInputMapper::conditionalFor(const Input& inputId) const { + Locker locker(_lock); + auto iterator = _endpointsByInput.find(inputId); + if (_endpointsByInput.end() == iterator) { + qWarning() << "Unknown input: " << QString::number(inputId.getID(), 16); + return Conditional::Pointer(); + } + return std::make_shared(iterator->second); +} + Conditional::Pointer UserInputMapper::parseConditional(const QJsonValue& value) { if (value.isArray()) { // Support "when" : [ "GamePad.RB", "GamePad.LB" ] @@ -764,7 +805,6 @@ Conditional::Pointer UserInputMapper::parseConditional(const QJsonValue& value) return Conditional::parse(value); } - Filter::Pointer UserInputMapper::parseFilter(const QJsonValue& value) { Filter::Pointer result; if (value.isString()) { @@ -780,7 +820,6 @@ Filter::Pointer UserInputMapper::parseFilter(const QJsonValue& value) { return result; } - Filter::List UserInputMapper::parseFilters(const QJsonValue& value) { if (value.isNull()) { return Filter::List(); diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h index 319037fcb1..0a6ed3acad 100644 --- a/libraries/controllers/src/controllers/UserInputMapper.h +++ b/libraries/controllers/src/controllers/UserInputMapper.h @@ -143,6 +143,7 @@ namespace controller { friend class MappingBuilderProxy; void runMappings(); + static void applyRoutes(const RouteList& route); static bool applyRoute(const RoutePointer& route, bool force = false); void enableMapping(const MappingPointer& mapping); @@ -151,6 +152,9 @@ namespace controller { EndpointPointer endpointFor(const QScriptValue& endpoint); EndpointPointer endpointFor(const Input& endpoint) const; EndpointPointer compositeEndpointFor(EndpointPointer first, EndpointPointer second); + ConditionalPointer conditionalFor(const QJSValue& endpoint); + ConditionalPointer conditionalFor(const QScriptValue& endpoint); + ConditionalPointer conditionalFor(const Input& endpoint) const; MappingPointer parseMapping(const QJsonValue& json); RoutePointer parseRoute(const QJsonValue& value); diff --git a/libraries/controllers/src/controllers/impl/Conditional.h b/libraries/controllers/src/controllers/impl/Conditional.h index 4d67d2871e..a216c8789f 100644 --- a/libraries/controllers/src/controllers/impl/Conditional.h +++ b/libraries/controllers/src/controllers/impl/Conditional.h @@ -28,6 +28,7 @@ namespace controller { using Pointer = std::shared_ptr; using List = std::list; using Factory = hifi::SimpleFactory; + using Lambda = std::function; virtual bool satisfied() = 0; virtual bool parseParameters(const QJsonValue& parameters) { return true; } diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp index c0d0758e4e..d56d699c28 100644 --- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp +++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.cpp @@ -33,7 +33,6 @@ void RouteBuilderProxy::to(const QScriptValue& destination) { } void RouteBuilderProxy::to(const Endpoint::Pointer& destination) { - auto sourceEndpoint = _route->source; _route->destination = destination; _mapping->routes.push_back(_route); deleteLater(); @@ -56,6 +55,17 @@ QObject* RouteBuilderProxy::filterQml(const QJSValue& expression) { return this; } +QObject* RouteBuilderProxy::when(const QScriptValue& expression) { + _route->conditional = _parent.conditionalFor(expression); + return this; +} + +QObject* RouteBuilderProxy::whenQml(const QJSValue& expression) { + _route->conditional = _parent.conditionalFor(expression); + return this; +} + + QObject* RouteBuilderProxy::filter(const QScriptValue& expression) { return this; } diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h index 2303f6184f..4bcfba5acd 100644 --- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h +++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h @@ -35,9 +35,11 @@ class RouteBuilderProxy : public QObject { Q_INVOKABLE void toQml(const QJSValue& destination); Q_INVOKABLE QObject* filterQml(const QJSValue& expression); + Q_INVOKABLE QObject* whenQml(const QJSValue& expression); Q_INVOKABLE void to(const QScriptValue& destination); Q_INVOKABLE QObject* debug(bool enable = true); + Q_INVOKABLE QObject* when(const QScriptValue& expression); Q_INVOKABLE QObject* filter(const QScriptValue& expression); Q_INVOKABLE QObject* clamp(float min, float max); Q_INVOKABLE QObject* pulse(float interval); @@ -49,6 +51,7 @@ class RouteBuilderProxy : public QObject { private: void to(const Endpoint::Pointer& destination); + void conditional(const Conditional::Pointer& conditional); void addFilter(Filter::Lambda lambda); void addFilter(Filter::Pointer filter); UserInputMapper& _parent;